diff --git a/dtool/src/dtoolbase/typeHandle.cxx b/dtool/src/dtoolbase/typeHandle.cxx index 4bbdbcbbb1..ed85da8d03 100644 --- a/dtool/src/dtoolbase/typeHandle.cxx +++ b/dtool/src/dtoolbase/typeHandle.cxx @@ -45,7 +45,9 @@ get_memory_usage(MemoryClass memory_class) const { void TypeHandle:: inc_memory_usage(MemoryClass memory_class, size_t size) { #ifdef DO_MEMORY_USAGE +#ifdef _DEBUG assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); +#endif if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); assert(rnode != (TypeRegistryNode *)NULL); @@ -67,7 +69,9 @@ inc_memory_usage(MemoryClass memory_class, size_t size) { void TypeHandle:: dec_memory_usage(MemoryClass memory_class, size_t size) { #ifdef DO_MEMORY_USAGE +#ifdef _DEBUG assert((int)memory_class >= 0 && (int)memory_class < (int)MC_limit); +#endif if ((*this) != TypeHandle::none()) { TypeRegistryNode *rnode = TypeRegistry::ptr()->look_up(*this, NULL); assert(rnode != (TypeRegistryNode *)NULL); diff --git a/dtool/src/prc/configVariableBool.I b/dtool/src/prc/configVariableBool.I index 4e6b0ab35f..7eba0820d0 100644 --- a/dtool/src/prc/configVariableBool.I +++ b/dtool/src/prc/configVariableBool.I @@ -67,7 +67,7 @@ operator = (bool value) { /** * Returns the variable's value. */ -INLINE ConfigVariableBool:: +ALWAYS_INLINE ConfigVariableBool:: operator bool () const { return get_value(); } @@ -100,12 +100,11 @@ set_value(bool value) { /** * Returns the variable's value. */ -INLINE bool ConfigVariableBool:: +ALWAYS_INLINE bool ConfigVariableBool:: get_value() const { TAU_PROFILE("bool ConfigVariableBool::get_value() const", " ", TAU_USER); if (!is_cache_valid(_local_modified)) { - mark_cache_valid(((ConfigVariableBool *)this)->_local_modified); - ((ConfigVariableBool *)this)->_cache = get_bool_word(0); + reload_value(); } return _cache; } diff --git a/dtool/src/prc/configVariableBool.cxx b/dtool/src/prc/configVariableBool.cxx index d063b06fd5..7fb604642d 100644 --- a/dtool/src/prc/configVariableBool.cxx +++ b/dtool/src/prc/configVariableBool.cxx @@ -12,3 +12,12 @@ */ #include "configVariableBool.h" + +/** + * Refreshes the cached value. + */ +void ConfigVariableBool:: +reload_value() const { + mark_cache_valid(_local_modified); + _cache = get_bool_word(0); +} diff --git a/dtool/src/prc/configVariableBool.h b/dtool/src/prc/configVariableBool.h index a0d8b0b1dd..9f486c4266 100644 --- a/dtool/src/prc/configVariableBool.h +++ b/dtool/src/prc/configVariableBool.h @@ -29,13 +29,13 @@ PUBLISHED: const string &description = string(), int flags = 0); INLINE void operator = (bool value); - INLINE operator bool () const; + ALWAYS_INLINE operator bool () const; INLINE size_t size() const; INLINE bool operator [] (size_t n) const; INLINE void set_value(bool value); - INLINE bool get_value() const; + ALWAYS_INLINE bool get_value() const; INLINE bool get_default_value() const; MAKE_PROPERTY(value, get_value, set_value); MAKE_PROPERTY(default_value, get_default_value); @@ -44,8 +44,10 @@ PUBLISHED: INLINE void set_word(size_t n, bool value); private: - AtomicAdjust::Integer _local_modified; - bool _cache; + void reload_value() const; + + mutable AtomicAdjust::Integer _local_modified; + mutable bool _cache; }; #include "configVariableBool.I" diff --git a/dtool/src/prc/notifyCategory.I b/dtool/src/prc/notifyCategory.I index a485447dcc..07d3634d92 100644 --- a/dtool/src/prc/notifyCategory.I +++ b/dtool/src/prc/notifyCategory.I @@ -70,7 +70,12 @@ is_on(NotifySeverity severity) const { */ INLINE bool NotifyCategory:: is_spam() const { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(is_on(NS_spam), 0); +#else return is_on(NS_spam); +#endif } /** @@ -78,7 +83,12 @@ is_spam() const { */ INLINE bool NotifyCategory:: is_debug() const { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(is_on(NS_debug), 0); +#else return is_on(NS_debug); +#endif } #else /** diff --git a/dtool/src/prc/notifyCategoryProxy.I b/dtool/src/prc/notifyCategoryProxy.I index 08c253f081..ae829eeedb 100644 --- a/dtool/src/prc/notifyCategoryProxy.I +++ b/dtool/src/prc/notifyCategoryProxy.I @@ -69,7 +69,12 @@ is_on(NotifySeverity severity) { template INLINE bool NotifyCategoryProxy:: is_spam() { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(get_unsafe_ptr()->is_spam(), 0); +#else return get_unsafe_ptr()->is_spam(); +#endif } #else template @@ -86,7 +91,12 @@ is_spam() { template INLINE bool NotifyCategoryProxy:: is_debug() { + // Instruct the compiler to optimize for the usual case. +#ifdef __GNUC__ + return __builtin_expect(get_unsafe_ptr()->is_debug(), 0); +#else return get_unsafe_ptr()->is_debug(); +#endif } #else template diff --git a/dtool/src/prc/pnotify.h b/dtool/src/prc/pnotify.h index a8254cc910..414b97d2a4 100644 --- a/dtool/src/prc/pnotify.h +++ b/dtool/src/prc/pnotify.h @@ -122,6 +122,13 @@ private: // constant expressions and compilation will fail if the assertion is not // true. +#ifdef __GNUC__ +// Tell the optimizer to optimize for the case where the condition is true. +#define _nassert_check(condition) (__builtin_expect(!(condition), 0)) +#else +#define _nassert_check(condition) (!(condition)) +#endif + #ifdef NDEBUG #define nassertr(condition, return_value) @@ -131,14 +138,14 @@ private: #define nassertr_always(condition, return_value) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ return return_value; \ } \ } #define nassertv_always(condition) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ return; \ } \ } @@ -151,7 +158,7 @@ private: #define nassertr(condition, return_value) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \ return return_value; \ } \ @@ -160,7 +167,7 @@ private: #define nassertv(condition) \ { \ - if (!(condition)) { \ + if (_nassert_check(condition)) { \ if (Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) { \ return; \ } \ @@ -168,7 +175,7 @@ private: } #define nassertd(condition) \ - if (!(condition) && \ + if (_nassert_check(condition) && \ Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__)) #define nassertr_always(condition, return_value) nassertr(condition, return_value) @@ -177,7 +184,7 @@ private: #define nassert_raise(message) Notify::ptr()->assert_failure(message, __LINE__, __FILE__) #define enter_debugger_if(condition) \ - if (condition) { \ + if (_nassert_check(condition)) { \ Notify::ptr()->assert_failure(#condition, __LINE__, __FILE__); \ __asm { int 3 } \ } diff --git a/panda/src/char/characterJointEffect.cxx b/panda/src/char/characterJointEffect.cxx index ec0dec9de3..33441e35c2 100644 --- a/panda/src/char/characterJointEffect.cxx +++ b/panda/src/char/characterJointEffect.cxx @@ -122,8 +122,10 @@ void CharacterJointEffect:: cull_callback(CullTraverser *trav, CullTraverserData &data, CPT(TransformState) &node_transform, CPT(RenderState) &) const { - CPT(TransformState) dummy_transform = TransformState::make_identity(); - adjust_transform(dummy_transform, node_transform, data.node()); + if (_character.is_valid_pointer()) { + _character->update(); + } + node_transform = data.node()->get_transform(); } /** @@ -147,7 +149,7 @@ has_adjust_transform() const { void CharacterJointEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const { + const PandaNode *node) const { if (_character.is_valid_pointer()) { _character->update(); } diff --git a/panda/src/char/characterJointEffect.h b/panda/src/char/characterJointEffect.h index 031b75237c..0df4cea6fd 100644 --- a/panda/src/char/characterJointEffect.h +++ b/panda/src/char/characterJointEffect.h @@ -53,7 +53,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/collide/collisionLevelState.I b/panda/src/collide/collisionLevelState.I index 5ac7cb9063..5dc74aa691 100644 --- a/panda/src/collide/collisionLevelState.I +++ b/panda/src/collide/collisionLevelState.I @@ -111,10 +111,12 @@ any_in_bounds() { } #endif // NDEBUG - CPT(BoundingVolume) node_bv = node()->get_bounds(); + PandaNode *pnode = node(); + + CPT(BoundingVolume) node_bv = pnode->get_bounds(); if (node_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - const GeometricBoundingVolume *node_gbv; - DCAST_INTO_R(node_gbv, node_bv, false); + const GeometricBoundingVolume *node_gbv = (const GeometricBoundingVolume *)node_bv.p(); + CollideMask this_mask = pnode->get_net_collide_mask(); int num_colliders = get_num_colliders(); for (int c = 0; c < num_colliders; c++) { @@ -125,10 +127,10 @@ any_in_bounds() { // Don't even bother testing the bounding volume if there are no // collide bits in common between our collider and this node. CollideMask from_mask = cnode->get_from_collide_mask() & _include_mask; - if (!(from_mask & node()->get_net_collide_mask()).is_zero()) { + if (!(from_mask & this_mask).is_zero()) { // Also don't test a node with itself, or with any of its // descendants. - if (node() == cnode) { + if (pnode == cnode) { #ifndef NDEBUG if (collide_cat.is_spam()) { indent(collide_cat.spam(false), indent_level) diff --git a/panda/src/collide/collisionLevelStateBase.h b/panda/src/collide/collisionLevelStateBase.h index bde70562c2..4c2abccb58 100644 --- a/panda/src/collide/collisionLevelStateBase.h +++ b/panda/src/collide/collisionLevelStateBase.h @@ -51,7 +51,7 @@ public: INLINE CollisionLevelStateBase(const NodePath &node_path); INLINE CollisionLevelStateBase(const CollisionLevelStateBase &parent, - PandaNode *child); + PandaNode *child); INLINE CollisionLevelStateBase(const CollisionLevelStateBase ©); INLINE void operator = (const CollisionLevelStateBase ©); diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index da5aa38cc6..9de94617b3 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -196,7 +196,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (respect_prev_transform) { // Determine the previous frame's position, relative to the current // position. - NodePath node_path = data._node_path.get_node_path(); + NodePath node_path = data.get_node_path(); CPT(TransformState) transform = node_path.get_net_transform()->invert_compose(node_path.get_net_prev_transform()); if (!transform->is_identity()) { diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index 6c95e6d435..db731f7bcf 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -93,6 +93,8 @@ private: typedef pvector< COWPT(CollisionSolid) > Solids; Solids _solids; + friend class CollisionTraverser; + public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); diff --git a/panda/src/collide/collisionTraverser.cxx b/panda/src/collide/collisionTraverser.cxx index 5934a5e541..74973d6764 100644 --- a/panda/src/collide/collisionTraverser.cxx +++ b/panda/src/collide/collisionTraverser.cxx @@ -57,7 +57,7 @@ public: inline bool operator () (int a, int b) const { const CollisionTraverser::OrderedColliderDef &ocd_a = _trav._ordered_colliders[a]; const CollisionTraverser::OrderedColliderDef &ocd_b = _trav._ordered_colliders[b]; - return DCAST(CollisionNode, ocd_a._node_path.node())->get_collider_sort() < DCAST(CollisionNode, ocd_b._node_path.node())->get_collider_sort(); + return ((const CollisionNode *)ocd_a._node_path.node())->get_collider_sort() < ((const CollisionNode *)ocd_b._node_path.node())->get_collider_sort(); } const CollisionTraverser &_trav; @@ -1117,31 +1117,45 @@ compare_collider_to_node(CollisionEntry &entry, } if (within_node_bounds) { + Thread *current_thread = Thread::get_current_thread(); + CollisionNode *cnode; DCAST_INTO_V(cnode, entry._into_node); + int num_solids = cnode->get_num_solids(); - collide_cat.spam() - << "Colliding against CollisionNode " << entry._into_node - << " which has " << num_solids << " collision solids.\n"; - for (int s = 0; s < num_solids; ++s) { - entry._into = cnode->get_solid(s); + if (collide_cat.is_spam()) { + collide_cat.spam() + << "Colliding against CollisionNode " << entry._into_node + << " which has " << num_solids << " collision solids.\n"; + } - // We should allow a collision test for solid into itself, because the - // solid might be simply instanced into multiple different - // CollisionNodes. We are already filtering out tests for a - // CollisionNode into itself. - CPT(BoundingVolume) solid_bv = entry._into->get_bounds(); - const GeometricBoundingVolume *solid_gbv = NULL; - if (num_solids > 1 && - solid_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - // Only bother to test against each solid's bounding volume if we have - // more than one solid in the node, as a slight optimization. (If the - // node contains just one solid, then the node's bounding volume, - // which we just tested, is the same as the solid's bounding volume.) - DCAST_INTO_V(solid_gbv, solid_bv); + // Only bother to test against each solid's bounding volume if we have + // more than one solid in the node, as a slight optimization. (If the + // node contains just one solid, then the node's bounding volume, which + // we just tested, is the same as the solid's bounding volume.) + if (num_solids == 1) { + entry._into = cnode->_solids[0].get_read_pointer(current_thread); + Colliders::const_iterator ci; + ci = _colliders.find(entry.get_from_node_path()); + nassertv(ci != _colliders.end()); + entry.test_intersection((*ci).second, this); + } else { + CollisionNode::Solids::const_iterator si; + for (si = cnode->_solids.begin(); si != cnode->_solids.end(); ++si) { + entry._into = (*si).get_read_pointer(current_thread); + + // We should allow a collision test for solid into itself, because the + // solid might be simply instanced into multiple different + // CollisionNodes. We are already filtering out tests for a + // CollisionNode into itself. + CPT(BoundingVolume) solid_bv = entry._into->get_bounds(); + const GeometricBoundingVolume *solid_gbv = nullptr; + if (solid_bv->is_of_type(GeometricBoundingVolume::get_class_type())) { + solid_gbv = (const GeometricBoundingVolume *)solid_bv.p(); + } + + compare_collider_to_solid(entry, from_node_gbv, solid_gbv); } - - compare_collider_to_solid(entry, from_node_gbv, solid_gbv); } } } diff --git a/panda/src/collide/collisionVisualizer.cxx b/panda/src/collide/collisionVisualizer.cxx index 19699b9d6f..d58137ce68 100644 --- a/panda/src/collide/collisionVisualizer.cxx +++ b/panda/src/collide/collisionVisualizer.cxx @@ -111,10 +111,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // its objects according to their appropriate net transform. xform_data._net_transform = TransformState::make_identity(); xform_data._view_frustum = trav->get_view_frustum(); - xform_data.apply_transform_and_state(trav, net_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + xform_data.apply_transform(net_transform); // Draw all the collision solids. Solids::const_iterator si; diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index 5b46251ba8..e8ef03ce3b 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -903,16 +903,10 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_identity: { return &LMatrix4::ident_mat(); } - case Shader::SMO_window_size: { - t = LMatrix4::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0); - return &t; - } + case Shader::SMO_window_size: case Shader::SMO_pixel_size: { - t = LMatrix4::translate_mat(_current_display_region->get_pixel_width(), - _current_display_region->get_pixel_height(), - 0.0); + LVecBase2i pixel_size = _current_display_region->get_pixel_size(); + t = LMatrix4::translate_mat(pixel_size[0], pixel_size[1], 0); return &t; } case Shader::SMO_frame_time: { @@ -1049,7 +1043,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 d = -(t.xform_vec(lt->get_direction())); d.normalize(); LVecBase3 h = d + LVecBase3(0,-1,0); @@ -1066,11 +1060,12 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &c = lt->get_color(); LColor const &s = lt->get_specular_color(); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = (t.xform_point(lt->get_point())); LVecBase3 a = lt->get_attenuation(); - PN_stdfloat lnear = lt->get_lens(0)->get_near(); - PN_stdfloat lfar = lt->get_lens(0)->get_far(); + Lens *lens = lt->get_lens(0); + PN_stdfloat lnear = lens->get_near(); + PN_stdfloat lfar = lens->get_far(); t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],lnear,a[0],a[1],a[2],lfar); return &t; } @@ -1086,7 +1081,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, LColor const &s = lt->get_specular_color(); PN_stdfloat cutoff = ccos(deg_2_rad(lens->get_hfov() * 0.5f)); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); LVecBase3 p = t.xform_point(lens->get_nodal_point()); LVecBase3 d = -(t.xform_vec(lens->get_view_vector())); t = LMatrix4(c[0],c[1],c[2],c[3],s[0],s[1],s[2],s[3],p[0],p[1],p[2],0,d[0],d[1],d[2],cutoff); @@ -1109,7 +1104,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, &LMatrix4::zeros_mat()); - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { cur_ambient_light += light_obj->get_color(); } } @@ -1155,27 +1150,31 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_plane_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); - nassertr(np.node()->is_of_type(PlaneNode::get_class_type()), &LMatrix4::zeros_mat()); - LPlane p = DCAST(PlaneNode, np.node())->get_plane(); + const PlaneNode *plane_node; + DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + LPlane p = plane_node->get_plane(); t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); return &t; } case Shader::SMO_clipplane_x: { - const ClipPlaneAttrib *cpa = DCAST(ClipPlaneAttrib, _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot())); + const ClipPlaneAttrib *cpa; + _target_rs->get_attrib_def(cpa); int planenr = atoi(name->get_name().c_str()); if (planenr >= cpa->get_num_on_planes()) { return &LMatrix4::zeros_mat(); } const NodePath &np = cpa->get_on_plane(planenr); nassertr(!np.is_empty(), &LMatrix4::zeros_mat()); - nassertr(np.node()->is_of_type(PlaneNode::get_class_type()), &LMatrix4::zeros_mat()); - LPlane p (DCAST(PlaneNode, np.node())->get_plane()); + const PlaneNode *plane_node; + DCAST_INTO_R(plane_node, np.node(), &LMatrix4::zeros_mat()); + LPlane p (plane_node->get_plane()); p.xform(np.get_net_transform()->get_mat()); // World-space t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,p[0],p[1],p[2],p[3]); return &t; } case Shader::SMO_apiview_clipplane_i: { - const ClipPlaneAttrib *cpa = DCAST(ClipPlaneAttrib, _target_rs->get_attrib_def(ClipPlaneAttrib::get_class_slot())); + const ClipPlaneAttrib *cpa; + _target_rs->get_attrib_def(cpa); if (index >= cpa->get_num_on_planes()) { return &LMatrix4::zeros_mat(); } @@ -1186,7 +1185,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, DCAST_INTO_R(plane_node, plane.node(), &LMatrix4::zeros_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( plane.get_transform(_scene_setup->get_scene_root().get_parent())); LPlane xformed_plane = plane_node->get_plane() * transform->get_mat(); @@ -1206,24 +1205,24 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, return &t; } case Shader::SMO_world_to_view: { - return &(get_scene()->get_world_transform()->get_mat()); + return &(_scene_setup->get_world_transform()->get_mat()); break; } case Shader::SMO_view_to_world: { - return &(get_scene()->get_camera_transform()->get_mat()); + return &(_scene_setup->get_camera_transform()->get_mat()); } case Shader::SMO_model_to_view: { - return &(get_external_transform()->get_mat()); + return &(_inv_cs_transform->compose(_internal_transform)->get_mat()); } case Shader::SMO_model_to_apiview: { - return &(get_internal_transform()->get_mat()); + return &(_internal_transform->get_mat()); } case Shader::SMO_view_to_model: { - t = get_external_transform()->get_inverse()->get_mat(); + t = _internal_transform->invert_compose(_cs_transform)->get_mat(); return &t; } case Shader::SMO_apiview_to_model: { - t = get_internal_transform()->get_inverse()->get_mat(); + t = _internal_transform->get_inverse()->get_mat(); return &t; } case Shader::SMO_apiview_to_view: { @@ -1268,13 +1267,13 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); t = np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_view_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = get_scene()->get_camera_transform()->get_mat() * + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat(); return &t; } @@ -1283,13 +1282,13 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, nassertr(!np.is_empty(), &LMatrix4::ident_mat()); t = LMatrix4::convert_mat(_internal_coordinate_system, _coordinate_system) * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_apiview_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - t = (get_scene()->get_camera_transform()->get_mat() * + t = (_scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, _internal_coordinate_system)); return &t; @@ -1297,20 +1296,22 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_clip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); t = lens->get_projection_mat_inv(_current_stereo_channel) * LMatrix4::convert_mat(lens->get_coordinate_system(), _coordinate_system) * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_clip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); - t = get_scene()->get_camera_transform()->get_mat() * + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()) * lens->get_projection_mat(_current_stereo_channel); @@ -1319,20 +1320,22 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, case Shader::SMO_apiclip_x_to_view: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); t = calc_projection_mat(lens)->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_inverse()->get_mat() * np.get_net_transform()->get_mat() * - get_scene()->get_world_transform()->get_mat(); + _scene_setup->get_world_transform()->get_mat(); return &t; } case Shader::SMO_view_to_apiclip_x: { const NodePath &np = _target_shader->get_shader_input_nodepath(name); nassertr(!np.is_empty(), &LMatrix4::ident_mat()); - nassertr(np.node()->is_of_type(LensNode::get_class_type()), &LMatrix4::ident_mat()); - Lens *lens = DCAST(LensNode, np.node())->get_lens(); - t = get_scene()->get_camera_transform()->get_mat() * + const LensNode *node; + DCAST_INTO_R(node, np.node(), &LMatrix4::ident_mat()); + const Lens *lens = node->get_lens(); + t = _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * get_cs_transform_for(lens->get_coordinate_system())->get_mat() * calc_projection_mat(lens)->get_mat(); @@ -1383,7 +1386,7 @@ fetch_specified_part(Shader::ShaderMatInput part, InternalName *name, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, &LMatrix4::ident_mat()); - if (light_obj->get_type() != AmbientLight::get_class_type()) { + if (!light_obj->is_ambient_light()) { if (i++ == index) { return fetch_specified_member(light, name, t); } @@ -1430,7 +1433,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) static const CPT_InternalName IN_constantAttenuation("constantAttenuation"); static const CPT_InternalName IN_linearAttenuation("linearAttenuation"); static const CPT_InternalName IN_quadraticAttenuation("quadraticAttenuation"); - static const CPT_InternalName IN_shadowMatrix("shadowMatrix"); + static const CPT_InternalName IN_shadowViewMatrix("shadowViewMatrix"); PandaNode *node = NULL; if (!np.is_empty()) { @@ -1454,7 +1457,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } Light *light = node->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ident_mat()); - if (node->is_of_type(AmbientLight::get_class_type())) { + if (node->is_ambient_light()) { LColor c = light->get_color(); c.componentwise_mult(_light_color_scale); t.set_row(3, c); @@ -1470,7 +1473,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) } Light *light = node->as_light(); nassertr(light != (Light *)NULL, &LMatrix4::ones_mat()); - if (node->is_of_type(AmbientLight::get_class_type())) { + if (node->is_ambient_light()) { // Ambient light has no diffuse color. t.set_row(3, LColor(0.0f, 0.0f, 0.0f, 1.0f)); } else { @@ -1493,7 +1496,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (np.is_empty()) { t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no position. t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); return &t; @@ -1503,7 +1506,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); - dir *= get_scene()->get_cs_world_transform()->get_mat(); + dir *= _scene_setup->get_cs_world_transform()->get_mat(); t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,dir[0],dir[1],dir[2],0); return &t; } else { @@ -1513,7 +1516,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1526,7 +1529,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (np.is_empty()) { t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no half-vector. t = LMatrix4(0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0); return &t; @@ -1536,7 +1539,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) CPT(TransformState) transform = np.get_transform(_scene_setup->get_scene_root().get_parent()); LVector3 dir = -(light->get_direction() * transform->get_mat()); - dir *= get_scene()->get_cs_world_transform()->get_mat(); + dir *= _scene_setup->get_cs_world_transform()->get_mat(); dir.normalize(); dir += LVector3(0, 0, 1); dir.normalize(); @@ -1549,7 +1552,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1565,7 +1568,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) if (node == (PandaNode *)NULL) { t.set_row(3, LVector3(0.0f, 0.0f, -1.0f)); return &t; - } else if (node->is_of_type(AmbientLight::get_class_type())) { + } else if (node->is_ambient_light()) { // Ambient light has no spot direction. t.set_row(3, LVector3(0.0f, 0.0f, 0.0f)); return &t; @@ -1576,7 +1579,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) nassertr(lens != (Lens *)NULL, &LMatrix4::ident_mat()); CPT(TransformState) transform = - get_scene()->get_cs_world_transform()->compose( + _scene_setup->get_cs_world_transform()->compose( np.get_transform(_scene_setup->get_scene_root().get_parent())); const LMatrix4 &light_mat = transform->get_mat(); @@ -1670,7 +1673,7 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) t.set_row(3, LVecBase4(light->get_attenuation()[2])); return &t; - } else if (attrib == IN_shadowMatrix) { + } else if (attrib == IN_shadowViewMatrix) { static const LMatrix4 biasmat(0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 0.0f, 0.5f, 0.0f, @@ -1684,8 +1687,8 @@ fetch_specified_member(const NodePath &np, CPT_InternalName attrib, LMatrix4 &t) DCAST_INTO_R(lnode, node, &LMatrix4::ident_mat()); Lens *lens = lnode->get_lens(); - t = get_external_transform()->get_mat() * - get_scene()->get_camera_transform()->get_mat() * + t = _inv_cs_transform->get_mat() * + _scene_setup->get_camera_transform()->get_mat() * np.get_net_transform()->get_inverse()->get_mat() * LMatrix4::convert_mat(_coordinate_system, lens->get_coordinate_system()); @@ -1785,7 +1788,7 @@ fetch_specified_texture(Shader::ShaderTexSpec &spec, SamplerState &sampler, Light *light_obj = light.node()->as_light(); nassertr(light_obj != (Light *)NULL, NULL); - if (light_obj->get_type() != AmbientLight::get_class_type()) { + if (!light_obj->is_ambient_light()) { if (i++ == spec._stage) { PT(Texture) tex = get_shadow_map(light); if (tex != (Texture *)NULL) { @@ -2663,7 +2666,7 @@ do_issue_light() { _lighting_enabled = true; } - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { // Ambient lights don't require specific light ids; simply add in the // ambient contribution to the current total cur_ambient_light += light_obj->get_color(); @@ -3143,11 +3146,12 @@ async_reload_texture(TextureContext *tc) { */ PT(Texture) GraphicsStateGuardian:: get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) { - nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || - light_np.node()->is_of_type(PointLight::get_class_type()) || - light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); + PandaNode *node = light_np.node(); + nassertr(node->is_of_type(DirectionalLight::get_class_type()) || + node->is_of_type(PointLight::get_class_type()) || + node->is_of_type(Spotlight::get_class_type()), NULL); - PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); + LightLensNode *light = (LightLensNode *)node; if (light == NULL || !light->_shadow_caster) { // TODO: return dummy shadow map (all white). return NULL; @@ -3177,11 +3181,12 @@ get_shadow_map(const NodePath &light_np, GraphicsOutputBase *host) { PT(Texture) GraphicsStateGuardian:: make_shadow_buffer(const NodePath &light_np, GraphicsOutputBase *host) { // Make sure everything is valid. - nassertr(light_np.node()->is_of_type(DirectionalLight::get_class_type()) || - light_np.node()->is_of_type(PointLight::get_class_type()) || - light_np.node()->is_of_type(Spotlight::get_class_type()), NULL); + PandaNode *node = light_np.node(); + nassertr(node->is_of_type(DirectionalLight::get_class_type()) || + node->is_of_type(PointLight::get_class_type()) || + node->is_of_type(Spotlight::get_class_type()), NULL); - PT(LightLensNode) light = DCAST(LightLensNode, light_np.node()); + LightLensNode *light = (LightLensNode *)node; if (light == NULL || !light->_shadow_caster) { return NULL; } diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index a5dbce4a11..a300771f1f 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -286,7 +286,7 @@ PUBLISHED: MAKE_PROPERTY(driver_shader_version_minor, get_driver_shader_version_minor); bool set_scene(SceneSetup *scene_setup); - virtual SceneSetup *get_scene() const; + virtual SceneSetup *get_scene() const FINAL; MAKE_PROPERTY(scene, get_scene, set_scene); public: diff --git a/panda/src/distort/projectionScreen.cxx b/panda/src/distort/projectionScreen.cxx index fd319031e6..1991bfc120 100644 --- a/panda/src/distort/projectionScreen.cxx +++ b/panda/src/distort/projectionScreen.cxx @@ -103,7 +103,7 @@ make_copy() const { bool ProjectionScreen:: cull_callback(CullTraverser *, CullTraverserData &data) { if (_auto_recompute) { - recompute_if_stale(data._node_path.get_node_path()); + recompute_if_stale(data.get_node_path()); } return true; } diff --git a/panda/src/express/memoryUsage.I b/panda/src/express/memoryUsage.I index 619da5a736..f9de4f8c93 100644 --- a/panda/src/express/memoryUsage.I +++ b/panda/src/express/memoryUsage.I @@ -295,10 +295,13 @@ show_trend_ages() { */ INLINE MemoryUsage *MemoryUsage:: get_global_ptr() { - if (_global_ptr == (MemoryUsage *)NULL) { - init_memory_hook(); - _global_ptr = new MemoryUsage(*memory_hook); - memory_hook = _global_ptr; +#ifdef __GNUC__ + // Tell the compiler that this is an unlikely branch. + if (__builtin_expect(_global_ptr == nullptr, 0)) { +#else + if (_global_ptr == nullptr) { +#endif + init_memory_usage(); } return _global_ptr; diff --git a/panda/src/express/memoryUsage.cxx b/panda/src/express/memoryUsage.cxx index 1aea4fe825..a834da9dad 100644 --- a/panda/src/express/memoryUsage.cxx +++ b/panda/src/express/memoryUsage.cxx @@ -489,6 +489,16 @@ MemoryUsage(const MemoryHook ©) : MemoryHook(copy) { _total_size = 0; } +/** + * Initializes the global MemoryUsage pointer. + */ +void MemoryUsage:: +init_memory_usage() { + init_memory_hook(); + _global_ptr = new MemoryUsage(*memory_hook); + memory_hook = _global_ptr; +} + /** * This callback method is called whenever the total allocated heap size * exceeds _max_heap_size. It's mainly intended for reporting memory leaks, diff --git a/panda/src/express/memoryUsage.h b/panda/src/express/memoryUsage.h index b52f71f7ea..eb4cc6856e 100644 --- a/panda/src/express/memoryUsage.h +++ b/panda/src/express/memoryUsage.h @@ -95,6 +95,8 @@ private: MemoryUsage(const MemoryHook ©); INLINE static MemoryUsage *get_global_ptr(); + static void init_memory_usage(); + void ns_record_pointer(ReferenceCount *ptr); void ns_update_type(ReferenceCount *ptr, TypeHandle type); void ns_update_type(ReferenceCount *ptr, TypedObject *typed_ptr); diff --git a/panda/src/express/pointerToBase.I b/panda/src/express/pointerToBase.I index 296dc5d3bb..d57064967b 100644 --- a/panda/src/express/pointerToBase.I +++ b/panda/src/express/pointerToBase.I @@ -21,9 +21,7 @@ PointerToBase(To *ptr) { if (ptr != (To *)NULL) { ptr->ref(); #ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } + update_type(ptr); #endif } } @@ -38,11 +36,6 @@ PointerToBase(const PointerToBase ©) { if (_void_ptr != NULL) { To *ptr = (To *)_void_ptr; ptr->ref(); -#ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } -#endif } } @@ -108,17 +101,15 @@ reassign(To *ptr) { To *old_ptr = (To *)_void_ptr; _void_ptr = (void *)ptr; - if (ptr != (To *)NULL) { + if (ptr != nullptr) { ptr->ref(); #ifdef DO_MEMORY_USAGE - if (MemoryUsage::get_track_memory_usage()) { - update_type(ptr); - } + update_type(ptr); #endif } // Now delete the old pointer. - if (old_ptr != (To *)NULL) { + if (old_ptr != nullptr) { unref_delete(old_ptr); } } @@ -130,7 +121,24 @@ reassign(To *ptr) { template INLINE void PointerToBase:: reassign(const PointerToBase ©) { - reassign((To *)copy._void_ptr); + if (copy._void_ptr != _void_ptr) { + // First save the old pointer; we won't delete it until we have assigned + // the new one. We do this just in case there are cascading effects from + // deleting this pointer that might inadvertently delete the new one. + // (Don't laugh--it's happened!) + To *old_ptr = (To *)_void_ptr; + To *new_ptr = (To *)copy._void_ptr; + + _void_ptr = copy._void_ptr; + if (new_ptr != nullptr) { + new_ptr->ref(); + } + + // Now delete the old pointer. + if (old_ptr != nullptr) { + unref_delete(old_ptr); + } + } } #ifdef DO_MEMORY_USAGE @@ -139,15 +147,17 @@ reassign(const PointerToBase ©) { * object, if we know the type ourselves. */ template -void PointerToBase:: +INLINE void PointerToBase:: update_type(To *ptr) { - TypeHandle type = get_type_handle(To); - if (type == TypeHandle::none()) { - do_init_type(To); - type = get_type_handle(To); - } - if (type != TypeHandle::none()) { - MemoryUsage::update_type(ptr, type); + if (MemoryUsage::get_track_memory_usage()) { + TypeHandle type = get_type_handle(To); + if (type == TypeHandle::none()) { + do_init_type(To); + type = get_type_handle(To); + } + if (type != TypeHandle::none()) { + MemoryUsage::update_type(ptr, type); + } } } #endif // DO_MEMORY_USAGE diff --git a/panda/src/express/pointerToBase.h b/panda/src/express/pointerToBase.h index b85e6ec856..d19edd6b5c 100644 --- a/panda/src/express/pointerToBase.h +++ b/panda/src/express/pointerToBase.h @@ -45,7 +45,7 @@ protected: INLINE void reassign(const PointerToBase ©); #ifdef DO_MEMORY_USAGE - void update_type(To *ptr); + INLINE void update_type(To *ptr); #endif // DO_MEMORY_USAGE // No assignment or retrieval functions are declared in PointerToBase, diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 8497c7de71..329594eb38 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -399,6 +399,7 @@ unbind() { void CLP(CgShaderContext):: set_state_and_transform(const RenderState *target_rs, const TransformState *modelview_transform, + const TransformState *camera_transform, const TransformState *projection_transform) { if (!valid()) { @@ -410,6 +411,10 @@ set_state_and_transform(const RenderState *target_rs, if (_modelview_transform != modelview_transform) { _modelview_transform = modelview_transform; + altered |= (Shader::SSD_transform & ~Shader::SSD_view_transform); + } + if (_camera_transform != camera_transform) { + _camera_transform = camera_transform; altered |= Shader::SSD_transform; } if (_projection_transform != projection_transform) { diff --git a/panda/src/glstuff/glCgShaderContext_src.h b/panda/src/glstuff/glCgShaderContext_src.h index ae76989d77..49d451d442 100644 --- a/panda/src/glstuff/glCgShaderContext_src.h +++ b/panda/src/glstuff/glCgShaderContext_src.h @@ -25,7 +25,7 @@ class CLP(GraphicsStateGuardian); /** * xyz */ -class EXPCL_GL CLP(CgShaderContext) : public ShaderContext { +class EXPCL_GL CLP(CgShaderContext) FINAL : public ShaderContext { public: friend class CLP(GraphicsStateGuardian); @@ -39,7 +39,8 @@ public: void set_state_and_transform(const RenderState *state, const TransformState *modelview_transform, - const TransformState *projection_transform); + const TransformState *camera_transform, + const TransformState *projection_transform) OVERRIDE; void issue_parameters(int altered) OVERRIDE; void update_transform_table(const TransformTable *table); @@ -77,6 +78,7 @@ private: WCPT(RenderState) _state_rs; CPT(TransformState) _modelview_transform; + CPT(TransformState) _camera_transform; CPT(TransformState) _projection_transform; GLint _frame_number; @@ -93,10 +95,10 @@ public: register_type(_type_handle, CLASSPREFIX_QUOTED "CgShaderContext", ShaderContext::get_class_type()); } - virtual TypeHandle get_type() const { + virtual TypeHandle get_type() const OVERRIDE { return get_class_type(); } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + virtual TypeHandle force_init_type() OVERRIDE {init_type(); return get_class_type();} private: static TypeHandle _type_handle; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 5c73772b50..51636ccd73 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -10350,7 +10350,7 @@ set_state_and_transform(const RenderState *target, // Update all of the state that is bound to the shader program. if (_current_shader_context != NULL) { - _current_shader_context->set_state_and_transform(target, transform, _projection_mat); + _current_shader_context->set_state_and_transform(target, transform, _scene_setup->get_camera_transform(), _projection_mat); } #endif diff --git a/panda/src/glstuff/glShaderContext_src.cxx b/panda/src/glstuff/glShaderContext_src.cxx index 41b004775f..65a4a1c01c 100644 --- a/panda/src/glstuff/glShaderContext_src.cxx +++ b/panda/src/glstuff/glShaderContext_src.cxx @@ -874,7 +874,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { matrix_name.substr(0, 12) == "LightSource[" && sscanf(matrix_name.c_str(), "LightSource[%d].%s", &bind._index, name_buffer) == 2) { // A matrix member of a p3d_LightSource struct. - if (strncmp(name_buffer, "shadowMatrix", 127) == 0) { + if (strncmp(name_buffer, "shadowViewMatrix", 127) == 0) { if (inverse) { // Tack inverse back onto the end. strcpy(name_buffer + strlen(name_buffer), "Inverse"); @@ -884,7 +884,25 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._part[0] = Shader::SMO_light_source_i_attrib; bind._arg[0] = InternalName::make(name_buffer); bind._part[1] = Shader::SMO_identity; + bind._arg[1] = NULL; + } else if (strncmp(name_buffer, "shadowMatrix", 127) == 0) { + // Only supported for backward compatibility: includes the model + // matrix. Not very efficient to do this. + bind._func = Shader::SMF_compose; + bind._part[0] = Shader::SMO_model_to_apiview; + bind._arg[0] = NULL; + bind._part[1] = Shader::SMO_light_source_i_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + + static bool warned = false; + if (!warned) { + warned = true; + GLCAT.warning() + << "p3d_LightSource[].shadowMatrix is deprecated; use " + "shadowViewMatrix instead, which transforms from view space " + "instead of model space.\n"; + } } else { GLCAT.error() << "p3d_LightSource struct does not provide a matrix named " << matrix_name << "!\n"; return; @@ -1163,11 +1181,16 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._index = index; bind._part[0] = Shader::SMO_light_source_i_attrib; bind._arg[0] = InternalName::make(member_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame | Shader::SSD_transform; + bind._dep[0] = Shader::SSD_general | Shader::SSD_light | Shader::SSD_frame; bind._part[1] = Shader::SMO_identity; bind._arg[1] = NULL; bind._dep[1] = Shader::SSD_NONE; + if (member_name == "position" || member_name == "halfVector" || + member_name == "spotDirection") { + bind._dep[0] |= Shader::SSD_view_transform; + } + switch (param_type) { case GL_FLOAT: bind._piece = Shader::SMP_row3x1; @@ -1250,7 +1273,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_compose; bind._part[0] = Shader::SMO_world_to_view; bind._part[1] = Shader::SMO_view_to_apiview; - bind._dep[0] = Shader::SSD_general | Shader::SSD_transform; + bind._dep[0] = Shader::SSD_general | Shader::SSD_view_transform; bind._dep[1] = Shader::SSD_general; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; @@ -1262,7 +1285,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._part[0] = Shader::SMO_apiview_to_view; bind._part[1] = Shader::SMO_view_to_world; bind._dep[0] = Shader::SSD_general; - bind._dep[1] = Shader::SSD_general | Shader::SSD_transform; + bind._dep[1] = Shader::SSD_general | Shader::SSD_view_transform; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0] | bind._dep[1]; return; @@ -1383,22 +1406,43 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._id = arg_id; bind._piece = Shader::SMP_whole; bind._func = Shader::SMF_first; + bind._part[1] = Shader::SMO_identity; + bind._arg[1] = NULL; + bind._dep[1] = Shader::SSD_NONE; PT(InternalName) iname = InternalName::make(param_name); if (iname->get_parent() != InternalName::get_root()) { // It might be something like an attribute of a shader input, like a // light parameter. It might also just be a custom struct // parameter. We can't know yet, sadly. - bind._part[0] = Shader::SMO_mat_constant_x_attrib; - bind._arg[0] = InternalName::make(param_name); - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform; + if (iname->get_basename() == "shadowMatrix") { + // Special exception for shadowMatrix, which is deprecated, + // because it includes the model transformation. It is far more + // efficient to do that in the shader instead. + static bool warned = false; + if (!warned) { + warned = true; + GLCAT.warning() + << "light.shadowMatrix inputs are deprecated; use " + "shadowViewMatrix instead, which transforms from view " + "space instead of model space.\n"; + } + bind._func = Shader::SMF_compose; + bind._part[0] = Shader::SMO_model_to_apiview; + bind._arg[0] = NULL; + bind._dep[0] = Shader::SSD_general | Shader::SSD_transform; + bind._part[1] = Shader::SMO_mat_constant_x_attrib; + bind._arg[1] = InternalName::make("shadowViewMatrix"); + bind._dep[1] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; + } else { + bind._part[0] = Shader::SMO_mat_constant_x_attrib; + bind._arg[0] = InternalName::make(param_name); + bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; + } } else { bind._part[0] = Shader::SMO_mat_constant_x; bind._arg[0] = InternalName::make(param_name); bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame; } - bind._part[1] = Shader::SMO_identity; - bind._arg[1] = NULL; - bind._dep[1] = Shader::SSD_NONE; _shader->_mat_spec.push_back(bind); _shader->_mat_deps |= bind._dep[0]; return; @@ -1430,9 +1474,9 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) { bind._func = Shader::SMF_first; bind._part[0] = Shader::SMO_vec_constant_x_attrib; bind._arg[0] = iname; - // We need SSD_transform since some attributes (eg. light position) - // have to be transformed to view space. - bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_transform; + // We need SSD_view_transform since some attributes (eg. light + // position) have to be transformed to view space. + bind._dep[0] = Shader::SSD_general | Shader::SSD_shaderinputs | Shader::SSD_frame | Shader::SSD_view_transform; bind._part[1] = Shader::SMO_identity; bind._arg[1] = NULL; bind._dep[1] = Shader::SSD_NONE; @@ -1822,6 +1866,7 @@ unbind() { void CLP(ShaderContext):: set_state_and_transform(const RenderState *target_rs, const TransformState *modelview_transform, + const TransformState *camera_transform, const TransformState *projection_transform) { // Find out which state properties have changed. @@ -1829,6 +1874,10 @@ set_state_and_transform(const RenderState *target_rs, if (_modelview_transform != modelview_transform) { _modelview_transform = modelview_transform; + altered |= (Shader::SSD_transform & ~Shader::SSD_view_transform); + } + if (_camera_transform != camera_transform) { + _camera_transform = camera_transform; altered |= Shader::SSD_transform; } if (_projection_transform != projection_transform) { @@ -2440,17 +2489,17 @@ update_shader_texture_bindings(ShaderContext *prev) { const ParamTextureImage *param = NULL; Texture *tex; - const ShaderInput *sinp = _glgsg->_target_shader->get_shader_input(input._name); - switch (sinp->get_value_type()) { + const ShaderInput &sinp = _glgsg->_target_shader->get_shader_input(input._name); + switch (sinp.get_value_type()) { case ShaderInput::M_texture_image: - param = (const ParamTextureImage *)sinp->get_param(); + param = (const ParamTextureImage *)sinp.get_param(); tex = param->get_texture(); break; case ShaderInput::M_texture: // People find it convenient to be able to pass a texture without // further ado. - tex = sinp->get_texture(); + tex = sinp.get_texture(); break; case ShaderInput::M_invalid: diff --git a/panda/src/glstuff/glShaderContext_src.h b/panda/src/glstuff/glShaderContext_src.h index e143774ed6..97c9b5940c 100644 --- a/panda/src/glstuff/glShaderContext_src.h +++ b/panda/src/glstuff/glShaderContext_src.h @@ -26,7 +26,7 @@ class CLP(GraphicsStateGuardian); /** * xyz */ -class EXPCL_GL CLP(ShaderContext) : public ShaderContext { +class EXPCL_GL CLP(ShaderContext) FINAL : public ShaderContext { public: friend class CLP(GraphicsStateGuardian); @@ -41,18 +41,19 @@ public: bool get_sampler_texture_type(int &out, GLenum param_type); INLINE bool valid(void); - void bind(); - void unbind(); + void bind() OVERRIDE; + void unbind() OVERRIDE; void set_state_and_transform(const RenderState *state, const TransformState *modelview_transform, - const TransformState *projection_transform); + const TransformState *camera_transform, + const TransformState *projection_transform) OVERRIDE; - void issue_parameters(int altered); + void issue_parameters(int altered) OVERRIDE; void update_transform_table(const TransformTable *table); void update_slider_table(const SliderTable *table); - void disable_shader_vertex_arrays(); - bool update_shader_vertex_arrays(ShaderContext *prev, bool force); + void disable_shader_vertex_arrays() OVERRIDE; + bool update_shader_vertex_arrays(ShaderContext *prev, bool force) OVERRIDE; void disable_shader_texture_bindings() OVERRIDE; void update_shader_texture_bindings(ShaderContext *prev) OVERRIDE; void update_shader_buffer_bindings(ShaderContext *prev) OVERRIDE; @@ -68,6 +69,7 @@ private: WCPT(RenderState) _state_rs; CPT(TransformState) _modelview_transform; + CPT(TransformState) _camera_transform; CPT(TransformState) _projection_transform; /* @@ -126,10 +128,10 @@ public: register_type(_type_handle, CLASSPREFIX_QUOTED "ShaderContext", ShaderContext::get_class_type()); } - virtual TypeHandle get_type() const { + virtual TypeHandle get_type() const OVERRIDE { return get_class_type(); } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + virtual TypeHandle force_init_type() OVERRIDE {init_type(); return get_class_type();} private: static TypeHandle _type_handle; diff --git a/panda/src/gobj/adaptiveLru.cxx b/panda/src/gobj/adaptiveLru.cxx index 8b68f0e9b2..a74fcfcb0d 100644 --- a/panda/src/gobj/adaptiveLru.cxx +++ b/panda/src/gobj/adaptiveLru.cxx @@ -114,12 +114,16 @@ update_page(AdaptiveLruPage *page) { update_frames = (_current_frame_identifier - page->_update_frame_identifier); if (update_frames > 0) { - PN_stdfloat update_average_frame_utilization = - (PN_stdfloat) (page->_update_total_usage) / (PN_stdfloat)update_frames; + if (page->_update_total_usage > 0) { + PN_stdfloat update_average_frame_utilization = + (PN_stdfloat) (page->_update_total_usage) / (PN_stdfloat)update_frames; - page->_average_frame_utilization = - calculate_exponential_moving_average(update_average_frame_utilization, - page->_average_frame_utilization); + page->_average_frame_utilization = + calculate_exponential_moving_average(update_average_frame_utilization, + page->_average_frame_utilization); + } else { + page->_average_frame_utilization *= 1.0f - _weight; + } target_priority = page->_priority; if (page->_average_frame_utilization >= 1.0f) { diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index eb44a46abb..66d7c19e62 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -655,28 +655,72 @@ unify_in_place(int max_indices, bool preserve_order) { // Should we split it up again to satisfy max_indices? if (prim->get_num_vertices() > max_indices) { + // Copy prim into smaller prims, no one of which has more than + // max_indices vertices. + GeomPrimitivePipelineReader reader(prim, current_thread); + // Copy prim into smaller prims, no one of which has more than // max_indices vertices. int i = 0; + int num_primitives = reader.get_num_primitives(); + int num_vertices_per_primitive = prim->get_num_vertices_per_primitive(); + int num_unused_vertices_per_primitive = prim->get_num_unused_vertices_per_primitive(); + if (num_vertices_per_primitive != 0) { + // This is a simple primitive type like a triangle, where all the + // primitives share the same number of vertices. + int total_vertices_per_primitive = num_vertices_per_primitive + num_unused_vertices_per_primitive; + int max_primitives = max_indices / total_vertices_per_primitive; + const unsigned char *ptr = reader.get_read_pointer(true); + size_t stride = reader.get_index_stride(); - while (i < prim->get_num_primitives()) { - PT(GeomPrimitive) smaller = prim->make_copy(); - smaller->clear_vertices(); - while (i < prim->get_num_primitives() && - smaller->get_num_vertices() + prim->get_primitive_num_vertices(i) < max_indices) { - int start = prim->get_primitive_start(i); - int end = prim->get_primitive_end(i); - for (int n = start; n < end; ++n) { - smaller->add_vertex(prim->get_vertex(n)); + while (i < num_primitives) { + PT(GeomPrimitive) smaller = prim->make_copy(); + smaller->clear_vertices(); + + // Since the number of vertices is consistent, we can calculate how + // many primitives will fit, and copy them all in one go. + int copy_primitives = min((num_primitives - i), max_primitives); + int num_vertices = copy_primitives * total_vertices_per_primitive; + nassertv(num_vertices > 0); + { + GeomVertexArrayDataHandle writer(smaller->modify_vertices(), current_thread); + writer.unclean_set_num_rows(num_vertices); + memcpy(writer.get_write_pointer(), ptr, stride * (size_t)(num_vertices - num_unused_vertices_per_primitive)); } - smaller->close_primitive(); - ++i; + cdata->_primitives.push_back(smaller.p()); + + ptr += stride * (size_t)num_vertices; + i += copy_primitives; } + } else { + // This is a complex primitive type like a triangle strip. + CPTA_int ends = reader.get_ends(); + int start = 0; + int end = ends[0]; - cdata->_primitives.push_back(smaller.p()); + while (i < num_primitives) { + PT(GeomPrimitive) smaller = prim->make_copy(); + smaller->clear_vertices(); + + while (smaller->get_num_vertices() + (end - start) < max_indices) { + for (int n = start; n < end; ++n) { + smaller->add_vertex(reader.get_vertex(n)); + } + smaller->close_primitive(); + + ++i; + if (i >= num_primitives) { + break; + } + + start = end + num_unused_vertices_per_primitive; + end = ends[i]; + } + + cdata->_primitives.push_back(smaller.p()); + } } - } else { // The prim has few enough vertices; keep it. cdata->_primitives.push_back(prim); @@ -925,7 +969,8 @@ bool Geom:: check_valid() const { Thread *current_thread = Thread::get_current_thread(); GeomPipelineReader geom_reader(this, current_thread); - GeomVertexDataPipelineReader data_reader(geom_reader.get_vertex_data(), current_thread); + CPT(GeomVertexData) vertex_data = geom_reader.get_vertex_data(); + GeomVertexDataPipelineReader data_reader(vertex_data, current_thread); data_reader.check_array_readers(); return geom_reader.check_valid(&data_reader); } @@ -1212,6 +1257,9 @@ compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { InternalName::get_vertex(), cdata, current_thread); + nassertv(!pmin.is_nan()); + nassertv(!pmax.is_nan()); + BoundingVolume::BoundsType btype = cdata->_bounds_type; if (btype == BoundingVolume::BT_default) { btype = bounds_type; diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 1dceada335..9863701e21 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -124,8 +124,19 @@ get_vertex(int i) const { */ INLINE int GeomPrimitive:: get_num_primitives() const { - GeomPrimitivePipelineReader reader(this, Thread::get_current_thread()); - return reader.get_num_primitives(); + int num_vertices_per_primitive = get_num_vertices_per_primitive(); + + if (num_vertices_per_primitive == 0) { + // This is a complex primitive type like a triangle strip: each primitive + // uses a different number of vertices. + CDReader cdata(_cycler); + return cdata->_ends.size(); + + } else { + // This is a simple primitive type like a triangle: each primitive uses + // the same number of vertices. + return (get_num_vertices() / num_vertices_per_primitive); + } } /** diff --git a/panda/src/gobj/geomPrimitive.cxx b/panda/src/gobj/geomPrimitive.cxx index b96249cc83..23a905f8e3 100644 --- a/panda/src/gobj/geomPrimitive.cxx +++ b/panda/src/gobj/geomPrimitive.cxx @@ -165,16 +165,17 @@ add_vertex(int vertex) { consider_elevate_index_type(cdata, vertex); - int num_primitives = get_num_primitives(); - if (num_primitives > 0 && - requires_unused_vertices() && - get_num_vertices() == get_primitive_end(num_primitives - 1)) { - // If we are beginning a new primitive, give the derived class a chance to - // insert some degenerate vertices. - if (cdata->_vertices.is_null()) { - do_make_indexed(cdata); + if (requires_unused_vertices()) { + int num_primitives = get_num_primitives(); + if (num_primitives > 0 && + get_num_vertices() == get_primitive_end(num_primitives - 1)) { + // If we are beginning a new primitive, give the derived class a chance to + // insert some degenerate vertices. + if (cdata->_vertices.is_null()) { + do_make_indexed(cdata); + } + append_unused_vertices(cdata->_vertices.get_write_pointer(), vertex); } - append_unused_vertices(cdata->_vertices.get_write_pointer(), vertex); } if (cdata->_vertices.is_null()) { @@ -199,11 +200,28 @@ add_vertex(int vertex) { do_make_indexed(cdata); } - PT(GeomVertexArrayData) array_obj = cdata->_vertices.get_write_pointer(); - GeomVertexWriter index(array_obj, 0); - index.set_row_unsafe(array_obj->get_num_rows()); + { + GeomVertexArrayDataHandle handle(cdata->_vertices.get_write_pointer(), + Thread::get_current_thread()); + int num_rows = handle.get_num_rows(); + handle.set_num_rows(num_rows + 1); - index.add_data1i(vertex); + unsigned char *ptr = handle.get_write_pointer(); + switch (cdata->_index_type) { + case GeomEnums::NT_uint8: + ((uint8_t *)ptr)[num_rows] = vertex; + break; + case GeomEnums::NT_uint16: + ((uint16_t *)ptr)[num_rows] = vertex; + break; + case GeomEnums::NT_uint32: + ((uint32_t *)ptr)[num_rows] = vertex; + break; + default: + nassertv(false); + break; + } + } cdata->_modified = Geom::get_next_modified(); cdata->_got_minmax = false; @@ -888,21 +906,9 @@ make_points() const { // First, get a list of all of the vertices referenced by the original // primitive. BitArray bits; - int num_vertices = get_num_vertices(); - if (is_indexed()) { - CPT(GeomVertexArrayData) vertices = get_vertices(); - int strip_cut_index = get_strip_cut_index(); - GeomVertexReader index(vertices, 0); - for (int vi = 0; vi < num_vertices; ++vi) { - nassertr(!index.is_at_end(), NULL); - int vertex = index.get_data1i(); - if (vertex != strip_cut_index) { - bits.set_bit(vertex); - } - } - } else { - int first_vertex = get_first_vertex(); - bits.set_range(first_vertex, num_vertices); + { + GeomPrimitivePipelineReader reader(this, Thread::get_current_thread()); + reader.get_referenced_vertices(bits); } // Now construct a new index array with just those bits. @@ -2200,9 +2206,21 @@ get_vertex(int i) const { // The indexed case. nassertr(i >= 0 && i < get_num_vertices(), -1); - GeomVertexReader index(_vertices, 0); - index.set_row_unsafe(i); - return index.get_data1i(); + const unsigned char *ptr = get_read_pointer(true); + switch (_cdata->_index_type) { + case GeomEnums::NT_uint8: + return ((uint8_t *)ptr)[i]; + break; + case GeomEnums::NT_uint16: + return ((uint16_t *)ptr)[i]; + break; + case GeomEnums::NT_uint32: + return ((uint32_t *)ptr)[i]; + break; + default: + nassertr(false, -1); + return -1; + } } else { // The nonindexed case. @@ -2229,6 +2247,52 @@ get_num_primitives() const { } } +/** + * Turns on all the bits corresponding to the vertices that are referenced + * by this GeomPrimitive. + */ +void GeomPrimitivePipelineReader:: +get_referenced_vertices(BitArray &bits) const { + int num_vertices = get_num_vertices(); + + if (is_indexed()) { + int strip_cut_index = get_strip_cut_index(); + const unsigned char *ptr = get_read_pointer(true); + switch (get_index_type()) { + case GeomEnums::NT_uint8: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint8_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + case GeomEnums::NT_uint16: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint16_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + case GeomEnums::NT_uint32: + for (int vi = 0; vi < num_vertices; ++vi) { + int index = ((const uint32_t *)ptr)[vi]; + if (index != strip_cut_index) { + bits.set_bit(index); + } + } + break; + default: + nassertv(false); + break; + } + } else { + // Nonindexed case. + bits.set_range(get_first_vertex(), num_vertices); + } +} + /** * */ diff --git a/panda/src/gobj/geomPrimitive.h b/panda/src/gobj/geomPrimitive.h index 0880e77c7a..eefaf1054c 100644 --- a/panda/src/gobj/geomPrimitive.h +++ b/panda/src/gobj/geomPrimitive.h @@ -371,6 +371,7 @@ public: INLINE int get_num_vertices() const; int get_vertex(int i) const; int get_num_primitives() const; + void get_referenced_vertices(BitArray &bits) const; INLINE int get_min_vertex() const; INLINE int get_max_vertex() const; INLINE int get_data_size_bytes() const; diff --git a/panda/src/gobj/geomVertexData.I b/panda/src/gobj/geomVertexData.I index 888db97c88..47fe0ef41b 100644 --- a/panda/src/gobj/geomVertexData.I +++ b/panda/src/gobj/geomVertexData.I @@ -756,7 +756,7 @@ GeomVertexDataPipelineReader(const GeomVertexData *object, * */ INLINE void GeomVertexDataPipelineReader:: -set_object(CPT(GeomVertexData) object) { +set_object(const GeomVertexData *object) { #ifdef DO_PIPELINING if (_cdata != NULL) { unref_delete((CycleData *)_cdata); @@ -764,7 +764,7 @@ set_object(CPT(GeomVertexData) object) { #endif // DO_PIPELINING _array_readers.clear(); - _object.swap(object); + _object = (GeomVertexData *)object; _cdata = (GeomVertexData::CData *)_object->_cycler.read_unlocked(_current_thread); _got_array_readers = false; diff --git a/panda/src/gobj/geomVertexData.h b/panda/src/gobj/geomVertexData.h index 8e236029ae..37839d98b8 100644 --- a/panda/src/gobj/geomVertexData.h +++ b/panda/src/gobj/geomVertexData.h @@ -432,7 +432,7 @@ public: INLINE UpdateSeq get_modified() const; protected: - PT(GeomVertexData) _object; + GeomVertexData *_object; Thread *_current_thread; GeomVertexData::CData *_cdata; }; @@ -440,6 +440,8 @@ protected: /** * Encapsulates the data from a GeomVertexData, pre-fetched for one stage of * the pipeline. + * Does not hold a reference to the GeomVertexData, so make sure it does not + * go out of scope. */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineReader : public GeomVertexDataPipelineBase { public: @@ -448,7 +450,7 @@ public: ALLOC_DELETED_CHAIN(GeomVertexDataPipelineReader); - INLINE void set_object(CPT(GeomVertexData) object); + INLINE void set_object(const GeomVertexData *object); INLINE const GeomVertexData *get_object() const; INLINE void check_array_readers() const; @@ -504,6 +506,8 @@ private: /** * Encapsulates the data from a GeomVertexData, pre-fetched for one stage of * the pipeline. + * Does not hold a reference to the GeomVertexData, so make sure it does not + * go out of scope. */ class EXPCL_PANDA_GOBJ GeomVertexDataPipelineWriter : public GeomVertexDataPipelineBase { public: diff --git a/panda/src/gobj/internalName.h b/panda/src/gobj/internalName.h index 7485e6f758..bc636eb1c9 100644 --- a/panda/src/gobj/internalName.h +++ b/panda/src/gobj/internalName.h @@ -178,6 +178,12 @@ private: static TypeHandle _texcoord_type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const InternalName &tcn); /** diff --git a/panda/src/gobj/shader.cxx b/panda/src/gobj/shader.cxx index 27a055a794..f0cb8e0506 100644 --- a/panda/src/gobj/shader.cxx +++ b/panda/src/gobj/shader.cxx @@ -390,8 +390,10 @@ cp_dependency(ShaderMatInput inp) { if ((inp == SMO_model_to_view) || (inp == SMO_view_to_model) || (inp == SMO_model_to_apiview) || - (inp == SMO_apiview_to_model) || - (inp == SMO_view_to_world) || + (inp == SMO_apiview_to_model)) { + dep |= SSD_transform; + } + if ((inp == SMO_view_to_world) || (inp == SMO_world_to_view) || (inp == SMO_view_x_to_view) || (inp == SMO_view_to_view_x) || @@ -404,7 +406,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_dlight_x) || (inp == SMO_plight_x) || (inp == SMO_slight_x)) { - dep |= SSD_transform; + dep |= SSD_view_transform; } if ((inp == SMO_texpad_x) || (inp == SMO_texpix_x) || @@ -449,7 +451,7 @@ cp_dependency(ShaderMatInput inp) { (inp == SMO_light_source_i_attrib)) { dep |= SSD_light; if (inp == SMO_light_source_i_attrib) { - dep |= SSD_transform; + dep |= SSD_view_transform; } } if ((inp == SMO_light_product_i_ambient) || diff --git a/panda/src/gobj/shader.h b/panda/src/gobj/shader.h index e7e843b9c6..2eb0bc910a 100644 --- a/panda/src/gobj/shader.h +++ b/panda/src/gobj/shader.h @@ -287,7 +287,7 @@ public: enum ShaderStateDep { SSD_NONE = 0x000, SSD_general = 0x001, - SSD_transform = 0x002, + SSD_transform = 0x2002, SSD_color = 0x004, SSD_colorscale = 0x008, SSD_material = 0x010, @@ -299,6 +299,7 @@ public: SSD_frame = 0x400, SSD_projection = 0x800, SSD_texture = 0x1000, + SSD_view_transform= 0x2000, }; enum ShaderBug { diff --git a/panda/src/gobj/shaderContext.h b/panda/src/gobj/shaderContext.h index 7a5312faa2..a8d8add8ed 100644 --- a/panda/src/gobj/shaderContext.h +++ b/panda/src/gobj/shaderContext.h @@ -32,7 +32,10 @@ class EXPCL_PANDA_GOBJ ShaderContext: public SavedContext { public: INLINE ShaderContext(Shader *se); - INLINE virtual void set_state_and_transform(const RenderState *, const TransformState *, const TransformState*) {}; + virtual void set_state_and_transform(const RenderState *, + const TransformState *, + const TransformState *, + const TransformState *) {}; INLINE virtual bool valid() { return false; } INLINE virtual void bind() {}; diff --git a/panda/src/grutil/pipeOcclusionCullTraverser.cxx b/panda/src/grutil/pipeOcclusionCullTraverser.cxx index 91ebeb6559..1052d5ace5 100644 --- a/panda/src/grutil/pipeOcclusionCullTraverser.cxx +++ b/panda/src/grutil/pipeOcclusionCullTraverser.cxx @@ -464,42 +464,33 @@ void PipeOcclusionCullTraverser:: make_box() { PT(GeomVertexData) vdata = new GeomVertexData ("occlusion_box", GeomVertexFormat::get_v3(), Geom::UH_static); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vdata->unclean_set_num_rows(8); - vertex.add_data3(0.0f, 0.0f, 0.0f); - vertex.add_data3(0.0f, 0.0f, 1.0f); - vertex.add_data3(0.0f, 1.0f, 0.0f); - vertex.add_data3(0.0f, 1.0f, 1.0f); - vertex.add_data3(1.0f, 0.0f, 0.0f); - vertex.add_data3(1.0f, 0.0f, 1.0f); - vertex.add_data3(1.0f, 1.0f, 0.0f); - vertex.add_data3(1.0f, 1.0f, 1.0f); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + vertex.set_data3(0.0f, 0.0f, 0.0f); + vertex.set_data3(0.0f, 0.0f, 1.0f); + vertex.set_data3(0.0f, 1.0f, 0.0f); + vertex.set_data3(0.0f, 1.0f, 1.0f); + vertex.set_data3(1.0f, 0.0f, 0.0f); + vertex.set_data3(1.0f, 0.0f, 1.0f); + vertex.set_data3(1.0f, 1.0f, 0.0f); + vertex.set_data3(1.0f, 1.0f, 1.0f); + } PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static); tris->add_vertices(0, 4, 5); - tris->close_primitive(); tris->add_vertices(0, 5, 1); - tris->close_primitive(); tris->add_vertices(4, 6, 7); - tris->close_primitive(); tris->add_vertices(4, 7, 5); - tris->close_primitive(); tris->add_vertices(6, 2, 3); - tris->close_primitive(); tris->add_vertices(6, 3, 7); - tris->close_primitive(); tris->add_vertices(2, 0, 1); - tris->close_primitive(); tris->add_vertices(2, 1, 3); - tris->close_primitive(); tris->add_vertices(1, 5, 7); - tris->close_primitive(); tris->add_vertices(1, 7, 3); - tris->close_primitive(); tris->add_vertices(2, 6, 4); - tris->close_primitive(); tris->add_vertices(2, 4, 0); - tris->close_primitive(); _box_geom = new Geom(vdata); _box_geom->add_primitive(tris); diff --git a/panda/src/grutil/shaderTerrainMesh.cxx b/panda/src/grutil/shaderTerrainMesh.cxx index c01c851345..a7f6b1d8af 100644 --- a/panda/src/grutil/shaderTerrainMesh.cxx +++ b/panda/src/grutil/shaderTerrainMesh.cxx @@ -513,15 +513,15 @@ void ShaderTerrainMesh::add_for_draw(CullTraverser *trav, CullTraverserData &dat nassertv(current_shader_attrib != NULL); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.terrain_size", LVecBase2i(_size)) ); + ShaderInput("ShaderTerrainMesh.terrain_size", LVecBase2i(_size))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.chunk_size", LVecBase2i(_chunk_size))); + ShaderInput("ShaderTerrainMesh.chunk_size", LVecBase2i(_chunk_size))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.view_index", LVecBase2i(_current_view_index))); + ShaderInput("ShaderTerrainMesh.view_index", LVecBase2i(_current_view_index))); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.data_texture", _data_texture)); + ShaderInput("ShaderTerrainMesh.data_texture", _data_texture)); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_shader_input( - new ShaderInput("ShaderTerrainMesh.heightfield", _heightfield_tex)); + ShaderInput("ShaderTerrainMesh.heightfield", _heightfield_tex)); current_shader_attrib = DCAST(ShaderAttrib, current_shader_attrib)->set_instance_count( traversal_data.emitted_chunks); diff --git a/panda/src/mathutil/geometricBoundingVolume.I b/panda/src/mathutil/geometricBoundingVolume.I index 21a32c4b48..beef98f9ff 100644 --- a/panda/src/mathutil/geometricBoundingVolume.I +++ b/panda/src/mathutil/geometricBoundingVolume.I @@ -16,6 +16,9 @@ */ INLINE_MATHUTIL GeometricBoundingVolume:: GeometricBoundingVolume() { +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** diff --git a/panda/src/mathutil/geometricBoundingVolume.h b/panda/src/mathutil/geometricBoundingVolume.h index 90c794d832..cc48177f17 100644 --- a/panda/src/mathutil/geometricBoundingVolume.h +++ b/panda/src/mathutil/geometricBoundingVolume.h @@ -83,6 +83,12 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "geometricBoundingVolume.I" #endif diff --git a/panda/src/parametrics/ropeNode.cxx b/panda/src/parametrics/ropeNode.cxx index c799595888..365795adf7 100644 --- a/panda/src/parametrics/ropeNode.cxx +++ b/panda/src/parametrics/ropeNode.cxx @@ -132,9 +132,9 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (curve != (NurbsCurveEvaluator *)NULL) { PT(NurbsCurveResult) result; if (has_matrix()) { - result = curve->evaluate(data._node_path.get_node_path(), get_matrix()); + result = curve->evaluate(data.get_node_path(), get_matrix()); } else { - result = curve->evaluate(data._node_path.get_node_path()); + result = curve->evaluate(data.get_node_path()); } if (result->get_num_segments() > 0) { diff --git a/panda/src/parametrics/sheetNode.cxx b/panda/src/parametrics/sheetNode.cxx index 34496bca68..b4e4cc5a4d 100644 --- a/panda/src/parametrics/sheetNode.cxx +++ b/panda/src/parametrics/sheetNode.cxx @@ -129,7 +129,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { if (get_num_u_subdiv() > 0 && get_num_v_subdiv() > 0) { NurbsSurfaceEvaluator *surface = get_surface(); if (surface != (NurbsSurfaceEvaluator *)NULL) { - PT(NurbsSurfaceResult) result = surface->evaluate(data._node_path.get_node_path()); + PT(NurbsSurfaceResult) result = surface->evaluate(data.get_node_path()); if (result->get_num_u_segments() > 0 && result->get_num_v_segments() > 0) { render_sheet(trav, data, result); diff --git a/panda/src/pgraph/billboardEffect.cxx b/panda/src/pgraph/billboardEffect.cxx index dad0638245..737b370c42 100644 --- a/panda/src/pgraph/billboardEffect.cxx +++ b/panda/src/pgraph/billboardEffect.cxx @@ -164,7 +164,7 @@ has_adjust_transform() const { void BillboardEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *) const { + const PandaNode *) const { // A BillboardEffect can only affect the net transform when it is to a // particular node. A billboard to a camera is camera-dependent, of course, // so it has no effect in the absence of any particular camera viewing it. diff --git a/panda/src/pgraph/billboardEffect.h b/panda/src/pgraph/billboardEffect.h index 2d528453f9..284182ba91 100644 --- a/panda/src/pgraph/billboardEffect.h +++ b/panda/src/pgraph/billboardEffect.h @@ -60,7 +60,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/pgraph/compassEffect.cxx b/panda/src/pgraph/compassEffect.cxx index c1e0cf24a8..d972e7f45a 100644 --- a/panda/src/pgraph/compassEffect.cxx +++ b/panda/src/pgraph/compassEffect.cxx @@ -157,7 +157,7 @@ has_adjust_transform() const { void CompassEffect:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *) const { + const PandaNode *) const { if (_properties == 0) { // Nothing to do. return; diff --git a/panda/src/pgraph/compassEffect.h b/panda/src/pgraph/compassEffect.h index 60ec6d03e9..6600820bb1 100644 --- a/panda/src/pgraph/compassEffect.h +++ b/panda/src/pgraph/compassEffect.h @@ -78,7 +78,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; protected: virtual int compare_to_impl(const RenderEffect *other) const; diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index 10b9fb04d3..f481a2aeb1 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -78,7 +78,6 @@ #include "scissorAttrib.h" #include "scissorEffect.h" #include "shadeModelAttrib.h" -#include "shaderInput.h" #include "shaderAttrib.h" #include "shader.h" #include "showBoundsEffect.h" @@ -449,7 +448,6 @@ init_libpgraph() { ScissorAttrib::init_type(); ScissorEffect::init_type(); ShadeModelAttrib::init_type(); - ShaderInput::init_type(); ShaderAttrib::init_type(); ShowBoundsEffect::init_type(); StateMunger::init_type(); @@ -502,7 +500,6 @@ init_libpgraph() { ScissorAttrib::register_with_read_factory(); ScissorEffect::register_with_read_factory(); ShadeModelAttrib::register_with_read_factory(); - ShaderInput::register_with_read_factory(); ShaderAttrib::register_with_read_factory(); ShowBoundsEffect::register_with_read_factory(); TexMatrixAttrib::register_with_read_factory(); diff --git a/panda/src/pgraph/cullPlanes.cxx b/panda/src/pgraph/cullPlanes.cxx index 782637c973..43a249403b 100644 --- a/panda/src/pgraph/cullPlanes.cxx +++ b/panda/src/pgraph/cullPlanes.cxx @@ -315,11 +315,10 @@ do_cull(int &result, CPT(RenderState) &state, result = BoundingVolume::IF_all | BoundingVolume::IF_possible | BoundingVolume::IF_some; - CPT(ClipPlaneAttrib) orig_cpa = DCAST(ClipPlaneAttrib, state->get_attrib(ClipPlaneAttrib::get_class_slot())); - CPT(CullPlanes) new_planes = this; - if (orig_cpa == (ClipPlaneAttrib *)NULL) { + const ClipPlaneAttrib *orig_cpa; + if (!state->get_attrib(orig_cpa)) { // If there are no clip planes in the state, the node is completely in // front of all zero of the clip planes. (This can happen if someone // directly changes the state during the traversal.) diff --git a/panda/src/pgraph/cullPlanes.h b/panda/src/pgraph/cullPlanes.h index 483eb2d30a..c091eebdc9 100644 --- a/panda/src/pgraph/cullPlanes.h +++ b/panda/src/pgraph/cullPlanes.h @@ -74,6 +74,12 @@ private: Occluders _occluders; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "cullPlanes.I" #endif diff --git a/panda/src/pgraph/cullTraverser.I b/panda/src/pgraph/cullTraverser.I index 180b94b37a..5da999d673 100644 --- a/panda/src/pgraph/cullTraverser.I +++ b/panda/src/pgraph/cullTraverser.I @@ -200,20 +200,14 @@ do_traverse(CullTraverserData &data) { if (is_in_view(data)) { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << "\n" << data._node_path + << "\n" << data.get_node_path() << " " << data._draw_mask << "\n"; } PandaNodePipelineReader *node_reader = data.node_reader(); int fancy_bits = node_reader->get_fancy_bits(); - if ((fancy_bits & (PandaNode::FB_transform | - PandaNode::FB_state | - PandaNode::FB_effects | - PandaNode::FB_tag | - PandaNode::FB_draw_mask | - PandaNode::FB_cull_callback)) == 0 && - data._cull_planes->is_empty()) { + if (fancy_bits == 0 && data._cull_planes->is_empty()) { // Nothing interesting in this node; just move on. } else { diff --git a/panda/src/pgraph/cullTraverser.cxx b/panda/src/pgraph/cullTraverser.cxx index 5d08b4e5dd..a796718828 100644 --- a/panda/src/pgraph/cullTraverser.cxx +++ b/panda/src/pgraph/cullTraverser.cxx @@ -113,10 +113,8 @@ traverse(const NodePath &root) { GeometricBoundingVolume *local_frustum = NULL; PT(BoundingVolume) bv = _scene_setup->get_lens()->make_bounds(); - if (bv != (BoundingVolume *)NULL && - bv->is_of_type(GeometricBoundingVolume::get_class_type())) { - - local_frustum = DCAST(GeometricBoundingVolume, bv); + if (bv != nullptr) { + local_frustum = bv->as_geometric_bounding_volume(); } // This local_frustum is in camera space @@ -199,19 +197,18 @@ traverse_below(CullTraverserData &data) { PandaNode::Children children = node_reader->get_children(); node_reader->release(); int num_children = children.get_num_children(); - if (node->has_selective_visibility()) { + if (!node->has_selective_visibility()) { + for (int i = 0; i < num_children; ++i) { + CullTraverserData next_data(data, children.get_child(i)); + do_traverse(next_data); + } + } else { int i = node->get_first_visible_child(); while (i < num_children) { CullTraverserData next_data(data, children.get_child(i)); do_traverse(next_data); i = node->get_next_visible_child(i); } - - } else { - for (int i = 0; i < num_children; i++) { - CullTraverserData next_data(data, children.get_child(i)); - do_traverse(next_data); - } } } @@ -235,12 +232,12 @@ draw_bounding_volume(const BoundingVolume *vol, if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(2); CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_outer_viz_state(), internal_transform); _cull_handler->record_object(outer_viz, this); CullableObject *inner_viz = - new CullableObject(bounds_viz, get_bounds_inner_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_inner_viz_state(), internal_transform); _cull_handler->record_object(inner_viz, this); } @@ -270,7 +267,7 @@ show_bounds(CullTraverserData &data, bool tight) { if (bounds_viz != (Geom *)NULL) { _geoms_pcollector.add_level(1); CullableObject *outer_viz = - new CullableObject(bounds_viz, get_bounds_outer_viz_state(), + new CullableObject(move(bounds_viz), get_bounds_outer_viz_state(), internal_transform); _cull_handler->record_object(outer_viz, this); } @@ -281,7 +278,7 @@ show_bounds(CullTraverserData &data, bool tight) { if (node->is_geom_node()) { // Also show the bounding volumes of included Geoms. internal_transform = internal_transform->compose(node->get_transform()); - GeomNode *gnode = DCAST(GeomNode, node); + GeomNode *gnode = (GeomNode *)node; int num_geoms = gnode->get_num_geoms(); for (int i = 0; i < num_geoms; ++i) { draw_bounding_volume(gnode->get_geom(i)->get_bounds(), @@ -334,29 +331,31 @@ make_bounds_viz(const BoundingVolume *vol) { const BoundingHexahedron *fvol = DCAST(BoundingHexahedron, vol); PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - for (int i = 0; i < 8; ++i ) { - vertex.add_data3(fvol->get_point(i)); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + for (int i = 0; i < 8; ++i) { + vertex.set_data3(fvol->get_point(i)); + } } PT(GeomLines) lines = new GeomLines(Geom::UH_stream); - lines->add_vertices(0, 1); lines->close_primitive(); - lines->add_vertices(1, 2); lines->close_primitive(); - lines->add_vertices(2, 3); lines->close_primitive(); - lines->add_vertices(3, 0); lines->close_primitive(); + lines->add_vertices(0, 1); + lines->add_vertices(1, 2); + lines->add_vertices(2, 3); + lines->add_vertices(3, 0); - lines->add_vertices(4, 5); lines->close_primitive(); - lines->add_vertices(5, 6); lines->close_primitive(); - lines->add_vertices(6, 7); lines->close_primitive(); - lines->add_vertices(7, 4); lines->close_primitive(); + lines->add_vertices(4, 5); + lines->add_vertices(5, 6); + lines->add_vertices(6, 7); + lines->add_vertices(7, 4); - lines->add_vertices(0, 4); lines->close_primitive(); - lines->add_vertices(1, 5); lines->close_primitive(); - lines->add_vertices(2, 6); lines->close_primitive(); - lines->add_vertices(3, 7); lines->close_primitive(); + lines->add_vertices(0, 4); + lines->add_vertices(1, 5); + lines->add_vertices(2, 6); + lines->add_vertices(3, 7); geom = new Geom(vdata); geom->add_primitive(lines); @@ -368,39 +367,29 @@ make_bounds_viz(const BoundingVolume *vol) { box.local_object(); PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - for (int i = 0; i < 8; ++i ) { - vertex.add_data3(box.get_point(i)); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex()); + for (int i = 0; i < 8; ++i) { + vertex.set_data3(box.get_point(i)); + } } PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_stream); tris->add_vertices(0, 4, 5); - tris->close_primitive(); tris->add_vertices(0, 5, 1); - tris->close_primitive(); tris->add_vertices(4, 6, 7); - tris->close_primitive(); tris->add_vertices(4, 7, 5); - tris->close_primitive(); tris->add_vertices(6, 2, 3); - tris->close_primitive(); tris->add_vertices(6, 3, 7); - tris->close_primitive(); tris->add_vertices(2, 0, 1); - tris->close_primitive(); tris->add_vertices(2, 1, 3); - tris->close_primitive(); tris->add_vertices(1, 5, 7); - tris->close_primitive(); tris->add_vertices(1, 7, 3); - tris->close_primitive(); tris->add_vertices(2, 6, 4); - tris->close_primitive(); tris->add_vertices(2, 4, 0); - tris->close_primitive(); geom = new Geom(vdata); geom->add_primitive(tris); @@ -430,19 +419,21 @@ make_tight_bounds_viz(PandaNode *node) const { _current_thread); if (found_any) { PT(GeomVertexData) vdata = new GeomVertexData - ("bounds", GeomVertexFormat::get_v3(), - Geom::UH_stream); - GeomVertexWriter vertex(vdata, InternalName::get_vertex(), - _current_thread); + ("bounds", GeomVertexFormat::get_v3(), Geom::UH_stream); + vdata->unclean_set_num_rows(8); - vertex.add_data3(n[0], n[1], n[2]); - vertex.add_data3(n[0], n[1], x[2]); - vertex.add_data3(n[0], x[1], n[2]); - vertex.add_data3(n[0], x[1], x[2]); - vertex.add_data3(x[0], n[1], n[2]); - vertex.add_data3(x[0], n[1], x[2]); - vertex.add_data3(x[0], x[1], n[2]); - vertex.add_data3(x[0], x[1], x[2]); + { + GeomVertexWriter vertex(vdata, InternalName::get_vertex(), + _current_thread); + vertex.set_data3(n[0], n[1], n[2]); + vertex.set_data3(n[0], n[1], x[2]); + vertex.set_data3(n[0], x[1], n[2]); + vertex.set_data3(n[0], x[1], x[2]); + vertex.set_data3(x[0], n[1], n[2]); + vertex.set_data3(x[0], n[1], x[2]); + vertex.set_data3(x[0], x[1], n[2]); + vertex.set_data3(x[0], x[1], x[2]); + } PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream); diff --git a/panda/src/pgraph/cullTraverserData.I b/panda/src/pgraph/cullTraverserData.I index 4367d1608e..e2a9a64c95 100644 --- a/panda/src/pgraph/cullTraverserData.I +++ b/panda/src/pgraph/cullTraverserData.I @@ -20,7 +20,8 @@ CullTraverserData(const NodePath &start, const RenderState *state, GeometricBoundingVolume *view_frustum, Thread *current_thread) : - _node_path(start), + _next(nullptr), + _start(start._head), _node_reader(start.node(), current_thread), _net_transform(net_transform), _state(state), @@ -34,44 +35,16 @@ CullTraverserData(const NodePath &start, _node_reader.check_cached(check_bounds); } -/** - * - */ -INLINE CullTraverserData:: -CullTraverserData(const CullTraverserData ©) : - _node_path(copy._node_path), - _node_reader(copy._node_reader), - _net_transform(copy._net_transform), - _state(copy._state), - _view_frustum(copy._view_frustum), - _cull_planes(copy._cull_planes), - _draw_mask(copy._draw_mask), - _portal_depth(copy._portal_depth) -{ -} - -/** - * - */ -INLINE void CullTraverserData:: -operator = (const CullTraverserData ©) { - _node_path = copy._node_path; - _node_reader = copy._node_reader; - _net_transform = copy._net_transform; - _state = copy._state; - _view_frustum = copy._view_frustum; - _cull_planes = copy._cull_planes; - _draw_mask = copy._draw_mask; - _portal_depth = copy._portal_depth; -} - /** * This constructor creates a CullTraverserData object that reflects the next * node down in the traversal. */ INLINE CullTraverserData:: CullTraverserData(const CullTraverserData &parent, PandaNode *child) : - _node_path(parent._node_path, child), + _next(&parent), +#ifdef _DEBUG + _start(nullptr), +#endif _node_reader(child, parent._node_reader.get_current_thread()), _net_transform(parent._net_transform), _state(parent._state), @@ -86,19 +59,12 @@ CullTraverserData(const CullTraverserData &parent, PandaNode *child) : _node_reader.check_cached(check_bounds); } -/** - * - */ -INLINE CullTraverserData:: -~CullTraverserData() { -} - /** * Returns the node traversed to so far. */ INLINE PandaNode *CullTraverserData:: node() const { - return _node_path.node(); + return (PandaNode *)_node_reader.get_node(); } /** @@ -117,6 +83,18 @@ node_reader() const { return &_node_reader; } +/** + * Constructs and returns an actual NodePath that represents the same path we + * have just traversed. + */ +INLINE NodePath CullTraverserData:: +get_node_path() const { + NodePath result; + result._head = r_get_node_path(); + nassertr(result._head != nullptr, NodePath::fail()); + return result; +} + /** * Returns the modelview transform: the relative transform from the camera to * the model. diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index b6bb5911f4..1a8280948f 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -46,25 +46,33 @@ apply_transform_and_state(CullTraverser *trav) { } _node_reader.compose_draw_mask(_draw_mask); - apply_transform_and_state(trav, _node_reader.get_transform(), - MOVE(node_state), _node_reader.get_effects(), - _node_reader.get_off_clip_planes()); + const RenderEffects *node_effects = _node_reader.get_effects(); + if (!node_effects->has_cull_callback()) { + apply_transform(_node_reader.get_transform()); + } else { + // The cull callback may decide to modify the node_transform. + CPT(TransformState) node_transform = _node_reader.get_transform(); + node_effects->cull_callback(trav, *this, node_transform, node_state); + apply_transform(node_transform); + } + + if (!node_state->is_empty()) { + _state = _state->compose(node_state); + } + + if (clip_plane_cull) { + _cull_planes = _cull_planes->apply_state(trav, this, + (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), + (const ClipPlaneAttrib *)_node_reader.get_off_clip_planes(), + (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); + } } /** - * Applies the indicated transform and state changes (e.g. as extracted from - * a node) onto the current data. This also evaluates billboards, etc. + * Applies the indicated transform changes onto the current data. */ void CullTraverserData:: -apply_transform_and_state(CullTraverser *trav, - CPT(TransformState) node_transform, - CPT(RenderState) node_state, - CPT(RenderEffects) node_effects, - const RenderAttrib *off_clip_planes) { - if (node_effects->has_cull_callback()) { - node_effects->cull_callback(trav, *this, node_transform, node_state); - } - +apply_transform(const TransformState *node_transform) { if (!node_transform->is_identity()) { _net_transform = _net_transform->compose(node_transform); @@ -95,15 +103,40 @@ apply_transform_and_state(CullTraverser *trav, } } } +} - _state = _state->compose(node_state); - - if (clip_plane_cull) { - _cull_planes = _cull_planes->apply_state(trav, this, - (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), - (const ClipPlaneAttrib *)off_clip_planes, - (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); +/** + * The private, recursive implementation of get_node_path(), this returns the + * NodePathComponent representing the NodePath. + */ +PT(NodePathComponent) CullTraverserData:: +r_get_node_path() const { + if (_next == nullptr) { + nassertr(_start != nullptr, nullptr); + return _start; } + +#ifdef _DEBUG + nassertr(_start == nullptr, nullptr); +#endif + nassertr(node() != nullptr, nullptr); + + PT(NodePathComponent) comp = _next->r_get_node_path(); + nassertr(comp != nullptr, nullptr); + + Thread *current_thread = Thread::get_current_thread(); + int pipeline_stage = current_thread->get_pipeline_stage(); + PT(NodePathComponent) result = + PandaNode::get_component(comp, node(), pipeline_stage, current_thread); + if (result == nullptr) { + // This means we found a disconnected chain in the CullTraverserData's + // ancestry: the node above this node isn't connected. In this case, + // don't attempt to go higher; just truncate the NodePath at the bottom of + // the disconnect. + return PandaNode::get_top_component(node(), true, pipeline_stage, current_thread); + } + + return result; } /** @@ -121,7 +154,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " cull result = " << hex << result << dec << "\n"; + << get_node_path() << " cull result = " << hex << result << dec << "\n"; } if (result == BoundingVolume::IF_no_intersection) { @@ -136,8 +169,7 @@ is_in_view_impl() { // If we have fake view-frustum culling enabled, instead of actually // culling an object we simply force it to be drawn in red wireframe. _view_frustum = (GeometricBoundingVolume *)NULL; - CPT(RenderState) fake_state = get_fake_view_frustum_cull_state(); - _state = _state->compose(fake_state); + _state = _state->compose(get_fake_view_frustum_cull_state()); #endif } else if ((result & BoundingVolume::IF_all) != 0) { @@ -170,7 +202,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " cull planes cull result = " << hex + << get_node_path() << " cull planes cull result = " << hex << result << dec << "\n"; _cull_planes->write(pgraph_cat.spam(false)); } @@ -182,7 +214,7 @@ is_in_view_impl() { if (pgraph_cat.is_spam()) { pgraph_cat.spam() - << _node_path << " is_final, cull planes disabled, state:\n"; + << get_node_path() << " is_final, cull planes disabled, state:\n"; _state->write(pgraph_cat.spam(false), 2); } } @@ -196,8 +228,7 @@ is_in_view_impl() { return false; } _cull_planes = CullPlanes::make_empty(); - CPT(RenderState) fake_state = get_fake_view_frustum_cull_state(); - _state = _state->compose(fake_state); + _state = _state->compose(get_fake_view_frustum_cull_state()); #endif } else if ((result & BoundingVolume::IF_all) != 0) { @@ -215,15 +246,15 @@ is_in_view_impl() { * Returns a RenderState for rendering stuff in red wireframe, strictly for * the fake_view_frustum_cull effect. */ -CPT(RenderState) CullTraverserData:: +const RenderState *CullTraverserData:: get_fake_view_frustum_cull_state() { #ifdef NDEBUG - return NULL; + return nullptr; #else // Once someone asks for this pointer, we hold its reference count and never // free it. - static CPT(RenderState) state = (const RenderState *)NULL; - if (state == (const RenderState *)NULL) { + static CPT(RenderState) state; + if (state == nullptr) { state = RenderState::make (ColorAttrib::make_flat(LColor(1.0f, 0.0f, 0.0f, 1.0f)), TextureAttrib::make_all_off(), diff --git a/panda/src/pgraph/cullTraverserData.h b/panda/src/pgraph/cullTraverserData.h index 80d523fe0c..e275dcfd93 100644 --- a/panda/src/pgraph/cullTraverserData.h +++ b/panda/src/pgraph/cullTraverserData.h @@ -44,11 +44,8 @@ public: const RenderState *state, GeometricBoundingVolume *view_frustum, Thread *current_thread); - INLINE CullTraverserData(const CullTraverserData ©); - INLINE void operator = (const CullTraverserData ©); INLINE CullTraverserData(const CullTraverserData &parent, PandaNode *child); - INLINE ~CullTraverserData(); PUBLISHED: INLINE PandaNode *node() const; @@ -57,6 +54,8 @@ public: INLINE PandaNodePipelineReader *node_reader(); INLINE const PandaNodePipelineReader *node_reader() const; + INLINE NodePath get_node_path() const; + PUBLISHED: INLINE CPT(TransformState) get_modelview_transform(const CullTraverser *trav) const; INLINE CPT(TransformState) get_internal_transform(const CullTraverser *trav) const; @@ -66,14 +65,15 @@ PUBLISHED: INLINE bool is_this_node_hidden(const DrawMask &camera_mask) const; void apply_transform_and_state(CullTraverser *trav); - void apply_transform_and_state(CullTraverser *trav, - CPT(TransformState) node_transform, - CPT(RenderState) node_state, - CPT(RenderEffects) node_effects, - const RenderAttrib *off_clip_planes); + void apply_transform(const TransformState *node_transform); + +private: + // We store a chain leading all the way to the root, so that we can compose + // a NodePath. We may be able to eliminate this requirement in the future. + const CullTraverserData *_next; + NodePathComponent *_start; public: - WorkingNodePath _node_path; PandaNodePipelineReader _node_reader; CPT(TransformState) _net_transform; CPT(RenderState) _state; @@ -83,8 +83,10 @@ public: int _portal_depth; private: + PT(NodePathComponent) r_get_node_path() const; + bool is_in_view_impl(); - static CPT(RenderState) get_fake_view_frustum_cull_state(); + static const RenderState *get_fake_view_frustum_cull_state(); }; /* okcircular */ diff --git a/panda/src/pgraph/geomTransformer.cxx b/panda/src/pgraph/geomTransformer.cxx index 04207356bd..65c1ca6c80 100644 --- a/panda/src/pgraph/geomTransformer.cxx +++ b/panda/src/pgraph/geomTransformer.cxx @@ -151,7 +151,7 @@ transform_vertices(GeomNode *node, const LMatrix4 &mat) { GeomNode::GeomEntry &entry = (*gi); PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy(); if (transform_vertices(new_geom, mat)) { - entry._geom = new_geom; + entry._geom = move(new_geom); any_changed = true; } } @@ -1439,13 +1439,8 @@ remove_unused_vertices(const GeomVertexData *vdata) { any_referenced = true; int num_primitives = geom->get_num_primitives(); for (int i = 0; i < num_primitives; ++i) { - CPT(GeomPrimitive) prim = geom->get_primitive(i); - - GeomPrimitivePipelineReader reader(prim, current_thread); - int num_vertices = reader.get_num_vertices(); - for (int vi = 0; vi < num_vertices; ++vi) { - referenced_vertices.set_bit(reader.get_vertex(vi)); - } + GeomPrimitivePipelineReader reader(geom->get_primitive(i), current_thread); + reader.get_referenced_vertices(referenced_vertices); } } diff --git a/panda/src/pgraph/nodePath.I b/panda/src/pgraph/nodePath.I index cfcef09112..efe133c215 100644 --- a/panda/src/pgraph/nodePath.I +++ b/panda/src/pgraph/nodePath.I @@ -1080,7 +1080,7 @@ get_sa() const { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1088,7 +1088,7 @@ set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1096,7 +1096,7 @@ set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_int &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1104,7 +1104,7 @@ set_shader_input(CPT_InternalName id, const PTA_int &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1112,7 +1112,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } @@ -1121,7 +1121,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1129,7 +1129,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1137,7 +1137,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1145,7 +1145,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1153,7 +1153,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1161,7 +1161,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } @@ -1170,7 +1170,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1178,7 +1178,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1186,7 +1186,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1194,7 +1194,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1202,7 +1202,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2i &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1210,7 +1210,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1218,7 +1218,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1226,7 +1226,7 @@ set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) { - set_shader_input(new ShaderInput(id, v, priority)); + set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -1234,7 +1234,7 @@ set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, int priority) { - set_shader_input(new ShaderInput(id, tex, priority)); + set_shader_input(ShaderInput(move(id), tex, priority)); } /** @@ -1242,7 +1242,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority) { - set_shader_input(new ShaderInput(id, tex, sampler, priority)); + set_shader_input(ShaderInput(move(id), tex, sampler, priority)); } /** @@ -1250,7 +1250,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z, int n, int priority) { - set_shader_input(new ShaderInput(id, tex, read, write, z, n, priority)); + set_shader_input(ShaderInput(move(id), tex, read, write, z, n, priority)); } /** @@ -1258,7 +1258,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) { - set_shader_input(new ShaderInput(id, buf, priority)); + set_shader_input(ShaderInput(move(id), buf, priority)); } /** @@ -1266,7 +1266,7 @@ set_shader_input(CPT_InternalName id, ShaderBuffer *buf, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, const NodePath &np, int priority) { - set_shader_input(new ShaderInput(id, np, priority)); + set_shader_input(ShaderInput(move(id), np, priority)); } /** @@ -1274,7 +1274,7 @@ set_shader_input(CPT_InternalName id, const NodePath &np, int priority) { */ INLINE void NodePath:: set_shader_input(CPT_InternalName id, int n1, int n2, int n3, int n4, int priority) { - set_shader_input(new ShaderInput(id, LVecBase4i(n1, n2, n3, n4), priority)); + set_shader_input(ShaderInput(move(id), LVecBase4i(n1, n2, n3, n4), priority)); } /** @@ -1282,7 +1282,7 @@ set_shader_input(CPT_InternalName id, int n1, int n2, int n3, int n4, int priori */ 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(new ShaderInput(id, LVecBase4(n1, n2, n3, n4), priority)); + set_shader_input(ShaderInput(move(id), LVecBase4(n1, n2, n3, n4), priority)); } /** diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index de0cf7c4fb..f0056e703f 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -697,8 +697,10 @@ get_state(const NodePath &other, Thread *current_thread) const { return other.get_net_state(current_thread)->invert_compose(RenderState::make_empty()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), RenderState::make_empty()); nassertr(other.verify_complete(current_thread), RenderState::make_empty()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -767,8 +769,10 @@ get_transform(const NodePath &other, Thread *current_thread) const { return other.get_net_transform(current_thread)->invert_compose(TransformState::make_identity()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), TransformState::make_identity()); nassertr(other.verify_complete(current_thread), TransformState::make_identity()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -852,8 +856,10 @@ get_prev_transform(const NodePath &other, Thread *current_thread) const { return other.get_net_prev_transform(current_thread)->invert_compose(TransformState::make_identity()); } +#if defined(_DEBUG) || (defined(HAVE_THREADS) && defined(SIMPLE_THREADS)) nassertr(verify_complete(current_thread), TransformState::make_identity()); nassertr(other.verify_complete(current_thread), TransformState::make_identity()); +#endif int a_count, b_count; if (find_common_ancestor(*this, other, a_count, b_count, current_thread) == (NodePathComponent *)NULL) { @@ -3255,35 +3261,36 @@ get_shader() const { * */ void NodePath:: -set_shader_input(const ShaderInput *inp) { +set_shader_input(ShaderInput inp) { nassertv_always(!is_empty()); + PandaNode *pnode = node(); const RenderAttrib *attrib = - node()->get_attrib(ShaderAttrib::get_class_slot()); - if (attrib != (const RenderAttrib *)NULL) { - const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); - node()->set_attrib(sa->set_shader_input(inp)); + pnode->get_attrib(ShaderAttrib::get_class_slot()); + if (attrib != nullptr) { + const ShaderAttrib *sa = (const ShaderAttrib *)attrib; + pnode->set_attrib(sa->set_shader_input(inp)); } else { // Create a new ShaderAttrib for this node. CPT(ShaderAttrib) sa = DCAST(ShaderAttrib, ShaderAttrib::make()); - node()->set_attrib(sa->set_shader_input(inp)); + pnode->set_attrib(sa->set_shader_input(inp)); } } /** * */ -const ShaderInput *NodePath:: +ShaderInput NodePath:: get_shader_input(CPT_InternalName id) const { - nassertr_always(!is_empty(), NULL); + nassertr_always(!is_empty(), ShaderInput::get_blank()); const RenderAttrib *attrib = node()->get_attrib(ShaderAttrib::get_class_slot()); - if (attrib != (const RenderAttrib *)NULL) { - const ShaderAttrib *sa = DCAST(ShaderAttrib, attrib); + if (attrib != nullptr) { + const ShaderAttrib *sa = (const ShaderAttrib *)attrib; return sa->get_shader_input(id); } - return NULL; + return ShaderInput::get_blank(); } /** @@ -5786,17 +5793,22 @@ r_get_net_transform(NodePathComponent *comp, Thread *current_thread) const { if (comp == (NodePathComponent *)NULL) { return TransformState::make_identity(); } else { + PandaNode *node = comp->get_node(); int pipeline_stage = current_thread->get_pipeline_stage(); CPT(TransformState) net_transform = r_get_net_transform(comp->get_next(pipeline_stage, current_thread), current_thread); - PandaNode *node = comp->get_node(); - CPT(TransformState) transform = node->get_transform(current_thread); - CPT(RenderEffects) effects = node->get_effects(current_thread); - if (effects->has_adjust_transform()) { - effects->adjust_transform(net_transform, transform, node); + PandaNode::CDReader node_cdata(node->_cycler, current_thread); + if (!node_cdata->_effects->has_adjust_transform()) { + if (node_cdata->_transform->is_identity()) { + return net_transform; + } else { + return net_transform->compose(node_cdata->_transform); + } + } else { + CPT(TransformState) transform = node_cdata->_transform.p(); + node_cdata->_effects->adjust_transform(net_transform, transform, node); + return net_transform->compose(transform); } - - return net_transform->compose(transform); } } @@ -5814,16 +5826,21 @@ r_get_partial_transform(NodePathComponent *comp, int n, if (n == 0 || comp == (NodePathComponent *)NULL) { return TransformState::make_identity(); } else { - if (comp->get_node()->get_effects(current_thread)->has_adjust_transform()) { + PandaNode *node = comp->get_node(); + PandaNode::CDReader node_cdata(node->_cycler, current_thread); + if (node_cdata->_effects->has_adjust_transform()) { return NULL; } - CPT(TransformState) transform = comp->get_node()->get_transform(current_thread); int pipeline_stage = current_thread->get_pipeline_stage(); CPT(TransformState) partial = r_get_partial_transform(comp->get_next(pipeline_stage, current_thread), n - 1, current_thread); if (partial == (const TransformState *)NULL) { return NULL; } - return partial->compose(transform); + if (node_cdata->_transform->is_identity()) { + return partial; + } else { + return partial->compose(node_cdata->_transform); + } } } diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index 6aeeda6d01..e6eaca10cd 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -629,7 +629,7 @@ PUBLISHED: void set_shader_auto(BitMask32 shader_switch, int priority=0); void clear_shader(); - void set_shader_input(const ShaderInput *inp); + void set_shader_input(ShaderInput input); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, int priority=0); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, const SamplerState &sampler, int priority=0); INLINE void set_shader_input(CPT_InternalName id, Texture *tex, bool read, bool write, int z=-1, int n=0, int priority=0); @@ -665,7 +665,7 @@ PUBLISHED: void set_instance_count(int instance_count); const Shader *get_shader() const; - const ShaderInput *get_shader_input(CPT_InternalName id) const; + ShaderInput get_shader_input(CPT_InternalName id) const; int get_instance_count() const; void set_tex_transform(TextureStage *stage, const TransformState *transform); @@ -1029,6 +1029,7 @@ private: friend class NodePathCollection; friend class WorkingNodePath; friend class WeakNodePath; + friend class CullTraverserData; }; INLINE ostream &operator << (ostream &out, const NodePath &node_path); diff --git a/panda/src/pgraph/nodePathComponent.I b/panda/src/pgraph/nodePathComponent.I index fa16ebe2b9..d3abe36c07 100644 --- a/panda/src/pgraph/nodePathComponent.I +++ b/panda/src/pgraph/nodePathComponent.I @@ -75,6 +75,15 @@ has_key() const { return (_key != 0); } +/** + * Returns the next component in the path. + */ +INLINE NodePathComponent *NodePathComponent:: +get_next(int pipeline_stage, Thread *current_thread) const { + CDStageReader cdata(_cycler, pipeline_stage, current_thread); + return cdata->_next; +} + INLINE ostream &operator << (ostream &out, const NodePathComponent &comp) { comp.output(out); return out; diff --git a/panda/src/pgraph/nodePathComponent.cxx b/panda/src/pgraph/nodePathComponent.cxx index 4dbacc4539..a9f8a38788 100644 --- a/panda/src/pgraph/nodePathComponent.cxx +++ b/panda/src/pgraph/nodePathComponent.cxx @@ -92,17 +92,6 @@ get_length(int pipeline_stage, Thread *current_thread) const { return cdata->_length; } -/** - * Returns the next component in the path. - */ -NodePathComponent *NodePathComponent:: -get_next(int pipeline_stage, Thread *current_thread) const { - CDStageReader cdata(_cycler, pipeline_stage, current_thread); - NodePathComponent *next = cdata->_next; - - return next; -} - /** * Checks that the length indicated by the component is one more than the * length of its predecessor. If this is broken, fixes it and returns true diff --git a/panda/src/pgraph/nodePathComponent.h b/panda/src/pgraph/nodePathComponent.h index fbe4625c14..b0ed69a389 100644 --- a/panda/src/pgraph/nodePathComponent.h +++ b/panda/src/pgraph/nodePathComponent.h @@ -39,7 +39,7 @@ * graph, and the NodePathComponents are stored in the nodes themselves to * allow the nodes to keep these up to date as the scene graph is manipulated. */ -class EXPCL_PANDA_PGRAPH NodePathComponent : public ReferenceCount { +class EXPCL_PANDA_PGRAPH NodePathComponent FINAL : public ReferenceCount { private: NodePathComponent(PandaNode *node, NodePathComponent *next, int pipeline_stage, Thread *current_thread); @@ -55,7 +55,7 @@ public: int get_key() const; bool is_top_node(int pipeline_stage, Thread *current_thread) const; - NodePathComponent *get_next(int pipeline_stage, Thread *current_thread) const; + INLINE NodePathComponent *get_next(int pipeline_stage, Thread *current_thread) const; int get_length(int pipeline_stage, Thread *current_thread) const; bool fix_length(int pipeline_stage, Thread *current_thread); @@ -125,6 +125,12 @@ private: friend class NodePath; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const NodePathComponent &comp); #include "nodePathComponent.I" diff --git a/panda/src/pgraph/nodePath_ext.cxx b/panda/src/pgraph/nodePath_ext.cxx index 60cbe19a1c..1d1449b423 100644 --- a/panda/src/pgraph/nodePath_ext.cxx +++ b/panda/src/pgraph/nodePath_ext.cxx @@ -278,7 +278,7 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { } CPT_InternalName name(string(buffer, length)); - ShaderInput *input = nullptr; + ShaderInput input(nullptr, 0); if (PyTuple_CheckExact(value)) { // A tuple is interpreted as a vector. @@ -300,13 +300,13 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { for (Py_ssize_t i = 0; i < size; ++i) { vec[i] = (PN_stdfloat)PyFloat_AsDouble(PyTuple_GET_ITEM(value, i)); } - input = new ShaderInput(name, vec); + input = ShaderInput(move(name), vec); } else { LVecBase4i vec(0); for (Py_ssize_t i = 0; i < size; ++i) { vec[i] = (int)PyLong_AsLong(PyTuple_GET_ITEM(value, i)); } - input = new ShaderInput(name, vec); + input = ShaderInput(move(name), vec); } } else if (DtoolCanThisBeAPandaInstance(value)) { @@ -314,91 +314,91 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { void *ptr; if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_Texture))) { - input = new ShaderInput(name, (Texture *)ptr); + input = ShaderInput(move(name), (Texture *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_NodePath))) { - input = new ShaderInput(name, *(const NodePath *)ptr); + input = ShaderInput(move(name), *(const NodePath *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_float))) { - input = new ShaderInput(name, *(const PTA_float *)ptr); + input = ShaderInput(move(name), *(const PTA_float *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_double))) { - input = new ShaderInput(name, *(const PTA_double *)ptr); + input = ShaderInput(move(name), *(const PTA_double *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_int))) { - input = new ShaderInput(name, *(const PTA_int *)ptr); + input = ShaderInput(move(name), *(const PTA_int *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4f))) { - input = new ShaderInput(name, *(const PTA_LVecBase4f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3f))) { - input = new ShaderInput(name, *(const PTA_LVecBase3f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2f))) { - input = new ShaderInput(name, *(const PTA_LVecBase2f *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4f))) { - input = new ShaderInput(name, *(const PTA_LMatrix4f *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3f))) { - input = new ShaderInput(name, *(const PTA_LMatrix3f *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4d))) { - input = new ShaderInput(name, *(const PTA_LVecBase4d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3d))) { - input = new ShaderInput(name, *(const PTA_LVecBase3d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2d))) { - input = new ShaderInput(name, *(const PTA_LVecBase2d *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4d))) { - input = new ShaderInput(name, *(const PTA_LMatrix4d *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3d))) { - input = new ShaderInput(name, *(const PTA_LMatrix3d *)ptr); + input = ShaderInput(move(name), *(const PTA_LMatrix3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4i))) { - input = new ShaderInput(name, *(const PTA_LVecBase4i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase4i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3i))) { - input = new ShaderInput(name, *(const PTA_LVecBase3i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase3i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2i))) { - input = new ShaderInput(name, *(const PTA_LVecBase2i *)ptr); + input = ShaderInput(move(name), *(const PTA_LVecBase2i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4f))) { - input = new ShaderInput(name, *(const LVecBase4f *)ptr); + input = ShaderInput(move(name), *(const LVecBase4f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3f))) { - input = new ShaderInput(name, *(const LVecBase3f *)ptr); + input = ShaderInput(move(name), *(const LVecBase3f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2f))) { - input = new ShaderInput(name, *(const LVecBase2f *)ptr); + input = ShaderInput(move(name), *(const LVecBase2f *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4d))) { - input = new ShaderInput(name, *(const LVecBase4d *)ptr); + input = ShaderInput(move(name), *(const LVecBase4d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3d))) { - input = new ShaderInput(name, *(const LVecBase3d *)ptr); + input = ShaderInput(move(name), *(const LVecBase3d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2d))) { - input = new ShaderInput(name, *(const LVecBase2d *)ptr); + input = ShaderInput(move(name), *(const LVecBase2d *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4i))) { - input = new ShaderInput(name, *(const LVecBase4i *)ptr); + input = ShaderInput(move(name), *(const LVecBase4i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3i))) { - input = new ShaderInput(name, *(const LVecBase3i *)ptr); + input = ShaderInput(move(name), *(const LVecBase3i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2i))) { - input = new ShaderInput(name, *(const LVecBase2i *)ptr); + input = ShaderInput(move(name), *(const LVecBase2i *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ShaderBuffer))) { - input = new ShaderInput(name, (ShaderBuffer *)ptr); + input = ShaderInput(move(name), (ShaderBuffer *)ptr); } else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ParamValueBase))) { - input = new ShaderInput(name, (ParamValueBase *)ptr); + input = ShaderInput(move(name), (ParamValueBase *)ptr); } else { Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs"); @@ -406,22 +406,22 @@ set_shader_inputs(PyObject *args, PyObject *kwargs) { } } else if (PyFloat_Check(value)) { - input = new ShaderInput(name, LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0)); #if PY_MAJOR_VERSION < 3 } else if (PyInt_Check(value)) { - input = new ShaderInput(name, LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0)); #endif } else if (PyLong_Check(value)) { - input = new ShaderInput(name, LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0)); + input = ShaderInput(move(name), LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0)); } else { Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs"); return; } - attrib->_inputs[move(name)] = input; + attrib->_inputs[input.get_name()] = move(input); } node->set_attrib(ShaderAttrib::return_new(attrib)); diff --git a/panda/src/pgraph/pandaNode.I b/panda/src/pgraph/pandaNode.I index 747f322a36..ecff479445 100644 --- a/panda/src/pgraph/pandaNode.I +++ b/panda/src/pgraph/pandaNode.I @@ -1482,7 +1482,7 @@ get_net_collide_mask() const { * Returns a ClipPlaneAttrib which represents the union of all of the clip * planes that have been turned *off* at this level and below. */ -INLINE CPT(RenderAttrib) PandaNodePipelineReader:: +INLINE const RenderAttrib *PandaNodePipelineReader:: get_off_clip_planes() const { nassertr(_cdata->_last_update == _cdata->_next_update, _cdata->_off_clip_planes); return _cdata->_off_clip_planes; @@ -1493,7 +1493,7 @@ get_off_clip_planes() const { * contains the user bounding volume, the internal bounding volume, and all of * the children's bounding volumes. */ -INLINE CPT(BoundingVolume) PandaNodePipelineReader:: +INLINE const BoundingVolume *PandaNodePipelineReader:: get_bounds() const { nassertr(_cdata->_last_bounds_update == _cdata->_next_update, _cdata->_external_bounds); return _cdata->_external_bounds; diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index e9f3204ccd..b55f160588 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -827,6 +827,7 @@ private: friend class PandaNodePipelineReader; friend class EggLoader; friend class Extension; + friend class CullTraverserData; }; /** @@ -877,8 +878,8 @@ public: INLINE bool has_tag(const string &key) const; INLINE CollideMask get_net_collide_mask() const; - INLINE CPT(RenderAttrib) get_off_clip_planes() const; - INLINE CPT(BoundingVolume) get_bounds() const; + INLINE const RenderAttrib *get_off_clip_planes() const; + INLINE const BoundingVolume *get_bounds() const; INLINE int get_nested_vertices() const; INLINE bool is_final() const; INLINE int get_fancy_bits() const; @@ -906,6 +907,12 @@ private: }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const PandaNode &node) { node.output(out); return out; diff --git a/panda/src/pgraph/polylightEffect.cxx b/panda/src/pgraph/polylightEffect.cxx index f2c49b7f91..acbd41b18f 100644 --- a/panda/src/pgraph/polylightEffect.cxx +++ b/panda/src/pgraph/polylightEffect.cxx @@ -136,9 +136,9 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran if (light->is_enabled()) { // if enabled get all the properties PN_stdfloat light_radius = light->get_radius(); // Calculate the distance of the node from the light dist = - // light_iter->second->get_distance(data->_node_path.get_node_path()); + // light_iter->second->get_distance(data->get_node_path()); const NodePath lightnp = *light_iter; - LPoint3 relative_point = data->_node_path.get_node_path().get_relative_point(lightnp, light->get_pos()); + LPoint3 relative_point = data->get_node_path().get_relative_point(lightnp, light->get_pos()); if (_effect_center[2]) { dist = (relative_point - _effect_center).length(); // this counts height difference @@ -155,7 +155,7 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran // LPoint3 camera_position = camera.get_relative_point(lightnp, // light->get_pos()); LPoint3 camera_position = lightnp.get_relative_point(camera, LPoint3(0,0,0)); - LPoint3 avatar_position = lightnp.get_relative_point(data->_node_path.get_node_path(), LPoint3(0,0,0)); + LPoint3 avatar_position = lightnp.get_relative_point(data->get_node_path(), LPoint3(0,0,0)); LVector3 light_camera = camera_position - light_position; LVector3 light_avatar = avatar_position - light_position; light_camera.normalize(); @@ -263,7 +263,7 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran if (num_lights) { // was_under_polylight = true; - // data->_node_path.get_node_path().set_color_scale_off(); + // data->get_node_path().set_color_scale_off(); if (polylight_info) pgraph_cat.debug() << "num lights = " << num_lights << endl; @@ -320,8 +320,8 @@ do_poly_light(const SceneSetup *scene, const CullTraverserData *data, const Tran else { if (was_under_polylight) { // under no polylight influence...so clear the color scale - // data->_node_path.get_node_path().clear_color_scale(); - // data->_node_path.get_node_path().set_color_scale(scene_color); + // data->get_node_path().clear_color_scale(); + // data->get_node_path().set_color_scale(scene_color); was_under_polylight = false; } } diff --git a/panda/src/pgraph/portalClipper.h b/panda/src/pgraph/portalClipper.h index a1c8f5b179..b6cee9e3a7 100644 --- a/panda/src/pgraph/portalClipper.h +++ b/panda/src/pgraph/portalClipper.h @@ -119,7 +119,7 @@ private: LPoint2 _reduced_viewport_max; CPT(RenderState) _clip_state; // each portal node needs to know the clip state of its "parent" portal Node - PortalNode *_portal_node; // current working portal for dereference ease + const PortalNode *_portal_node; // current working portal for dereference ease // int _num_vert; LVertex _coords[4]; diff --git a/panda/src/pgraph/portalNode.cxx b/panda/src/pgraph/portalNode.cxx index d70eacd17e..dccfef23c4 100644 --- a/panda/src/pgraph/portalNode.cxx +++ b/panda/src/pgraph/portalNode.cxx @@ -213,7 +213,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max); PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum(); - if (portal_viewer->prepare_portal(data._node_path.get_node_path())) { + if (portal_viewer->prepare_portal(data.get_node_path())) { if ((reduced_frustum = portal_viewer->get_reduced_frustum())) { // remember current clip state, we might change it CPT(RenderState) old_clip_state = portal_viewer->get_clip_state(); @@ -241,7 +241,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { // camera space to this portal node's space (because the clip planes // are attached to this node) PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy()); - CPT(TransformState) temp_frustum_transform = data._node_path.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); + CPT(TransformState) temp_frustum_transform = data.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform()); portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl; portal_cat.spam() << "frustum before transform " << *temp_bh << endl; diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 334898a510..3a7b511381 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -22,7 +22,7 @@ LightReMutex *RenderAttrib::_attribs_lock = NULL; RenderAttrib::Attribs *RenderAttrib::_attribs = NULL; TypeHandle RenderAttrib::_type_handle; -int RenderAttrib::_garbage_index = 0; +size_t RenderAttrib::_garbage_index = 0; PStatCollector RenderAttrib::_garbage_collect_pcollector("*:State Cache:Garbage Collect"); @@ -195,8 +195,8 @@ list_attribs(ostream &out) { LightReMutexHolder holder(*_attribs_lock); out << _attribs->get_num_entries() << " attribs:\n"; - int size = _attribs->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _attribs->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_attribs->has_element(si)) { continue; } @@ -219,7 +219,9 @@ garbage_collect() { PStatTimer timer(_garbage_collect_pcollector); int orig_size = _attribs->get_num_entries(); +#ifdef _DEBUG nassertr(_attribs->validate(), 0); +#endif // How many elements to process this pass? int size = _attribs->get_size(); @@ -230,11 +232,9 @@ garbage_collect() { num_this_pass = min(num_this_pass, size); int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; do { if (_attribs->has_element(si)) { - ++num_elements; RenderAttrib *attrib = (RenderAttrib *)_attribs->get_key(si); if (attrib->get_ref_count() == 1) { // This attrib has recently been unreffed to 1 (the one we added when @@ -250,9 +250,12 @@ garbage_collect() { si = (si + 1) % size; } while (si != stop_at_element); _garbage_index = si; - nassertr(_attribs->validate(), 0); - int new_size = _attribs->get_num_entries(); +#ifdef _DEBUG + nassertr(_attribs->validate(), 0); +#endif + + size_t new_size = _attribs->get_num_entries(); return orig_size - new_size; } @@ -272,8 +275,8 @@ validate_attribs() { pgraph_cat.error() << "RenderAttrib::_attribs cache is invalid!\n"; - int size = _attribs->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _attribs->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_attribs->has_element(si)) { continue; } @@ -285,14 +288,14 @@ validate_attribs() { return false; } - int size = _attribs->get_size(); - int si = 0; + size_t size = _attribs->get_size(); + size_t si = 0; while (si < size && !_attribs->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_attribs->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_attribs->has_element(snext)) { ++snext; diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index 12dd33b720..9d6ed83a1a 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -196,7 +196,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static PStatCollector _garbage_collect_pcollector; diff --git a/panda/src/pgraph/renderEffect.cxx b/panda/src/pgraph/renderEffect.cxx index ceada3a109..09572cc445 100644 --- a/panda/src/pgraph/renderEffect.cxx +++ b/panda/src/pgraph/renderEffect.cxx @@ -160,7 +160,7 @@ has_adjust_transform() const { */ void RenderEffect:: adjust_transform(CPT(TransformState) &, CPT(TransformState) &, - PandaNode *) const { + const PandaNode *) const { } /** diff --git a/panda/src/pgraph/renderEffect.h b/panda/src/pgraph/renderEffect.h index f8a55de869..d739f5cee7 100644 --- a/panda/src/pgraph/renderEffect.h +++ b/panda/src/pgraph/renderEffect.h @@ -68,7 +68,7 @@ public: virtual bool has_adjust_transform() const; virtual void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; PUBLISHED: INLINE int compare_to(const RenderEffect &other) const; diff --git a/panda/src/pgraph/renderEffects.cxx b/panda/src/pgraph/renderEffects.cxx index 18c7565a3f..639f11be9b 100644 --- a/panda/src/pgraph/renderEffects.cxx +++ b/panda/src/pgraph/renderEffects.cxx @@ -492,7 +492,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data, void RenderEffects:: adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const { + const PandaNode *node) const { Effects::const_iterator ei; for (ei = _effects.begin(); ei != _effects.end(); ++ei) { (*ei)._effect->adjust_transform(net_transform, node_transform, node); diff --git a/panda/src/pgraph/renderEffects.h b/panda/src/pgraph/renderEffects.h index e1ece7d2b3..6ccf7eb05f 100644 --- a/panda/src/pgraph/renderEffects.h +++ b/panda/src/pgraph/renderEffects.h @@ -102,7 +102,7 @@ public: INLINE bool has_adjust_transform() const; void adjust_transform(CPT(TransformState) &net_transform, CPT(TransformState) &node_transform, - PandaNode *node) const; + const PandaNode *node) const; static void init_states(); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index c6d0520ec4..75b6f1070a 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -522,7 +522,8 @@ INLINE void RenderState:: check_hash() const { // This pretends to be a const function, even though it's not, because it // only updates a transparent cache value. - if ((_flags & F_hash_known) == 0) { + if ((_flags & F_hash_known) != 0) { + } else { ((RenderState *)this)->calc_hash(); } } diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index de3a58b2ba..e92f284cc1 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -40,7 +40,7 @@ LightReMutex *RenderState::_states_lock = NULL; RenderState::States *RenderState::_states = NULL; const RenderState *RenderState::_empty_state = NULL; UpdateSeq RenderState::_last_cycle_detect; -int RenderState::_garbage_index = 0; +size_t RenderState::_garbage_index = 0; PStatCollector RenderState::_cache_update_pcollector("*:State Cache:Update"); PStatCollector RenderState::_garbage_collect_pcollector("*:State Cache:Garbage Collect"); @@ -75,6 +75,10 @@ RenderState() : _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -97,6 +101,10 @@ RenderState(const RenderState ©) : _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -617,7 +625,7 @@ adjust_all_priorities(int adjustment) const { */ bool RenderState:: unref() const { - if (!state_cache || garbage_collect_states) { + if (garbage_collect_states || !state_cache) { // If we're not using the cache at all, or if we're relying on garbage // collection, just allow the pointer to unref normally. return ReferenceCount::unref(); @@ -774,8 +782,8 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -871,8 +879,8 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -938,27 +946,30 @@ garbage_collect() { if (_states == (States *)NULL || !garbage_collect_states) { return num_attribs; } + + bool break_and_uniquify = (auto_break_cycles && uniquify_transforms); + LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); int orig_size = _states->get_num_entries(); // How many elements to process this pass? - int size = _states->get_size(); - int num_this_pass = int(size * garbage_collect_states_rate); - if (num_this_pass <= 0) { + size_t size = _states->get_size(); + size_t num_this_pass = int((int)size * garbage_collect_states_rate); + if (size <= 0 || num_this_pass <= 0) { return num_attribs; } - num_this_pass = min(num_this_pass, size); - int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; + + num_this_pass = min(num_this_pass, size); + size_t stop_at_element = (si + num_this_pass) % (size - 1); + do { if (_states->has_element(si)) { - ++num_elements; RenderState *state = (RenderState *)_states->get_key(si); - if (auto_break_cycles && uniquify_states) { + if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { // If we have removed all the references to this state not in the @@ -982,10 +993,13 @@ garbage_collect() { } } - si = (si + 1) % size; + si = (si + 1) & (size - 1); } while (si != stop_at_element); _garbage_index = si; + +#ifdef _DEBUG nassertr(_states->validate(), 0); +#endif int new_size = _states->get_num_entries(); return orig_size - new_size + num_attribs; @@ -999,8 +1013,8 @@ void RenderState:: clear_munger_cache() { LightReMutexHolder holder(*_states_lock); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1034,8 +1048,8 @@ list_cycles(ostream &out) { VisitedStates visited; CompositionCycleDesc cycle_desc; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1113,8 +1127,8 @@ list_states(ostream &out) { out << _states->get_num_entries() << " states:\n"; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1148,14 +1162,14 @@ validate_states() { return false; } - int size = _states->get_size(); - int si = 0; + size_t size = _states->get_size(); + size_t si = 0; while (si < size && !_states->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_states->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_states->has_element(snext)) { ++snext; diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index c15efe68ad..f91f02cd3e 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -278,7 +278,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static PStatCollector _cache_update_pcollector; static PStatCollector _garbage_collect_pcollector; @@ -368,6 +368,12 @@ private: friend class Extension; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const RenderState &state) { state.output(out); return out; diff --git a/panda/src/pgraph/shaderAttrib.I b/panda/src/pgraph/shaderAttrib.I index f3667b27d9..6513604ae9 100644 --- a/panda/src/pgraph/shaderAttrib.I +++ b/panda/src/pgraph/shaderAttrib.I @@ -110,7 +110,7 @@ has_shader_input(CPT_InternalName id) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -118,7 +118,7 @@ set_shader_input(CPT_InternalName id, const PTA_float &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -126,7 +126,7 @@ set_shader_input(CPT_InternalName id, const PTA_double &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -134,7 +134,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase4 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } @@ -143,7 +143,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase3 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -151,7 +151,7 @@ set_shader_input(CPT_InternalName id, const PTA_LVecBase2 &v, int priority) cons */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -159,7 +159,7 @@ set_shader_input(CPT_InternalName id, const LVecBase4 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -167,7 +167,7 @@ set_shader_input(CPT_InternalName id, const LVecBase3 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -175,7 +175,7 @@ set_shader_input(CPT_InternalName id, const LVecBase2 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -183,7 +183,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix4 &v, int priority) const */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -191,7 +191,7 @@ set_shader_input(CPT_InternalName id, const PTA_LMatrix3 &v, int priority) const */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -199,7 +199,7 @@ set_shader_input(CPT_InternalName id, const LMatrix4 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), v, priority)); + return set_shader_input(ShaderInput(move(id), v, priority)); } /** @@ -207,7 +207,7 @@ set_shader_input(CPT_InternalName id, const LMatrix3 &v, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, Texture *tex, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), tex, priority)); + return set_shader_input(ShaderInput(move(id), tex, priority)); } /** @@ -215,7 +215,7 @@ set_shader_input(CPT_InternalName id, Texture *tex, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, const NodePath &np, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), np, priority)); + return set_shader_input(ShaderInput(move(id), np, priority)); } /** @@ -223,7 +223,7 @@ set_shader_input(CPT_InternalName id, const NodePath &np, int priority) const { */ INLINE CPT(RenderAttrib) ShaderAttrib:: set_shader_input(CPT_InternalName id, double n1, double n2, double n3, double n4, int priority) const { - return set_shader_input(new ShaderInput(MOVE(id), LVecBase4((PN_stdfloat)n1, (PN_stdfloat)n2, (PN_stdfloat)n3, (PN_stdfloat)n4), priority)); + return set_shader_input(ShaderInput(move(id), LVecBase4((PN_stdfloat)n1, (PN_stdfloat)n2, (PN_stdfloat)n3, (PN_stdfloat)n4), priority)); } INLINE bool ShaderAttrib:: diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 2e6ac7cd77..6435ceed5d 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -193,13 +193,13 @@ clear_flag(int flag) const { * */ CPT(RenderAttrib) ShaderAttrib:: -set_shader_input(const ShaderInput *input) const { +set_shader_input(ShaderInput input) const { ShaderAttrib *result = new ShaderAttrib(*this); - Inputs::iterator i = result->_inputs.find(input->get_name()); + Inputs::iterator i = result->_inputs.find(input.get_name()); if (i == result->_inputs.end()) { - result->_inputs.insert(Inputs::value_type(input->get_name(), input)); + result->_inputs.insert(Inputs::value_type(input.get_name(), move(input))); } else { - i->second = input; + i->second = move(input); } return return_new(result); } @@ -248,13 +248,13 @@ clear_all_shader_inputs() const { * Returns the ShaderInput of the given name. If no such name is found, this * function does not return NULL --- it returns the "blank" ShaderInput. */ -const ShaderInput *ShaderAttrib:: +const ShaderInput &ShaderAttrib:: get_shader_input(const InternalName *id) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - return ShaderInput::get_blank(); - } else { + if (i != _inputs.end()) { return (*i).second; + } else { + return ShaderInput::get_blank(); } } @@ -262,7 +262,7 @@ get_shader_input(const InternalName *id) const { * Returns the ShaderInput of the given name. If no such name is found, this * function does not return NULL --- it returns the "blank" ShaderInput. */ -const ShaderInput *ShaderAttrib:: +const ShaderInput &ShaderAttrib:: get_shader_input(const string &id) const { return get_shader_input(InternalName::make(id)); } @@ -275,20 +275,21 @@ const NodePath &ShaderAttrib:: get_shader_input_nodepath(const InternalName *id) const { static NodePath resfail; Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return resfail; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_nodepath) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + if (p.get_value_type() == ShaderInput::M_nodepath) { + return ((const ParamNodePath *)p.get_value())->get_value(); + } else { ostringstream strm; strm << "Shader input " << id->get_name() << " is not a nodepath.\n"; nassert_raise(strm.str()); return resfail; } - return p->get_nodepath(); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return resfail; } // Satisfy compiler. @@ -303,19 +304,14 @@ LVecBase4 ShaderAttrib:: get_shader_input_vector(InternalName *id) const { static LVecBase4 resfail(0,0,0,0); Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return resfail; - } else { - const ShaderInput *p = (*i).second; + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_vector) { - return p->get_vector(); + if (p.get_value_type() == ShaderInput::M_vector) { + return p.get_vector(); - } else if (p->get_value_type() == ShaderInput::M_numeric && p->get_ptr()._size <= 4) { - const Shader::ShaderPtrData &ptr = p->get_ptr(); + } else if (p.get_value_type() == ShaderInput::M_numeric && p.get_ptr()._size <= 4) { + const Shader::ShaderPtrData &ptr = p.get_ptr(); switch (ptr._type) { case Shader::SPT_float: @@ -339,19 +335,23 @@ get_shader_input_vector(InternalName *id) const { } } - } else if (p->get_value_type() == ShaderInput::M_param) { + } else if (p.get_value_type() == ShaderInput::M_param) { // Temporary solution until the new param system - ParamValueBase *param = p->get_param(); + TypedWritableReferenceCount *param = p.get_value(); if (param != NULL && param->is_of_type(ParamVecBase4::get_class_type())) { - return ((const ParamVecBase4 *) param)->get_value(); + return ((const ParamVecBase4 *)param)->get_value(); } } ostringstream strm; strm << "Shader input " << id->get_name() << " is not a vector.\n"; nassert_raise(strm.str()); - return resfail; + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); } + return resfail; } /** @@ -361,21 +361,21 @@ get_shader_input_vector(InternalName *id) const { const Shader::ShaderPtrData *ShaderAttrib:: get_shader_input_ptr(const InternalName *id) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return NULL; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_numeric && - p->get_value_type() != ShaderInput::M_vector) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + if (p.get_value_type() != ShaderInput::M_numeric && + p.get_value_type() != ShaderInput::M_vector) { ostringstream strm; strm << "Shader input " << id->get_name() << " is not a PTA(float/double) type.\n"; nassert_raise(strm.str()); return NULL; } - return &(p->get_ptr()); + return &(p.get_ptr()); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return NULL; } } @@ -389,24 +389,39 @@ get_shader_input_ptr(const InternalName *id) const { Texture *ShaderAttrib:: get_shader_input_texture(const InternalName *id, SamplerState *sampler) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return NULL; - } else { - const ShaderInput *p = (*i).second; - if (p->get_value_type() != ShaderInput::M_texture && - p->get_value_type() != ShaderInput::M_texture_sampler) { + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; + switch (p.get_value_type()) { + case ShaderInput::M_texture: + { + Texture *tex = (Texture *)p.get_value(); + if (sampler) { + *sampler = tex->get_default_sampler(); + } + return tex; + } + + case ShaderInput::M_texture_sampler: + { + const ParamTextureSampler *param = (const ParamTextureSampler *)p.get_value(); + if (sampler) { + *sampler = param->get_sampler(); + } + return param->get_texture(); + } + + default: ostringstream strm; strm << "Shader input " << id->get_name() << " is not a texture.\n"; nassert_raise(strm.str()); return NULL; } - if (sampler != NULL) { - *sampler = p->get_sampler(); - } - return p->get_texture(); + + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return NULL; } } @@ -417,22 +432,17 @@ get_shader_input_texture(const InternalName *id, SamplerState *sampler) const { const LMatrix4 &ShaderAttrib:: get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { Inputs::const_iterator i = _inputs.find(id); - if (i == _inputs.end()) { - ostringstream strm; - strm << "Shader input " << id->get_name() << " is not present.\n"; - nassert_raise(strm.str()); - return LMatrix4::ident_mat(); - } else { - const ShaderInput *p = (*i).second; + if (i != _inputs.end()) { + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_nodepath) { - const NodePath &np = p->get_nodepath(); + if (p.get_value_type() == ShaderInput::M_nodepath) { + const NodePath &np = p.get_nodepath(); nassertr(!np.is_empty(), LMatrix4::ident_mat()); return np.get_transform()->get_mat(); - } else if (p->get_value_type() == ShaderInput::M_numeric && - p->get_ptr()._size >= 16 && (p->get_ptr()._size & 15) == 0) { - const Shader::ShaderPtrData &ptr = p->get_ptr(); + } else if (p.get_value_type() == ShaderInput::M_numeric && + p.get_ptr()._size >= 16 && (p.get_ptr()._size & 15) == 0) { + const Shader::ShaderPtrData &ptr = p.get_ptr(); switch (ptr._type) { case Shader::SPT_float: { @@ -460,6 +470,11 @@ get_shader_input_matrix(const InternalName *id, LMatrix4 &matrix) const { strm << "Shader input " << id->get_name() << " is not a NodePath, LMatrix4 or PTA_LMatrix4.\n"; nassert_raise(strm.str()); return LMatrix4::ident_mat(); + } else { + ostringstream strm; + strm << "Shader input " << id->get_name() << " is not present.\n"; + nassert_raise(strm.str()); + return LMatrix4::ident_mat(); } } @@ -476,11 +491,11 @@ get_shader_input_buffer(const InternalName *id) const { nassert_raise(strm.str()); return NULL; } else { - const ShaderInput *p = (*i).second; + const ShaderInput &p = (*i).second; - if (p->get_value_type() == ShaderInput::M_buffer) { + if (p.get_value_type() == ShaderInput::M_buffer) { ShaderBuffer *value; - DCAST_INTO_R(value, p->_value, NULL); + DCAST_INTO_R(value, p._value, NULL); return value; } @@ -615,8 +630,7 @@ get_hash_impl() const { Inputs::const_iterator ii; for (ii = _inputs.begin(); ii != _inputs.end(); ++ii) { - hash = pointer_hash::add_hash(hash, (*ii).first); - hash = pointer_hash::add_hash(hash, (*ii).second); + hash = (*ii).second.add_hash(hash); } return hash; @@ -649,13 +663,13 @@ compose_impl(const RenderAttrib *other) const { Inputs::const_iterator iover; for (iover=over->_inputs.begin(); iover!=over->_inputs.end(); ++iover) { const InternalName *id = (*iover).first; - const ShaderInput *dover = (*iover).second; + const ShaderInput &dover = (*iover).second; Inputs::iterator iattr = attr->_inputs.find(id); if (iattr == attr->_inputs.end()) { attr->_inputs.insert(Inputs::value_type(id,dover)); } else { - const ShaderInput *dattr = (*iattr).second; - if (dattr->get_priority() <= dover->get_priority()) { + const ShaderInput &dattr = (*iattr).second; + if (dattr.get_priority() <= dover.get_priority()) { iattr->second = iover->second; } } diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index ebdcca499c..719106c0b6 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -71,7 +71,7 @@ PUBLISHED: CPT(RenderAttrib) clear_shader() const; // Shader Inputs - CPT(RenderAttrib) set_shader_input(const ShaderInput *inp) const; + CPT(RenderAttrib) set_shader_input(ShaderInput input) const; INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, Texture *tex, int priority=0) const; INLINE CPT(RenderAttrib) set_shader_input(CPT_InternalName id, const NodePath &np, int priority=0) const; @@ -104,8 +104,8 @@ PUBLISHED: INLINE bool has_shader_input(CPT_InternalName id) const; const Shader *get_shader() const; - const ShaderInput *get_shader_input(const InternalName *id) const; - const ShaderInput *get_shader_input(const string &id) const; + const ShaderInput &get_shader_input(const InternalName *id) const; + const ShaderInput &get_shader_input(const string &id) const; const NodePath &get_shader_input_nodepath(const InternalName *id) const; LVecBase4 get_shader_input_vector(InternalName *id) const; @@ -145,7 +145,9 @@ private: bool _auto_ramp_on; bool _auto_shadow_on; - typedef pmap Inputs; + // We don't keep a reference to the InternalName, since this is also already + // stored on the ShaderInput object. + typedef pmap Inputs; Inputs _inputs; friend class Extension; diff --git a/panda/src/pgraph/shaderInput.I b/panda/src/pgraph/shaderInput.I index 7344717e47..30d1bab97a 100644 --- a/panda/src/pgraph/shaderInput.I +++ b/panda/src/pgraph/shaderInput.I @@ -13,13 +13,6 @@ * @date 2010-04-06 */ -/** - * - */ -INLINE ShaderInput:: -~ShaderInput() { -} - /** * */ @@ -424,6 +417,81 @@ ShaderInput(CPT_InternalName name, const LVecBase2i &vec, int priority) : { } +/** + * + */ +INLINE bool ShaderInput:: +operator == (const ShaderInput &other) const { + if (_type != other._type || _name != other._name || _priority != other._priority) { + return false; + } + switch (_type) { + case M_invalid: + return true; + + case M_vector: + return _stored_vector == other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr == other._stored_ptr._ptr; + + default: + return _value == other._value; + } +} + +/** + * + */ +INLINE bool ShaderInput:: +operator != (const ShaderInput &other) const { + if (_type != other._type || _name != other._name || _priority != other._priority) { + return true; + } + switch (_type) { + case M_invalid: + return false; + + case M_vector: + return _stored_vector != other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr != other._stored_ptr._ptr; + + default: + return _value != other._value; + } +} + +/** + * + */ +INLINE bool ShaderInput:: +operator < (const ShaderInput &other) const { + if (_type != other._type) { + return (_type < other._type); + } + if (_name != other._name) { + return (_name < other._name); + } + if (_priority != other._priority) { + return (_priority < other._priority); + } + switch (_type) { + case M_invalid: + return false; + + case M_vector: + return _stored_vector < other._stored_vector; + + case M_numeric: + return _stored_ptr._ptr < other._stored_ptr._ptr; + + default: + return _value < other._value; + } +} + /** * */ @@ -471,3 +539,11 @@ INLINE ParamValueBase *ShaderInput:: get_param() const { return DCAST(ParamValueBase, _value); } + +/** + * + */ +INLINE TypedWritableReferenceCount *ShaderInput:: +get_value() const { + return _value.p(); +} diff --git a/panda/src/pgraph/shaderInput.cxx b/panda/src/pgraph/shaderInput.cxx index 3ee38ef70a..44fb91cf23 100644 --- a/panda/src/pgraph/shaderInput.cxx +++ b/panda/src/pgraph/shaderInput.cxx @@ -15,18 +15,13 @@ #include "paramNodePath.h" #include "paramTexture.h" -TypeHandle ShaderInput::_type_handle; - /** * Returns a static ShaderInput object with name NULL, priority zero, type * INVALID, and all value-fields cleared. */ -const ShaderInput *ShaderInput:: +const ShaderInput &ShaderInput:: get_blank() { - static CPT(ShaderInput) blank; - if (blank == 0) { - blank = new ShaderInput(NULL, 0); - } + static ShaderInput blank(nullptr, 0); return blank; } @@ -66,6 +61,30 @@ ShaderInput(CPT_InternalName name, Texture *tex, const SamplerState &sampler, in { } +/** + * + */ +size_t ShaderInput:: +add_hash(size_t hash) const { + hash = int_hash::add_hash(hash, _type); + hash = pointer_hash::add_hash(hash, _name); + hash = int_hash::add_hash(hash, _priority); + + switch (_type) { + case M_invalid: + return hash; + + case M_vector: + return _stored_vector.add_hash(hash); + + case M_numeric: + return pointer_hash::add_hash(hash, _stored_ptr._ptr); + + default: + return pointer_hash::add_hash(hash, _value); + } +} + /** * Warning: no error checking is done. This *will* crash if get_value_type() * is not M_nodepath. diff --git a/panda/src/pgraph/shaderInput.h b/panda/src/pgraph/shaderInput.h index c91c790618..ebf630fcaa 100644 --- a/panda/src/pgraph/shaderInput.h +++ b/panda/src/pgraph/shaderInput.h @@ -17,7 +17,6 @@ #define SHADERINPUT_H #include "pandabase.h" -#include "typedWritableReferenceCount.h" #include "pointerTo.h" #include "internalName.h" #include "paramValue.h" @@ -37,10 +36,7 @@ * This is a small container class that can hold any one of the value types * that can be passed as input to a shader. */ -class EXPCL_PANDA_PGRAPH ShaderInput : public TypedWritableReferenceCount { -public: - INLINE ~ShaderInput(); - +class EXPCL_PANDA_PGRAPH ShaderInput { PUBLISHED: // Used when binding texture images. enum AccessFlags { @@ -49,7 +45,7 @@ PUBLISHED: A_layered = 0x04, }; - static const ShaderInput *get_blank(); + static const ShaderInput &get_blank(); INLINE ShaderInput(CPT_InternalName name, int priority=0); INLINE ShaderInput(CPT_InternalName name, Texture *tex, int priority=0); INLINE ShaderInput(CPT_InternalName name, ParamValueBase *param, int priority=0); @@ -102,6 +98,12 @@ PUBLISHED: M_buffer, }; + INLINE bool operator == (const ShaderInput &other) const; + INLINE bool operator != (const ShaderInput &other) const; + INLINE bool operator < (const ShaderInput &other) const; + + size_t add_hash(size_t hash) const; + INLINE const InternalName *get_name() const; INLINE int get_value_type() const; @@ -114,7 +116,10 @@ PUBLISHED: const SamplerState &get_sampler() const; public: + ShaderInput() DEFAULT_CTOR; + INLINE ParamValueBase *get_param() const; + INLINE TypedWritableReferenceCount *get_value() const; static void register_with_read_factory(); @@ -127,26 +132,8 @@ private: int _type; friend class ShaderAttrib; - -public: - static TypeHandle get_class_type() { - return _type_handle; - } - static void init_type() { - TypedWritableReferenceCount::init_type(); - register_type(_type_handle, "ShaderInput", - TypedWritableReferenceCount::get_class_type()); - } - virtual TypeHandle get_type() const { - return get_class_type(); - } - virtual TypeHandle force_init_type() {init_type(); return get_class_type();} - -private: - static TypeHandle _type_handle; }; - #include "shaderInput.I" #endif // SHADERINPUT_H diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 4d1aade0ec..be1ed4a15a 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -29,7 +29,7 @@ TransformState::States *TransformState::_states = NULL; CPT(TransformState) TransformState::_identity_state; CPT(TransformState) TransformState::_invalid_state; UpdateSeq TransformState::_last_cycle_detect; -int TransformState::_garbage_index = 0; +size_t TransformState::_garbage_index = 0; bool TransformState::_uniquify_matrix = true; PStatCollector TransformState::_cache_update_pcollector("*:State Cache:Update"); @@ -62,6 +62,10 @@ TransformState() : _lock("TransformState") { _flags = F_is_identity | F_singular_known | F_is_2d; _inv_mat = (LMatrix4 *)NULL; _cache_stats.add_num_states(1); + +#ifdef DO_MEMORY_USAGE + MemoryUsage::update_type(this, this); +#endif } /** @@ -608,33 +612,74 @@ compose(const TransformState *other) const { return do_compose(other); } - // Is this composition already cached? - CPT(TransformState) result; - { - LightReMutexHolder holder(*_states_lock); - int index = _composition_cache.find(other); - if (index != -1) { - const Composition &comp = _composition_cache.get_data(index); - result = comp._result; - } - if (result != (TransformState *)NULL) { - _cache_stats.inc_hits(); - } - } + LightReMutexHolder holder(*_states_lock); - if (result != (TransformState *)NULL) { - // Success! - return result; + // Is this composition already cached? + int index = _composition_cache.find(other); + if (index != -1) { + const Composition &comp = _composition_cache.get_data(index); + if (comp._result != nullptr) { + // Success! + _cache_stats.inc_hits(); + return comp._result; + } } // Not in the cache. Compute a new result. It's important that we don't // hold the lock while we do this, or we lose the benefit of // parallelization. - result = do_compose(other); + CPT(TransformState) result = do_compose(other); - // It's OK to cast away the constness of this pointer, because the cache is - // a transparent property of the class. - return ((TransformState *)this)->store_compose(other, result); + if (index != -1) { + Composition &comp = _composition_cache.modify_data(index); + // Well, it wasn't cached already, but we already had an entry (probably + // created for the reverse direction), so use the same entry to store + // the new result. + comp._result = result; + + if (result != (const TransformState *)this) { + // See the comments below about the need to up the reference count + // only when the result is not the same as this. + result->cache_ref(); + } + // Here's the cache! + _cache_stats.inc_hits(); + return result; + } + _cache_stats.inc_misses(); + + // We need to make a new cache entry, both in this object and in the other + // object. We make both records so the other TransformState object will + // know to delete the entry from this object when it destructs, and vice- + // versa. + + // The cache entry in this object is the only one that indicates the result; + // the other will be NULL for now. + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(_composition_cache.get_size() == 0); + + _composition_cache[other]._result = result; + + if (other != this) { + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(other->_composition_cache.get_size() == 0); + other->_composition_cache[this]._result = NULL; + } + + if (result != (TransformState *)this) { + // If the result of do_compose() is something other than this, explicitly + // increment the reference count. We have to be sure to decrement it + // again later, when the composition entry is removed from the cache. + result->cache_ref(); + + // (If the result was just this again, we still store the result, but we + // don't increment the reference count, since that would be a self- + // referential leak.) + } + + _cache_stats.maybe_report("TransformState"); + + return result; } /** @@ -676,32 +721,69 @@ invert_compose(const TransformState *other) const { LightReMutexHolder holder(*_states_lock); - CPT(TransformState) result; - { - LightReMutexHolder holder(*_states_lock); - int index = _invert_composition_cache.find(other); - if (index != -1) { - const Composition &comp = _invert_composition_cache.get_data(index); - result = comp._result; - } - if (result != (TransformState *)NULL) { + int index = _invert_composition_cache.find(other); + if (index != -1) { + const Composition &comp = _invert_composition_cache.get_data(index); + if (comp._result != nullptr) { + // Success! _cache_stats.inc_hits(); + return comp._result; } } - if (result != (TransformState *)NULL) { - // Success! - return result; - } - // Not in the cache. Compute a new result. It's important that we don't // hold the lock while we do this, or we lose the benefit of // parallelization. - result = do_invert_compose(other); + CPT(TransformState) result = do_invert_compose(other); - // It's OK to cast away the constness of this pointer, because the cache is - // a transparent property of the class. - return ((TransformState *)this)->store_invert_compose(other, result); + // Is this composition already cached? + if (index != -1) { + Composition &comp = _invert_composition_cache.modify_data(index); + // Well, it wasn't cached already, but we already had an entry (probably + // created for the reverse direction), so use the same entry to store + // the new result. + comp._result = result; + + if (result != (const TransformState *)this) { + // See the comments below about the need to up the reference count + // only when the result is not the same as this. + result->cache_ref(); + } + // Here's the cache! + _cache_stats.inc_hits(); + return result; + } + _cache_stats.inc_misses(); + + // We need to make a new cache entry, both in this object and in the other + // object. We make both records so the other TransformState object will + // know to delete the entry from this object when it destructs, and vice- + // versa. + + // The cache entry in this object is the only one that indicates the result; + // the other will be NULL for now. + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0); + _invert_composition_cache[other]._result = result; + + if (other != this) { + _cache_stats.add_total_size(1); + _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0); + other->_invert_composition_cache[this]._result = NULL; + } + + if (result != (TransformState *)this) { + // If the result of compose() is something other than this, explicitly + // increment the reference count. We have to be sure to decrement it + // again later, when the composition entry is removed from the cache. + result->cache_ref(); + + // (If the result was just this again, we still store the result, but we + // don't increment the reference count, since that would be a self- + // referential leak.) + } + + return result; } /** @@ -712,7 +794,7 @@ invert_compose(const TransformState *other) const { */ bool TransformState:: unref() const { - if (!transform_cache || garbage_collect_states) { + if (garbage_collect_states || !transform_cache) { // If we're not using the cache at all, or if we're relying on garbage // collection, just allow the pointer to unref normally. return ReferenceCount::unref(); @@ -760,8 +842,8 @@ bool TransformState:: validate_composition_cache() const { LightReMutexHolder holder(*_states_lock); - int size = _composition_cache.get_size(); - for (int i = 0; i < size; ++i) { + size_t size = _composition_cache.get_size(); + for (size_t i = 0; i < size; ++i) { if (!_composition_cache.has_element(i)) { continue; } @@ -955,15 +1037,15 @@ get_num_unused_states() { typedef pmap StateCount; StateCount state_count; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } const TransformState *state = _states->get_key(si); - int i; - int cache_size = state->_composition_cache.get_size(); + size_t i; + size_t cache_size = state->_composition_cache.get_size(); for (i = 0; i < cache_size; ++i) { if (state->_composition_cache.has_element(i)) { const TransformState *result = state->_composition_cache.get_data(i)._result; @@ -1053,8 +1135,8 @@ clear_cache() { TempStates temp_states; temp_states.reserve(orig_size); - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1116,27 +1198,30 @@ garbage_collect() { if (_states == (States *)NULL || !garbage_collect_states) { return 0; } + + bool break_and_uniquify = (auto_break_cycles && uniquify_transforms); + LightReMutexHolder holder(*_states_lock); PStatTimer timer(_garbage_collect_pcollector); - int orig_size = _states->get_num_entries(); + size_t orig_size = _states->get_num_entries(); // How many elements to process this pass? - int size = _states->get_size(); - int num_this_pass = int(size * garbage_collect_states_rate); - if (num_this_pass <= 0) { + size_t size = _states->get_size(); + size_t num_this_pass = int(size * garbage_collect_states_rate); + if (size <= 0 || num_this_pass <= 0) { return 0; } - num_this_pass = min(num_this_pass, size); - int stop_at_element = (_garbage_index + num_this_pass) % size; - int num_elements = 0; - int si = _garbage_index; + size_t si = _garbage_index; + + num_this_pass = min(num_this_pass, size); + size_t stop_at_element = (si + num_this_pass) & (size - 1); + do { if (_states->has_element(si)) { - ++num_elements; TransformState *state = (TransformState *)_states->get_key(si); - if (auto_break_cycles && uniquify_transforms) { + if (break_and_uniquify) { if (state->get_cache_ref_count() > 0 && state->get_ref_count() == state->get_cache_ref_count()) { // If we have removed all the references to this state not in the @@ -1160,10 +1245,13 @@ garbage_collect() { } } - si = (si + 1) % size; + si = (si + 1) & (size - 1); } while (si != stop_at_element); _garbage_index = si; + +#ifdef _DEBUG nassertr(_states->validate(), 0); +#endif int new_size = _states->get_num_entries(); return orig_size - new_size; @@ -1193,8 +1281,8 @@ list_cycles(ostream &out) { VisitedStates visited; CompositionCycleDesc cycle_desc; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1272,8 +1360,8 @@ list_states(ostream &out) { out << _states->get_num_entries() << " states:\n"; - int size = _states->get_size(); - for (int si = 0; si < size; ++si) { + size_t size = _states->get_size(); + for (size_t si = 0; si < size; ++si) { if (!_states->has_element(si)) { continue; } @@ -1307,14 +1395,14 @@ validate_states() { return false; } - int size = _states->get_size(); - int si = 0; + size_t size = _states->get_size(); + size_t si = 0; while (si < size && !_states->has_element(si)) { ++si; } nassertr(si < size, false); nassertr(_states->get_key(si)->get_ref_count() >= 0, false); - int snext = si; + size_t snext = si; ++snext; while (snext < size && !_states->has_element(snext)) { ++snext; @@ -1533,150 +1621,6 @@ do_compose(const TransformState *other) const { } } -/** - * Stores the result of a composition in the cache. Returns the stored result - * (it may be a different object than the one passed in, due to another thread - * having computed the composition first). - */ -CPT(TransformState) TransformState:: -store_compose(const TransformState *other, const TransformState *result) { - // Identity should have already been screened. - nassertr(!is_identity(), other); - nassertr(!other->is_identity(), this); - - // So should have validity. - nassertr(!is_invalid(), this); - nassertr(!other->is_invalid(), other); - - LightReMutexHolder holder(*_states_lock); - - // Is this composition already cached? - int index = _composition_cache.find(other); - if (index != -1) { - Composition &comp = _composition_cache.modify_data(index); - if (comp._result == (const TransformState *)NULL) { - // Well, it wasn't cached already, but we already had an entry (probably - // created for the reverse direction), so use the same entry to store - // the new result. - comp._result = result; - - if (result != (const TransformState *)this) { - // See the comments below about the need to up the reference count - // only when the result is not the same as this. - result->cache_ref(); - } - } - // Here's the cache! - _cache_stats.inc_hits(); - return comp._result; - } - _cache_stats.inc_misses(); - - // We need to make a new cache entry, both in this object and in the other - // object. We make both records so the other TransformState object will - // know to delete the entry from this object when it destructs, and vice- - // versa. - - // The cache entry in this object is the only one that indicates the result; - // the other will be NULL for now. - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(_composition_cache.get_size() == 0); - - _composition_cache[other]._result = result; - - if (other != this) { - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(other->_composition_cache.get_size() == 0); - ((TransformState *)other)->_composition_cache[this]._result = NULL; - } - - if (result != (TransformState *)this) { - // If the result of do_compose() is something other than this, explicitly - // increment the reference count. We have to be sure to decrement it - // again later, when the composition entry is removed from the cache. - result->cache_ref(); - - // (If the result was just this again, we still store the result, but we - // don't increment the reference count, since that would be a self- - // referential leak.) - } - - _cache_stats.maybe_report("TransformState"); - - return result; -} - -/** - * Stores the result of a composition in the cache. Returns the stored result - * (it may be a different object than the one passed in, due to another thread - * having computed the composition first). - */ -CPT(TransformState) TransformState:: -store_invert_compose(const TransformState *other, const TransformState *result) { - // Identity should have already been screened. - nassertr(!is_identity(), other); - - // So should have validity. - nassertr(!is_invalid(), this); - nassertr(!other->is_invalid(), other); - - nassertr(other != this, make_identity()); - - LightReMutexHolder holder(*_states_lock); - - // Is this composition already cached? - int index = _invert_composition_cache.find(other); - if (index != -1) { - Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index); - if (comp._result == (const TransformState *)NULL) { - // Well, it wasn't cached already, but we already had an entry (probably - // created for the reverse direction), so use the same entry to store - // the new result. - comp._result = result; - - if (result != (const TransformState *)this) { - // See the comments below about the need to up the reference count - // only when the result is not the same as this. - result->cache_ref(); - } - } - // Here's the cache! - _cache_stats.inc_hits(); - return comp._result; - } - _cache_stats.inc_misses(); - - // We need to make a new cache entry, both in this object and in the other - // object. We make both records so the other TransformState object will - // know to delete the entry from this object when it destructs, and vice- - // versa. - - // The cache entry in this object is the only one that indicates the result; - // the other will be NULL for now. - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(_invert_composition_cache.get_size() == 0); - _invert_composition_cache[other]._result = result; - - if (other != this) { - _cache_stats.add_total_size(1); - _cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0); - ((TransformState *)other)->_invert_composition_cache[this]._result = NULL; - } - - if (result != (TransformState *)this) { - // If the result of compose() is something other than this, explicitly - // increment the reference count. We have to be sure to decrement it - // again later, when the composition entry is removed from the cache. - result->cache_ref(); - - // (If the result was just this again, we still store the result, but we - // don't increment the reference count, since that would be a self- - // referential leak.) - } - - return result; -} - /** * The private implemention of invert_compose(). */ diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 3287fb1853..3fd628be7c 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -234,9 +234,7 @@ private: static CPT(TransformState) return_unique(TransformState *state); CPT(TransformState) do_compose(const TransformState *other) const; - CPT(TransformState) store_compose(const TransformState *other, const TransformState *result); CPT(TransformState) do_invert_compose(const TransformState *other) const; - CPT(TransformState) store_invert_compose(const TransformState *other, const TransformState *result); void detect_and_break_cycles(); static bool r_detect_cycles(const TransformState *start_state, const TransformState *current_state, @@ -288,8 +286,8 @@ private: }; typedef SimpleHashMap CompositionCache; - CompositionCache _composition_cache; - CompositionCache _invert_composition_cache; + mutable CompositionCache _composition_cache; + mutable CompositionCache _invert_composition_cache; // This is used to mark nodes as we visit them to detect cycles. UpdateSeq _cycle_detect; @@ -297,7 +295,7 @@ private: // This keeps track of our current position through the garbage collection // cycle. - static int _garbage_index; + static size_t _garbage_index; static bool _uniquify_matrix; @@ -408,6 +406,12 @@ private: friend class Extension; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + INLINE ostream &operator << (ostream &out, const TransformState &state) { state.output(out); return out; diff --git a/panda/src/pgraphnodes/ambientLight.h b/panda/src/pgraphnodes/ambientLight.h index e52122bdde..23623d7afe 100644 --- a/panda/src/pgraphnodes/ambientLight.h +++ b/panda/src/pgraphnodes/ambientLight.h @@ -33,7 +33,7 @@ protected: public: virtual PandaNode *make_copy() const; virtual void write(ostream &out, int indent_level) const; - virtual bool is_ambient_light() const; + virtual bool is_ambient_light() const FINAL; PUBLISHED: virtual int get_class_priority() const; diff --git a/panda/src/pgraphnodes/fadeLodNode.cxx b/panda/src/pgraphnodes/fadeLodNode.cxx index 5f1f8d15ec..de952457e8 100644 --- a/panda/src/pgraphnodes/fadeLodNode.cxx +++ b/panda/src/pgraphnodes/fadeLodNode.cxx @@ -93,7 +93,7 @@ cull_callback(CullTraverser *trav, CullTraverserData &data) { consider_verify_lods(trav, data); Camera *camera = trav->get_scene()->get_camera_node(); - NodePath this_np = data._node_path.get_node_path(); + NodePath this_np = data.get_node_path(); FadeLODNodeData *ldata = DCAST(FadeLODNodeData, camera->get_aux_scene_data(this_np)); diff --git a/panda/src/pgraphnodes/lightLensNode.I b/panda/src/pgraphnodes/lightLensNode.I index ddb2808e86..8fff5b2533 100644 --- a/panda/src/pgraphnodes/lightLensNode.I +++ b/panda/src/pgraphnodes/lightLensNode.I @@ -15,7 +15,7 @@ * Returns whether this light is configured to cast shadows or not. */ INLINE bool LightLensNode:: -is_shadow_caster() { +is_shadow_caster() const { return _shadow_caster; } diff --git a/panda/src/pgraphnodes/lightLensNode.h b/panda/src/pgraphnodes/lightLensNode.h index d4e0c7385d..0c4b329b16 100644 --- a/panda/src/pgraphnodes/lightLensNode.h +++ b/panda/src/pgraphnodes/lightLensNode.h @@ -34,7 +34,7 @@ PUBLISHED: LightLensNode(const string &name, Lens *lens = new PerspectiveLens()); virtual ~LightLensNode(); - INLINE bool is_shadow_caster(); + INLINE bool is_shadow_caster() const; INLINE void set_shadow_caster(bool caster); INLINE void set_shadow_caster(bool caster, int buffer_xsize, int buffer_ysize, int sort = -10); diff --git a/panda/src/pgraphnodes/lodNode.cxx b/panda/src/pgraphnodes/lodNode.cxx index 5936b0634b..4c2ca87528 100644 --- a/panda/src/pgraphnodes/lodNode.cxx +++ b/panda/src/pgraphnodes/lodNode.cxx @@ -330,7 +330,7 @@ compute_child(CullTraverser *trav, CullTraverserData &data) { * trav->get_scene()->get_camera_node()->get_lod_scale())) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() - << data._node_path << " at distance " << sqrt(dist2) + << data.get_node_path() << " at distance " << sqrt(dist2) << ", selected child " << index << "\n"; } @@ -340,7 +340,7 @@ compute_child(CullTraverser *trav, CullTraverserData &data) { if (pgraph_cat.is_debug()) { pgraph_cat.debug() - << data._node_path << " at distance " << sqrt(dist2) + << data.get_node_path() << " at distance " << sqrt(dist2) << ", no children in range.\n"; } @@ -393,20 +393,14 @@ show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) { // And draw the spindle in this color. CullTraverserData next_data2(data, sw.get_spindle_viz()); - next_data2.apply_transform_and_state(trav, viz_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + next_data2.apply_transform(viz_transform); trav->traverse(next_data2); } // Draw the rings for this switch level. We do this after we have drawn // the geometry and the spindle. CullTraverserData next_data(data, sw.get_ring_viz()); - next_data.apply_transform_and_state(trav, viz_transform, - RenderState::make_empty(), - RenderEffects::make_empty(), - ClipPlaneAttrib::make()); + next_data.apply_transform(viz_transform); trav->traverse(next_data); } } @@ -650,7 +644,7 @@ do_auto_verify_lods(CullTraverser *trav, CullTraverserData &data) { const Switch &sw = cdata->_switch_vector[index]; ostringstream strm; strm - << "Level " << index << " geometry of " << data._node_path + << "Level " << index << " geometry of " << data.get_node_path() << " is larger than its switch radius; suggest radius of " << suggested_radius << " instead of " << sw.get_in() << " (configure verify-lods 0 to ignore this error)"; diff --git a/panda/src/pgraphnodes/nodeCullCallbackData.cxx b/panda/src/pgraphnodes/nodeCullCallbackData.cxx index d0bf763e98..b0cbd9d980 100644 --- a/panda/src/pgraphnodes/nodeCullCallbackData.cxx +++ b/panda/src/pgraphnodes/nodeCullCallbackData.cxx @@ -41,7 +41,7 @@ void NodeCullCallbackData:: upcall() { PandaNode *node = _data.node(); if (node->is_of_type(CallbackNode::get_class_type())) { - CallbackNode *cbnode = DCAST(CallbackNode, _data.node()); + CallbackNode *cbnode = (CallbackNode *)node; // OK, render this node. Rendering a CallbackNode means creating a // CullableObject for the draw_callback, if any. We don't need to pass diff --git a/panda/src/pgraphnodes/shaderGenerator.cxx b/panda/src/pgraphnodes/shaderGenerator.cxx index 2c840e46ee..63973c6bc3 100644 --- a/panda/src/pgraphnodes/shaderGenerator.cxx +++ b/panda/src/pgraphnodes/shaderGenerator.cxx @@ -284,7 +284,7 @@ analyze_renderstate(const RenderState *rs) { PandaNode *light_obj = light.node(); nassertv(light_obj != (PandaNode *)NULL); - if (light_obj->get_type() == AmbientLight::get_class_type()) { + if (light_obj->is_ambient_light()) { if (_material->has_ambient()) { LColor a = _material->get_ambient(); if ((a[0]!=0.0)||(a[1]!=0.0)||(a[2]!=0.0)) { @@ -298,7 +298,7 @@ analyze_renderstate(const RenderState *rs) { } else if (light_obj->is_of_type(LightLensNode::get_class_type())) { _lights_np.push_back(light); _lights.push_back((LightLensNode *)light_obj); - if (DCAST(LightLensNode, light_obj)->is_shadow_caster()) { + if (((const LightLensNode *)light_obj)->is_shadow_caster()) { _shadows = true; } _lighting = true; diff --git a/panda/src/pipeline/pipelineCyclerTrueImpl.I b/panda/src/pipeline/pipelineCyclerTrueImpl.I index 2c393d0546..9b078a6a30 100644 --- a/panda/src/pipeline/pipelineCyclerTrueImpl.I +++ b/panda/src/pipeline/pipelineCyclerTrueImpl.I @@ -231,6 +231,8 @@ read_stage_unlocked(int pipeline_stage) const { TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage_unlocked(int)", " ", TAU_USER); #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif return _data[pipeline_stage]._cdata; } @@ -248,6 +250,8 @@ read_stage(int pipeline_stage, Thread *current_thread) const { TAU_PROFILE("const CycleData *PipelineCyclerTrueImpl::read_stage(int, Thread *)", " ", TAU_USER); #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif _lock.acquire(current_thread); return _data[pipeline_stage]._cdata; @@ -278,6 +282,8 @@ elevate_read_stage(int pipeline_stage, const CycleData *pointer, #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); nassertr(_data[pipeline_stage]._cdata == pointer, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif CycleData *new_pointer = write_stage(pipeline_stage, current_thread); _lock.release(); @@ -296,6 +302,8 @@ elevate_read_stage_upstream(int pipeline_stage, const CycleData *pointer, #ifdef _DEBUG nassertr(pipeline_stage >= 0 && pipeline_stage < _num_stages, NULL); nassertr(_data[pipeline_stage]._cdata == pointer, NULL); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif CycleData *new_pointer = write_stage_upstream(pipeline_stage, force_to_0, current_thread); @@ -313,6 +321,8 @@ release_write_stage(int pipeline_stage, CycleData *pointer) { nassertv(pipeline_stage >= 0 && pipeline_stage < _num_stages); nassertv(_data[pipeline_stage]._cdata == pointer); nassertv(_data[pipeline_stage]._writes_outstanding > 0); +#elif defined(__has_builtin) && __has_builtin(__builtin_assume) + __builtin_assume(pipeline_stage >= 0); #endif --(_data[pipeline_stage]._writes_outstanding); _lock.release(); diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index b6ae48469a..321d24da6a 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -78,7 +78,7 @@ get_pipeline_stage() const { // However, since we guarantee that this is never less than zero, clang // offers a nice way to avoid that. int pipeline_stage = _pipeline_stage; - __builtin_assume(_pipeline_stage >= 0); + __builtin_assume(pipeline_stage >= 0); return pipeline_stage; #else return _pipeline_stage; diff --git a/panda/src/putil/copyOnWriteObject.h b/panda/src/putil/copyOnWriteObject.h index 12ea5baf24..37302ea44a 100644 --- a/panda/src/putil/copyOnWriteObject.h +++ b/panda/src/putil/copyOnWriteObject.h @@ -161,6 +161,12 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +// We can safely redefine this as a no-op. +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "copyOnWriteObject.I" #endif diff --git a/panda/src/putil/simpleHashMap.I b/panda/src/putil/simpleHashMap.I index d68fae9542..74245fd606 100644 --- a/panda/src/putil/simpleHashMap.I +++ b/panda/src/putil/simpleHashMap.I @@ -235,8 +235,8 @@ get_size() const { */ template INLINE bool SimpleHashMap:: -has_element(int n) const { - nassertr(n >= 0 && n < (int)_table_size, false); +has_element(size_t n) const { + nassertr(n < _table_size, false); return (get_exists_array()[n] != 0); } @@ -249,7 +249,7 @@ has_element(int n) const { */ template INLINE const Key &SimpleHashMap:: -get_key(int n) const { +get_key(size_t n) const { nassertr(has_element(n), _table[n]._key); return _table[n]._key; } @@ -263,7 +263,7 @@ get_key(int n) const { */ template INLINE const Value &SimpleHashMap:: -get_data(int n) const { +get_data(size_t n) const { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -277,7 +277,7 @@ get_data(int n) const { */ template INLINE Value &SimpleHashMap:: -modify_data(int n) { +modify_data(size_t n) { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -291,7 +291,7 @@ modify_data(int n) { */ template INLINE void SimpleHashMap:: -set_data(int n, const Value &data) { +set_data(size_t n, const Value &data) { nassertv(has_element(n)); _table[n]._data = data; } @@ -305,7 +305,7 @@ set_data(int n, const Value &data) { */ template void SimpleHashMap:: -remove_element(int n) { +remove_element(size_t n) { nassertv(has_element(n)); clear_element(n); @@ -314,7 +314,7 @@ remove_element(int n) { // Now we have put a hole in the table. If there was a hash conflict in the // slot following this one, we have to move it down to close the hole. - size_t i = (size_t)n; + size_t i = n; i = (i + 1) & (_table_size - 1); while (has_element(i)) { size_t wants_index = get_hash(_table[i]._key); @@ -403,12 +403,14 @@ bool SimpleHashMap:: validate() const { size_t count = 0; + const unsigned char *exists_array = get_exists_array(); + for (size_t i = 0; i < _table_size; ++i) { - if (has_element(i)) { + if (exists_array[i] != 0) { ++count; size_t ideal_index = get_hash(_table[i]._key); size_t wants_index = ideal_index; - while (wants_index != i && has_element(wants_index)) { + while (wants_index != i && exists_array[wants_index] != 0) { wants_index = (wants_index + 1) & (_table_size - 1); } if (wants_index != i) { @@ -455,7 +457,7 @@ get_hash(const Key &key) const { */ template INLINE bool SimpleHashMap:: -is_element(int n, const Key &key) const { +is_element(size_t n, const Key &key) const { nassertr(has_element(n), false); return _comp.is_equal(_table[n]._key, key); } @@ -466,7 +468,7 @@ is_element(int n, const Key &key) const { */ template INLINE void SimpleHashMap:: -store_new_element(int n, const Key &key, const Value &data) { +store_new_element(size_t n, const Key &key, const Value &data) { new(&_table[n]) TableEntry(key, data); get_exists_array()[n] = true; } @@ -476,7 +478,7 @@ store_new_element(int n, const Key &key, const Value &data) { */ template INLINE void SimpleHashMap:: -clear_element(int n) { +clear_element(size_t n) { _table[n].~TableEntry(); get_exists_array()[n] = false; } diff --git a/panda/src/putil/simpleHashMap.h b/panda/src/putil/simpleHashMap.h index 7954cd943e..c1a25fc7f9 100644 --- a/panda/src/putil/simpleHashMap.h +++ b/panda/src/putil/simpleHashMap.h @@ -42,12 +42,12 @@ public: INLINE Value &operator [] (const Key &key); INLINE size_t get_size() const; - INLINE bool has_element(int n) const; - INLINE const Key &get_key(int n) const; - INLINE const Value &get_data(int n) const; - INLINE Value &modify_data(int n); - INLINE void set_data(int n, const Value &data); - void remove_element(int n); + INLINE bool has_element(size_t n) const; + INLINE const Key &get_key(size_t n) const; + INLINE const Value &get_data(size_t n) const; + INLINE Value &modify_data(size_t n); + INLINE void set_data(size_t n, const Value &data); + void remove_element(size_t n); INLINE size_t get_num_entries() const; INLINE bool is_empty() const; @@ -61,9 +61,9 @@ private: INLINE size_t get_hash(const Key &key) const; - INLINE bool is_element(int n, const Key &key) const; - INLINE void store_new_element(int n, const Key &key, const Value &data); - INLINE void clear_element(int n); + INLINE bool is_element(size_t n, const Key &key) const; + INLINE void store_new_element(size_t n, const Key &key, const Value &data); + INLINE void clear_element(size_t n); INLINE unsigned char *get_exists_array() const; void new_table(); diff --git a/panda/src/putil/typedWritableReferenceCount.h b/panda/src/putil/typedWritableReferenceCount.h index 97d7d90029..51803d7b36 100644 --- a/panda/src/putil/typedWritableReferenceCount.h +++ b/panda/src/putil/typedWritableReferenceCount.h @@ -61,6 +61,11 @@ private: static TypeHandle _type_handle; }; +#ifdef DO_MEMORY_USAGE +template<> +INLINE void PointerToBase::update_type(To *ptr) {} +#endif + #include "typedWritableReferenceCount.I" #endif diff --git a/panda/src/putil/weakKeyHashMap.I b/panda/src/putil/weakKeyHashMap.I index b4b007f998..f894411f24 100644 --- a/panda/src/putil/weakKeyHashMap.I +++ b/panda/src/putil/weakKeyHashMap.I @@ -234,8 +234,8 @@ get_size() const { */ template INLINE bool WeakKeyHashMap:: -has_element(int n) const { - nassertr(n >= 0 && n < (int)_table_size, false); +has_element(size_t n) const { + nassertr(n < _table_size, false); return (get_exists_array()[n] != 0 && !_table[n]._key.was_deleted()); } @@ -248,7 +248,7 @@ has_element(int n) const { */ template INLINE const Key *WeakKeyHashMap:: -get_key(int n) const { +get_key(size_t n) const { nassertr(has_element(n), _table[n]._key); return _table[n]._key; } @@ -262,7 +262,7 @@ get_key(int n) const { */ template INLINE const Value &WeakKeyHashMap:: -get_data(int n) const { +get_data(size_t n) const { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -276,7 +276,7 @@ get_data(int n) const { */ template INLINE Value &WeakKeyHashMap:: -modify_data(int n) { +modify_data(size_t n) { nassertr(has_element(n), _table[n]._data); return _table[n]._data; } @@ -290,7 +290,7 @@ modify_data(int n) { */ template INLINE void WeakKeyHashMap:: -set_data(int n, const Value &data) { +set_data(size_t n, const Value &data) { nassertv(has_element(n)); _table[n]._data = data; } @@ -305,7 +305,7 @@ set_data(int n, const Value &data) { */ template INLINE void WeakKeyHashMap:: -set_data(int n, Value &&data) { +set_data(size_t n, Value &&data) { nassertv(has_element(n)); _table[n]._data = move(data); } @@ -320,7 +320,7 @@ set_data(int n, Value &&data) { */ template void WeakKeyHashMap:: -remove_element(int n) { +remove_element(size_t n) { nassertv(get_exists_array()[n] != 0); clear_element(n); @@ -329,7 +329,7 @@ remove_element(int n) { // Now we have put a hole in the table. If there was a hash conflict in the // slot following this one, we have to move it down to close the hole. - size_t i = (size_t)n; + size_t i = n; i = (i + 1) & (_table_size - 1); while (get_exists_array()[i] != 0) { if (_table[i]._key.was_deleted()) { @@ -430,15 +430,17 @@ bool WeakKeyHashMap:: validate() const { size_t count = 0; + const unsigned char *exists_array = get_exists_array(); + for (size_t i = 0; i < _table_size; ++i) { - if (get_exists_array()[i] != 0) { + if (exists_array[i] != 0) { ++count; if (_table[i]._key.was_deleted()) { continue; } size_t ideal_index = get_hash(_table[i]._key.get_orig()); size_t wants_index = ideal_index; - while (wants_index != i && get_exists_array()[i] != 0) { + while (wants_index != i && exists_array[wants_index] != 0) { wants_index = (wants_index + 1) & (_table_size - 1); } if (wants_index != i) { @@ -485,7 +487,7 @@ get_hash(const Key *key) const { */ template INLINE bool WeakKeyHashMap:: -is_element(int n, const Key *key) const { +is_element(size_t n, const Key *key) const { nassertr(has_element(n), false); return _table[n]._key == key; } @@ -496,7 +498,7 @@ is_element(int n, const Key *key) const { */ template INLINE void WeakKeyHashMap:: -store_new_element(int n, const Key *key, const Value &data) { +store_new_element(size_t n, const Key *key, const Value &data) { if (get_exists_array()[n] != 0) { // There was already an element in this spot. This can happen if it was a // pointer that had already been deleted. @@ -513,7 +515,7 @@ store_new_element(int n, const Key *key, const Value &data) { */ template INLINE void WeakKeyHashMap:: -clear_element(int n) { +clear_element(size_t n) { _table[n].~TableEntry(); get_exists_array()[n] = false; } diff --git a/panda/src/putil/weakKeyHashMap.h b/panda/src/putil/weakKeyHashMap.h index 98a8863ee2..bbb7077998 100644 --- a/panda/src/putil/weakKeyHashMap.h +++ b/panda/src/putil/weakKeyHashMap.h @@ -45,15 +45,15 @@ public: INLINE Value &operator [] (const Key *key); INLINE size_t get_size() const; - INLINE bool has_element(int n) const; - INLINE const Key *get_key(int n) const; - INLINE const Value &get_data(int n) const; - INLINE Value &modify_data(int n); - INLINE void set_data(int n, const Value &data); + INLINE bool has_element(size_t n) const; + INLINE const Key *get_key(size_t n) const; + INLINE const Value &get_data(size_t n) const; + INLINE Value &modify_data(size_t n); + INLINE void set_data(size_t n, const Value &data); #ifdef USE_MOVE_SEMANTICS - INLINE void set_data(int n, Value &&data); + INLINE void set_data(size_t n, Value &&data); #endif - void remove_element(int n); + void remove_element(size_t n); INLINE size_t get_num_entries() const; INLINE bool is_empty() const; @@ -65,9 +65,9 @@ public: private: INLINE size_t get_hash(const Key *key) const; - INLINE bool is_element(int n, const Key *key) const; - INLINE void store_new_element(int n, const Key *key, const Value &data); - INLINE void clear_element(int n); + INLINE bool is_element(size_t n, const Key *key) const; + INLINE void store_new_element(size_t n, const Key *key, const Value &data); + INLINE void clear_element(size_t n); INLINE unsigned char *get_exists_array() const; void new_table();