diff --git a/dtool/src/dtoolbase/typedObject.I b/dtool/src/dtoolbase/typedObject.I index 684d0e8143..7c2917072f 100644 --- a/dtool/src/dtoolbase/typedObject.I +++ b/dtool/src/dtoolbase/typedObject.I @@ -61,7 +61,9 @@ get_type_index() const { //////////////////////////////////////////////////////////////////// INLINE bool TypedObject:: is_of_type(TypeHandle handle) const { - return get_type().is_derived_from(handle, (TypedObject *)this); + // Shortcut for the common case where the type matches exactly. + TypeHandle my_type = get_type(); + return handle == my_type || my_type.is_derived_from(handle, (TypedObject *)this); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/char/character.cxx b/panda/src/char/character.cxx index 9be6fe87d5..6d3ce17d94 100644 --- a/panda/src/char/character.cxx +++ b/panda/src/char/character.cxx @@ -420,8 +420,7 @@ find_joint(const string &name) const { int num_bundles = get_num_bundles(); for (int i = 0; i < num_bundles; ++i) { PartGroup *part = get_bundle(i)->find_child(name); - if (part != (PartGroup *)NULL && - part->is_of_type(CharacterJoint::get_class_type())) { + if (part != (PartGroup *)NULL && part->is_character_joint()) { return DCAST(CharacterJoint, part); } } @@ -728,7 +727,7 @@ r_merge_bundles(Character::JointMap &joint_map, PartGroup *old_group, PartGroup *new_group) { joint_map[old_group] = new_group; - if (new_group->is_of_type(CharacterJoint::get_class_type())) { + if (new_group->is_character_joint()) { CharacterJoint *new_joint; DCAST_INTO_V(new_joint, new_group); @@ -736,7 +735,7 @@ r_merge_bundles(Character::JointMap &joint_map, new_joint->_character = this; if (old_group != new_group && - old_group->is_of_type(CharacterJoint::get_class_type())) { + old_group->is_character_joint()) { CharacterJoint *old_joint; DCAST_INTO_V(old_joint, old_group); @@ -763,7 +762,7 @@ r_merge_bundles(Character::JointMap &joint_map, if (old_group == new_group) { return; } - + int i = 0, j = 0; int old_num_children = old_group->get_num_children(); int new_num_children = new_group->get_num_children(); @@ -809,7 +808,7 @@ r_merge_bundles(Character::JointMap &joint_map, // new_group. Duplicate it. PartGroup *new_pc = pc->make_copy(); new_children.push_back(new_pc); - + r_merge_bundles(joint_map, pc, new_pc); i++; } @@ -968,7 +967,7 @@ copy_geom(const Geom *source, const Character::JointMap &joint_map, void Character:: copy_node_pointers(const Character::NodeMap &node_map, PartGroup *dest, const PartGroup *source) { - if (dest->is_of_type(CharacterJoint::get_class_type())) { + if (dest->is_character_joint()) { nassertv(dest != source); const CharacterJoint *source_joint; CharacterJoint *dest_joint; @@ -1204,7 +1203,7 @@ redirect_slider(const VertexSlider *vs, Character::GeomSliderMap &gsmap) { //////////////////////////////////////////////////////////////////// void Character:: r_clear_joint_characters(PartGroup *part) { - if (part->is_of_type(CharacterJoint::get_class_type())) { + if (part->is_character_joint()) { CharacterJoint *joint = DCAST(CharacterJoint, part); // It is possible for the joint to reference a different Character diff --git a/panda/src/char/characterJointBundle.cxx b/panda/src/char/characterJointBundle.cxx index 8732d5a2ac..ba045369c4 100644 --- a/panda/src/char/characterJointBundle.cxx +++ b/panda/src/char/characterJointBundle.cxx @@ -102,8 +102,8 @@ r_set_character(PartGroup *group, Character *character) { return; } - if (group->is_of_type(CharacterJoint::get_class_type())) { - DCAST(CharacterJoint, group)->set_character(character); + if (group->is_character_joint()) { + ((CharacterJoint *)group)->set_character(character); } Children::const_iterator ci; diff --git a/panda/src/cull/cullBinBackToFront.cxx b/panda/src/cull/cullBinBackToFront.cxx index 6a734c0092..9e67adc36b 100644 --- a/panda/src/cull/cullBinBackToFront.cxx +++ b/panda/src/cull/cullBinBackToFront.cxx @@ -64,8 +64,8 @@ add_object(CullableObject *object, Thread *current_thread) { return; } - const GeometricBoundingVolume *gbv; - DCAST_INTO_V(gbv, volume); + const GeometricBoundingVolume *gbv = volume->as_geometric_bounding_volume(); + nassertv(gbv != NULL); LPoint3 center = gbv->get_approx_center(); nassertv(object->_internal_transform != (const TransformState *)NULL); diff --git a/panda/src/cull/cullBinFrontToBack.cxx b/panda/src/cull/cullBinFrontToBack.cxx index 91e8c99133..ba2103a0f7 100644 --- a/panda/src/cull/cullBinFrontToBack.cxx +++ b/panda/src/cull/cullBinFrontToBack.cxx @@ -64,8 +64,8 @@ add_object(CullableObject *object, Thread *current_thread) { return; } - const GeometricBoundingVolume *gbv; - DCAST_INTO_V(gbv, volume); + const GeometricBoundingVolume *gbv = volume->as_geometric_bounding_volume(); + nassertv(gbv != NULL); LPoint3 center = gbv->get_approx_center(); nassertv(object->_internal_transform != (const TransformState *)NULL); diff --git a/panda/src/display/displayRegion.I b/panda/src/display/displayRegion.I index 53d68ff00d..112b612de4 100644 --- a/panda/src/display/displayRegion.I +++ b/panda/src/display/displayRegion.I @@ -597,11 +597,16 @@ get_region_pixels_i(int i, int &xo, int &yo, int &w, int &h) const { // to all upstream pipeline stages. //////////////////////////////////////////////////////////////////// INLINE void DisplayRegion:: -set_cull_result(CullResult *cull_result, SceneSetup *scene_setup, +set_cull_result(PT(CullResult) cull_result, PT(SceneSetup) scene_setup, Thread *current_thread) { CDCullWriter cdata(_cycler_cull, true, current_thread); - cdata->_cull_result = cull_result; - cdata->_scene_setup = scene_setup; +#ifdef USE_MOVE_SEMANTICS + cdata->_cull_result = std::move(cull_result); + cdata->_scene_setup = std::move(scene_setup); +#else + swap(cdata->_cull_result, cull_result); + swap(cdata->_scene_setup, scene_setup); +#endif } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/displayRegion.h b/panda/src/display/displayRegion.h index 811b913e5c..3b33590996 100644 --- a/panda/src/display/displayRegion.h +++ b/panda/src/display/displayRegion.h @@ -161,7 +161,7 @@ public: virtual bool supports_pixel_zoom() const; - INLINE void set_cull_result(CullResult *cull_result, SceneSetup *scene_setup, + INLINE void set_cull_result(PT(CullResult) cull_result, PT(SceneSetup) scene_setup, Thread *current_thread); INLINE CullResult *get_cull_result(Thread *current_thread) const; INLINE SceneSetup *get_scene_setup(Thread *current_thread) const; diff --git a/panda/src/display/graphicsEngine.cxx b/panda/src/display/graphicsEngine.cxx index 2cac310b0c..892d70361d 100644 --- a/panda/src/display/graphicsEngine.cxx +++ b/panda/src/display/graphicsEngine.cxx @@ -41,7 +41,6 @@ #include "bamCache.h" #include "cullableObject.h" #include "geomVertexArrayData.h" -#include "omniBoundingVolume.h" #include "vertexDataSaveFile.h" #include "vertexDataBook.h" #include "vertexDataPage.h" @@ -1248,12 +1247,12 @@ do_cull(CullHandler *cull_handler, SceneSetup *scene_setup, // from the lens. PT(BoundingVolume) bv = scene_setup->get_cull_bounds(); - if (bv != (BoundingVolume *)NULL && - bv->is_of_type(GeometricBoundingVolume::get_class_type()) && - !bv->is_of_type(OmniBoundingVolume::get_class_type())) { + if (bv != (BoundingVolume *)NULL && !bv->is_infinite() && + bv->as_geometric_bounding_volume() != NULL) { // Transform it into the appropriate coordinate space. PT(GeometricBoundingVolume) local_frustum; - local_frustum = DCAST(GeometricBoundingVolume, bv->make_copy()); + local_frustum = bv->make_copy()->as_geometric_bounding_volume(); + nassertv(!local_frustum.is_null()); NodePath scene_parent = scene_setup->get_scene_root().get_parent(current_thread); CPT(TransformState) cull_center_transform = @@ -1580,7 +1579,7 @@ cull_to_bins(GraphicsOutput *win, DisplayRegion *dr, Thread *current_thread) { } // Save the results for next frame. - dr->set_cull_result(cull_result, scene_setup, current_thread); + dr->set_cull_result(MOVE(cull_result), MOVE(scene_setup), current_thread); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/display/graphicsStateGuardian.cxx b/panda/src/display/graphicsStateGuardian.cxx index b2fef6f469..de9b8d0036 100644 --- a/panda/src/display/graphicsStateGuardian.cxx +++ b/panda/src/display/graphicsStateGuardian.cxx @@ -40,6 +40,7 @@ #include "graphicsOutput.h" #include "texturePool.h" #include "geomMunger.h" +#include "stateMunger.h" #include "ambientLight.h" #include "directionalLight.h" #include "pointLight.h" @@ -814,38 +815,42 @@ dispatch_compute(int num_groups_x, int num_groups_y, int num_groups_z) { //////////////////////////////////////////////////////////////////// PT(GeomMunger) GraphicsStateGuardian:: get_geom_munger(const RenderState *state, Thread *current_thread) { - // Before we even look up the map, see if the _last_mi value points - // to this GSG. This is likely because we tend to visit the same - // state multiple times during a frame. Also, this might well be - // the only GSG in the world anyway. - if (!state->_mungers.empty()) { - RenderState::Mungers::const_iterator mi = state->_last_mi; - if (!(*mi).first.was_deleted() && (*mi).first == this) { - if ((*mi).second->is_registered()) { - return (*mi).second; + RenderState::Mungers &mungers = state->_mungers; + + if (mungers.is_empty()) { + // Before we even look up the map, see if the _last_mi value points + // to this GSG. This is likely because we tend to visit the same + // state multiple times during a frame. Also, this might well be + // the only GSG in the world anyway. + int mi = state->_last_mi; + if (mi >= 0 && mungers.has_element(mi) && mungers.get_key(mi) == this) { + PT(GeomMunger) munger = mungers.get_data(mi); + if (munger->is_registered()) { + return munger; } } - } - // Nope, we have to look it up in the map. - RenderState::Mungers::iterator mi = state->_mungers.find(this); - if (mi != state->_mungers.end() && !(*mi).first.was_deleted()) { - if ((*mi).second->is_registered()) { - state->_last_mi = mi; - return (*mi).second; + // Nope, we have to look it up in the map. + mi = mungers.find(this); + if (mi >= 0) { + PT(GeomMunger) munger = mungers.get_data(mi); + if (munger->is_registered()) { + state->_last_mi = mi; + return munger; + } else { + // This GeomMunger is no longer registered. Remove it from + // the map. + mungers.remove_element(mi); + } } - // This GeomMunger is no longer registered. Remove it from the - // map. - state->_mungers.erase(mi); } // Nothing in the map; create a new entry. PT(GeomMunger) munger = make_geom_munger(state, current_thread); nassertr(munger != (GeomMunger *)NULL && munger->is_registered(), munger); + nassertr(munger->is_of_type(StateMunger::get_class_type()), munger); - mi = state->_mungers.insert(RenderState::Mungers::value_type(this, munger)).first; - state->_last_mi = mi; - + state->_last_mi = mungers.store(this, munger); return munger; } diff --git a/panda/src/display/standardMunger.cxx b/panda/src/display/standardMunger.cxx index 85ddd0f3e1..53b4485303 100644 --- a/panda/src/display/standardMunger.cxx +++ b/panda/src/display/standardMunger.cxx @@ -15,7 +15,6 @@ #include "standardMunger.h" #include "renderState.h" #include "graphicsStateGuardian.h" -#include "dcast.h" #include "config_gobj.h" #include "displayRegion.h" @@ -43,16 +42,15 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, _auto_shader(false), _shader_skinning(false) { - _render_mode = DCAST(RenderModeAttrib, state->get_attrib(RenderModeAttrib::get_class_slot())); + _render_mode = (const RenderModeAttrib *) + state->get_attrib(RenderModeAttrib::get_class_slot()); if (!get_gsg()->get_runtime_color_scale()) { // We might need to munge the colors. - const ColorAttrib *color_attrib = (const ColorAttrib *) - state->get_attrib(ColorAttrib::get_class_slot()); - const ColorScaleAttrib *color_scale_attrib = (const ColorScaleAttrib *) - state->get_attrib(ColorScaleAttrib::get_class_slot()); + const ColorAttrib *color_attrib; + const ColorScaleAttrib *color_scale_attrib; - if (color_attrib != (ColorAttrib *)NULL && + if (state->get_attrib(color_attrib) && color_attrib->get_color_type() == ColorAttrib::T_flat) { if (!get_gsg()->get_color_scale_via_lighting()) { @@ -60,7 +58,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, // can't cheat the color via lighting (presumably, in this case, // by applying a material). _color = color_attrib->get_color(); - if (color_scale_attrib != (ColorScaleAttrib *)NULL && + if (state->get_attrib(color_scale_attrib) && color_scale_attrib->has_scale()) { const LVecBase4 &cs = color_scale_attrib->get_scale(); _color.set(_color[0] * cs[0], @@ -70,11 +68,11 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, } _munge_color = true; } - - } else if (color_scale_attrib != (ColorScaleAttrib *)NULL && + + } else if (state->get_attrib(color_scale_attrib) && color_scale_attrib->has_scale()) { _color_scale = color_scale_attrib->get_scale(); - + const TextureAttrib *tex_attrib = (const TextureAttrib *) state->get_attrib(TextureAttrib::get_class_slot()); @@ -106,7 +104,7 @@ StandardMunger(GraphicsStateGuardianBase *gsg, const RenderState *state, //////////////////////////////////////////////////////////////////// // Function: StandardMunger::Destructor // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// StandardMunger:: ~StandardMunger() { @@ -126,7 +124,7 @@ munge_data_impl(const GeomVertexData *data) { new_data = new_data->set_color(_color, _num_components, _numeric_type, _contents); } else if (_munge_color_scale) { - new_data = new_data->scale_color(_color_scale, _num_components, + new_data = new_data->scale_color(_color_scale, _num_components, _numeric_type, _contents); } @@ -142,9 +140,9 @@ munge_data_impl(const GeomVertexData *data) { const TransformBlendTable *table = new_data->get_transform_blend_table(); if (table != (TransformBlendTable *)NULL && table->get_num_transforms() != 0 && - table->get_max_simultaneous_transforms() <= + table->get_max_simultaneous_transforms() <= get_gsg()->get_max_vertex_transforms()) { - if (matrix_palette && + if (matrix_palette && table->get_num_transforms() <= get_gsg()->get_max_vertex_transform_indices()) { if (table->get_num_transforms() == table->get_max_simultaneous_transforms()) { @@ -186,7 +184,7 @@ munge_data_impl(const GeomVertexData *data) { // Description: Converts a Geom and/or its data as necessary. //////////////////////////////////////////////////////////////////// void StandardMunger:: -munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, +munge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data, Thread *) { int supported_geom_rendering = get_gsg()->get_supported_geom_rendering(); @@ -289,7 +287,7 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) { //////////////////////////////////////////////////////////////////// int StandardMunger:: compare_to_impl(const GeomMunger *other) const { - const StandardMunger *om = DCAST(StandardMunger, other); + const StandardMunger *om = (const StandardMunger *)other; if (_render_mode != om->_render_mode) { return _render_mode < om->_render_mode ? -1 : 1; @@ -335,7 +333,8 @@ compare_to_impl(const GeomMunger *other) const { //////////////////////////////////////////////////////////////////// int StandardMunger:: geom_compare_to_impl(const GeomMunger *other) const { - const StandardMunger *om = DCAST(StandardMunger, other); + const StandardMunger *om = (const StandardMunger *)other; + if (_munge_color != om->_munge_color) { return (int)_munge_color - (int)om->_munge_color; } diff --git a/panda/src/egg2pg/characterMaker.cxx b/panda/src/egg2pg/characterMaker.cxx index 18b688f3e1..5450a3ab6d 100644 --- a/panda/src/egg2pg/characterMaker.cxx +++ b/panda/src/egg2pg/characterMaker.cxx @@ -156,7 +156,7 @@ PandaNode *CharacterMaker:: part_to_node(PartGroup *part, const string &name) const { PandaNode *node = _character_node; - if (part->is_of_type(CharacterJoint::get_class_type())) { + if (part->is_character_joint()) { CharacterJoint *joint = DCAST(CharacterJoint, part); if (joint->_geom_node != (PandaNode *)NULL) { node = joint->_geom_node; @@ -343,7 +343,7 @@ build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) { //////////////////////////////////////////////////////////////////// void CharacterMaker:: parent_joint_nodes(PartGroup *part) { - if (part->is_of_type(CharacterJoint::get_class_type())) { + if (part->is_character_joint()) { CharacterJoint *joint = DCAST(CharacterJoint, part); PandaNode *joint_node = joint->_geom_node; if (joint_node != NULL) { diff --git a/panda/src/egg2pg/eggBinner.cxx b/panda/src/egg2pg/eggBinner.cxx index 89d5db08a6..f06cf04ff9 100644 --- a/panda/src/egg2pg/eggBinner.cxx +++ b/panda/src/egg2pg/eggBinner.cxx @@ -57,16 +57,7 @@ prepare_node(EggNode *node) { //////////////////////////////////////////////////////////////////// int EggBinner:: get_bin_number(const EggNode *node) { - if (node->is_of_type(EggNurbsSurface::get_class_type())) { - return (int)BN_nurbs_surface; - - } else if (node->is_of_type(EggNurbsCurve::get_class_type())) { - return (int)BN_nurbs_curve; - - } else if (node->is_of_type(EggPatch::get_class_type())) { - return (int)BN_patches; - - } else if (node->is_of_type(EggPrimitive::get_class_type())) { + if (node->is_of_type(EggPrimitive::get_class_type())) { return (int)BN_polyset; } else if (node->is_of_type(EggGroup::get_class_type())) { @@ -74,6 +65,15 @@ get_bin_number(const EggNode *node) { if (group->has_lod()) { return (int)BN_lod; } + + } else if (node->is_of_type(EggNurbsSurface::get_class_type())) { + return (int)BN_nurbs_surface; + + } else if (node->is_of_type(EggNurbsCurve::get_class_type())) { + return (int)BN_nurbs_curve; + + } else if (node->is_of_type(EggPatch::get_class_type())) { + return (int)BN_patches; } return (int)BN_none; diff --git a/panda/src/glstuff/glCgShaderContext_src.cxx b/panda/src/glstuff/glCgShaderContext_src.cxx index 643fa4299a..a2301e74a7 100644 --- a/panda/src/glstuff/glCgShaderContext_src.cxx +++ b/panda/src/glstuff/glCgShaderContext_src.cxx @@ -991,8 +991,8 @@ update_shader_texture_bindings(ShaderContext *prev) { // We get the TextureAttrib directly from the _target_rs, not the // filtered TextureAttrib in _target_texture. - const TextureAttrib *texattrib = DCAST(TextureAttrib, _glgsg->_target_rs->get_attrib_def(TextureAttrib::get_class_slot())); - nassertv(texattrib != (TextureAttrib *)NULL); + const TextureAttrib *texattrib; + _glgsg->_target_rs->get_attrib_def(texattrib); for (int i = 0; i < (int)_shader->_tex_spec.size(); ++i) { Shader::ShaderTexSpec &spec = _shader->_tex_spec[i]; @@ -1053,8 +1053,9 @@ update_shader_texture_bindings(ShaderContext *prev) { continue; } - _glgsg->apply_texture(tc); - _glgsg->apply_sampler(texunit, sampler, tc); + CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc; + _glgsg->apply_texture(gtc); + _glgsg->apply_sampler(texunit, sampler, gtc); } cg_report_errors(); diff --git a/panda/src/glstuff/glGeomMunger_src.cxx b/panda/src/glstuff/glGeomMunger_src.cxx index 778fb71d95..7be5a50d50 100644 --- a/panda/src/glstuff/glGeomMunger_src.cxx +++ b/panda/src/glstuff/glGeomMunger_src.cxx @@ -26,8 +26,8 @@ ALLOC_DELETED_CHAIN_DEF(CLP(GeomMunger)); CLP(GeomMunger):: CLP(GeomMunger)(GraphicsStateGuardian *gsg, const RenderState *state) : StandardMunger(gsg, state, 4, NT_uint8, C_color), - _texture(DCAST(TextureAttrib, state->get_attrib(TextureAttrib::get_class_slot()))), - _tex_gen(DCAST(TexGenAttrib, state->get_attrib(TexGenAttrib::get_class_slot()))) + _texture((const TextureAttrib *)state->get_attrib(TextureAttrib::get_class_slot())), + _tex_gen((const TexGenAttrib *)state->get_attrib(TexGenAttrib::get_class_slot())) { // Set a callback to unregister ourselves when either the Texture or // the TexGen object gets deleted. @@ -475,7 +475,7 @@ premunge_geom_impl(CPT(Geom) &geom, CPT(GeomVertexData) &vertex_data) { //////////////////////////////////////////////////////////////////// int CLP(GeomMunger):: compare_to_impl(const GeomMunger *other) const { - const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other); + const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other; if (_texture != om->_texture) { return _texture < om->_texture ? -1 : 1; } @@ -499,7 +499,7 @@ compare_to_impl(const GeomMunger *other) const { //////////////////////////////////////////////////////////////////// int CLP(GeomMunger):: geom_compare_to_impl(const GeomMunger *other) const { - const CLP(GeomMunger) *om = DCAST(CLP(GeomMunger), other); + const CLP(GeomMunger) *om = (CLP(GeomMunger) *)other; #ifdef OPENGLES if (get_render_mode() != om->get_render_mode()) { return get_render_mode() < om->get_render_mode() ? -1 : 1; diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx index 8ab2c7b872..89227ee1bf 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.cxx +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.cxx @@ -4512,13 +4512,14 @@ prepare_texture(Texture *tex, int view) { //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: update_texture(TextureContext *tc, bool force) { - CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); + CLP(TextureContext) *gtc; + DCAST_INTO_R(gtc, tc, false); if (gtc->was_image_modified() || !gtc->_has_storage) { PStatGPUTimer timer(this, _texture_update_pcollector); // If the texture image was modified, reload the texture. - apply_texture(tc); + apply_texture(gtc); Texture *tex = tc->get_texture(); if (gtc->was_properties_modified()) { @@ -4536,7 +4537,7 @@ update_texture(TextureContext *tc, bool force) { // If only the properties have been modified, we don't necessarily // need to reload the texture. - apply_texture(tc); + apply_texture(gtc); Texture *tex = tc->get_texture(); if (specify_texture(gtc, tex->get_default_sampler())) { @@ -9649,8 +9650,10 @@ update_standard_texture_bindings() { glDisable(target); continue; } - apply_texture(tc); - apply_sampler(i, _target_texture->get_on_sampler(stage), tc); + // Don't DCAST(); we already did the verification in update_texture. + CLP(TextureContext) *gtc = (CLP(TextureContext) *)tc; + apply_texture(gtc); + apply_sampler(i, _target_texture->get_on_sampler(stage), gtc); if (stage->involves_color_scale() && _color_scale_enabled) { LColor color = stage->get_color(); @@ -10487,9 +10490,7 @@ specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler) { // for rendering. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -apply_texture(TextureContext *tc) { - CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); - +apply_texture(CLP(TextureContext) *gtc) { gtc->set_active(true); GLenum target = get_texture_target(gtc->get_texture()->get_texture_type()); if (target == GL_NONE) { @@ -10520,9 +10521,7 @@ apply_texture(TextureContext *tc) { // context instead. //////////////////////////////////////////////////////////////////// bool CLP(GraphicsStateGuardian):: -apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { - CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc); - +apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc) { #ifndef OPENGLES if (_supports_sampler_objects) { // We support sampler objects. Prepare the sampler object and @@ -10547,7 +10546,7 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { // texture and change the texture parameters if they don't match. if (gtc->_active_sampler != sampler) { _glActiveTexture(GL_TEXTURE0 + unit); - apply_texture(tc); + apply_texture(gtc); specify_texture(gtc, sampler); } } @@ -10555,7 +10554,7 @@ apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc) { if (sampler.uses_mipmaps() && !gtc->_uses_mipmaps) { // The texture wasn't created with mipmaps, but we are trying // to sample it with mipmaps. We will need to reload it. - apply_texture(tc); + apply_texture(gtc); gtc->mark_needs_reload(); bool okflag = upload_texture(gtc, false, true); if (!okflag) { diff --git a/panda/src/glstuff/glGraphicsStateGuardian_src.h b/panda/src/glstuff/glGraphicsStateGuardian_src.h index 63c4cb8abd..f38dd5326c 100644 --- a/panda/src/glstuff/glGraphicsStateGuardian_src.h +++ b/panda/src/glstuff/glGraphicsStateGuardian_src.h @@ -531,8 +531,8 @@ protected: #endif // NDEBUG bool specify_texture(CLP(TextureContext) *gtc, const SamplerState &sampler); - bool apply_texture(TextureContext *tc); - bool apply_sampler(GLuint unit, const SamplerState &sampler, TextureContext *tc); + bool apply_texture(CLP(TextureContext) *gtc); + bool apply_sampler(GLuint unit, const SamplerState &sampler, CLP(TextureContext) *gtc); bool upload_texture(CLP(TextureContext) *gtc, bool force, bool uses_mipmaps); bool upload_texture_image(CLP(TextureContext) *gtc, bool needs_reload, bool uses_mipmaps, int mipmap_bias, diff --git a/panda/src/gobj/geom.I b/panda/src/gobj/geom.I index 823e9798a4..b639041c85 100644 --- a/panda/src/gobj/geom.I +++ b/panda/src/gobj/geom.I @@ -832,7 +832,7 @@ get_modified() const { INLINE GeomContext *GeomPipelineReader:: prepare_now(PreparedGraphicsObjects *prepared_objects, GraphicsStateGuardianBase *gsg) const { - return ((Geom *)_object.p())->prepare_now(prepared_objects, gsg); + return ((Geom *)_object)->prepare_now(prepared_objects, gsg); } INLINE ostream & diff --git a/panda/src/gobj/geom.cxx b/panda/src/gobj/geom.cxx index fe82255c6e..40166e15bc 100644 --- a/panda/src/gobj/geom.cxx +++ b/panda/src/gobj/geom.cxx @@ -1897,7 +1897,7 @@ check_usage_hint() const { #ifdef DO_PIPELINING unref_delete((CycleData *)_cdata); #endif - Geom::CDWriter fresh_cdata(((Geom *)_object.p())->_cycler, + Geom::CDWriter fresh_cdata(((Geom *)_object)->_cycler, false, _current_thread); ((GeomPipelineReader *)this)->_cdata = fresh_cdata; #ifdef DO_PIPELINING @@ -1906,7 +1906,7 @@ check_usage_hint() const { if (!fresh_cdata->_got_usage_hint) { // The cache is still stale. We have to do the work of // freshening it. - ((Geom *)_object.p())->reset_usage_hint(fresh_cdata); + ((Geom *)_object)->reset_usage_hint(fresh_cdata); nassertv(fresh_cdata->_got_usage_hint); } diff --git a/panda/src/gobj/geom.h b/panda/src/gobj/geom.h index 5e5b269f10..e1acb5f465 100644 --- a/panda/src/gobj/geom.h +++ b/panda/src/gobj/geom.h @@ -397,6 +397,10 @@ private: // Class : GeomPipelineReader // Description : Encapsulates the data from a Geom, // pre-fetched for one stage of the pipeline. +// +// Does not hold a reference to the Geom. The caller +// must ensure that the Geom persists for at least the +// lifetime of the GeomPipelineReader. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA_GOBJ GeomPipelineReader : public GeomEnums { public: @@ -434,7 +438,7 @@ public: bool force) const; private: - CPT(Geom) _object; + const Geom *_object; Thread *_current_thread; const Geom::CData *_cdata; diff --git a/panda/src/gobj/geomPrimitive.I b/panda/src/gobj/geomPrimitive.I index 9eb42022db..cbaede08be 100644 --- a/panda/src/gobj/geomPrimitive.I +++ b/panda/src/gobj/geomPrimitive.I @@ -107,8 +107,8 @@ is_composite() const { //////////////////////////////////////////////////////////////////// INLINE bool GeomPrimitive:: is_indexed() const { - GeomPrimitivePipelineReader reader(this, Thread::get_current_thread()); - return reader.is_indexed(); + CDReader cdata(_cycler); + return (!cdata->_vertices.is_null()); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/mathutil/boundingVolume.cxx b/panda/src/mathutil/boundingVolume.cxx index 48ca7a8bab..de223c05bf 100644 --- a/panda/src/mathutil/boundingVolume.cxx +++ b/panda/src/mathutil/boundingVolume.cxx @@ -84,6 +84,18 @@ write(ostream &out, int indent_level) const { indent(out, indent_level) << *this << "\n"; } +//////////////////////////////////////////////////////////////////// +// Function: BoundingVolume::as_geometric_bounding_volume +// Access: Public, Virtual +// Description: Virtual downcast method. Returns this object as a +// pointer of the indicated type, if it is in fact that +// type. Returns NULL if it is not that type. +//////////////////////////////////////////////////////////////////// +GeometricBoundingVolume *BoundingVolume:: +as_geometric_bounding_volume() { + return NULL; +} + //////////////////////////////////////////////////////////////////// // Function: BoundingVolume::as_geometric_bounding_volume // Access: Public, Virtual diff --git a/panda/src/mathutil/boundingVolume.h b/panda/src/mathutil/boundingVolume.h index 3af3e7fa2d..ab6f02578f 100644 --- a/panda/src/mathutil/boundingVolume.h +++ b/panda/src/mathutil/boundingVolume.h @@ -112,6 +112,7 @@ PUBLISHED: }; public: + virtual GeometricBoundingVolume *as_geometric_bounding_volume(); virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const; virtual const FiniteBoundingVolume *as_finite_bounding_volume() const; virtual const BoundingSphere *as_bounding_sphere() const; diff --git a/panda/src/mathutil/geometricBoundingVolume.cxx b/panda/src/mathutil/geometricBoundingVolume.cxx index 756f86dca0..829c705d85 100644 --- a/panda/src/mathutil/geometricBoundingVolume.cxx +++ b/panda/src/mathutil/geometricBoundingVolume.cxx @@ -19,7 +19,19 @@ TypeHandle GeometricBoundingVolume::_type_handle; //////////////////////////////////////////////////////////////////// // Function: GeometricBoundingVolume::as_geometric_bounding_volume -// Access: Public, Virtual +// Access: Public, Virtual, Final +// Description: Virtual downcast method. Returns this object as a +// pointer of the indicated type, if it is in fact that +// type. Returns NULL if it is not that type. +//////////////////////////////////////////////////////////////////// +GeometricBoundingVolume *GeometricBoundingVolume:: +as_geometric_bounding_volume() { + return this; +} + +//////////////////////////////////////////////////////////////////// +// Function: GeometricBoundingVolume::as_geometric_bounding_volume +// Access: Public, Virtual, Final // Description: Virtual downcast method. Returns this object as a // pointer of the indicated type, if it is in fact that // type. Returns NULL if it is not that type. diff --git a/panda/src/mathutil/geometricBoundingVolume.h b/panda/src/mathutil/geometricBoundingVolume.h index 4bd53591e3..a1e191285c 100644 --- a/panda/src/mathutil/geometricBoundingVolume.h +++ b/panda/src/mathutil/geometricBoundingVolume.h @@ -53,7 +53,8 @@ PUBLISHED: virtual void xform(const LMatrix4 &mat)=0; public: - virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const; + virtual GeometricBoundingVolume *as_geometric_bounding_volume() FINAL; + virtual const GeometricBoundingVolume *as_geometric_bounding_volume() const FINAL; protected: // Some virtual functions to implement fundamental bounding diff --git a/panda/src/pgraph/alphaTestAttrib.cxx b/panda/src/pgraph/alphaTestAttrib.cxx index 8819fe74f0..b9f4531bc5 100644 --- a/panda/src/pgraph/alphaTestAttrib.cxx +++ b/panda/src/pgraph/alphaTestAttrib.cxx @@ -76,13 +76,13 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int AlphaTestAttrib:: compare_to_impl(const RenderAttrib *other) const { - const AlphaTestAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AlphaTestAttrib *ta = (const AlphaTestAttrib *)other; + int compare_result = ((int)_mode - (int)ta->_mode) ; if (compare_result != 0) { return compare_result; } - + if (_reference_alpha != ta->_reference_alpha) { return _reference_alpha < ta->_reference_alpha ? -1 : 1; } diff --git a/panda/src/pgraph/alphaTestAttrib.h b/panda/src/pgraph/alphaTestAttrib.h index 2e3cf9e539..3714f39d9d 100644 --- a/panda/src/pgraph/alphaTestAttrib.h +++ b/panda/src/pgraph/alphaTestAttrib.h @@ -65,7 +65,7 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; @@ -74,7 +74,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "AlphaTestAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new AlphaTestAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/antialiasAttrib.cxx b/panda/src/pgraph/antialiasAttrib.cxx index 54c41096f1..e2242f34be 100644 --- a/panda/src/pgraph/antialiasAttrib.cxx +++ b/panda/src/pgraph/antialiasAttrib.cxx @@ -75,11 +75,7 @@ make(unsigned short mode) { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) AntialiasAttrib:: make_default() { - if (default_antialias_enable) { - return return_new(new AntialiasAttrib(M_auto)); - } else { - return return_new(new AntialiasAttrib(M_none)); - } + return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); } //////////////////////////////////////////////////////////////////// @@ -146,8 +142,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int AntialiasAttrib:: compare_to_impl(const RenderAttrib *other) const { - const AntialiasAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AntialiasAttrib *ta = (const AntialiasAttrib *)other; + if (_mode != ta->_mode) { return (int)_mode - (int)ta->_mode; } @@ -190,8 +186,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) AntialiasAttrib:: compose_impl(const RenderAttrib *other) const { - const AntialiasAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AntialiasAttrib *ta = (const AntialiasAttrib *)other; unsigned short mode_type; unsigned short mode_quality; @@ -277,3 +272,26 @@ fillin(DatagramIterator &scan, BamReader *manager) { _mode = scan.get_uint16(); } + +//////////////////////////////////////////////////////////////////// +// Function: AntialiasAttrib::init_type +// Access: Public, Static +// Description: +//////////////////////////////////////////////////////////////////// +void AntialiasAttrib:: +init_type() { + RenderAttrib::init_type(); + register_type(_type_handle, "AntialiasAttrib", + RenderAttrib::get_class_type()); + + // This is defined here, since we have otherwise no guarantee that + // the config var has already been constructed by the time we call + // init_type() at static init time. + static ConfigVariableBool default_antialias_enable + ("default-antialias-enable", false, + PRC_DESC("Set this true to enable the M_auto antialiasing mode for all " + "nodes by default.")); + + _attrib_slot = register_slot(_type_handle, 100, + new AntialiasAttrib(default_antialias_enable ? M_auto : M_none)); +} diff --git a/panda/src/pgraph/antialiasAttrib.h b/panda/src/pgraph/antialiasAttrib.h index ae7fbfddb1..d975f60575 100644 --- a/panda/src/pgraph/antialiasAttrib.h +++ b/panda/src/pgraph/antialiasAttrib.h @@ -80,17 +80,12 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; } - static void init_type() { - RenderAttrib::init_type(); - register_type(_type_handle, "AntialiasAttrib", - RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); - } + static void init_type(); virtual TypeHandle get_type() const { return get_class_type(); } diff --git a/panda/src/pgraph/audioVolumeAttrib.cxx b/panda/src/pgraph/audioVolumeAttrib.cxx index 05f546ad55..59c055f447 100644 --- a/panda/src/pgraph/audioVolumeAttrib.cxx +++ b/panda/src/pgraph/audioVolumeAttrib.cxx @@ -147,8 +147,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int AudioVolumeAttrib:: compare_to_impl(const RenderAttrib *other) const { - const AudioVolumeAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other; if (_off != ta->_off) { return (int)_off - (int)ta->_off; @@ -198,8 +197,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) AudioVolumeAttrib:: compose_impl(const RenderAttrib *other) const { - const AudioVolumeAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other; if (ta->is_off()) { return ta; @@ -223,8 +221,8 @@ invert_compose_impl(const RenderAttrib *other) const { if (is_off()) { return other; } - const AudioVolumeAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AudioVolumeAttrib *ta = (const AudioVolumeAttrib *)other; + PN_stdfloat new_volume = _volume == 0.0f ? 1.0f : ta->_volume / _volume; AudioVolumeAttrib *attrib = new AudioVolumeAttrib(false, new_volume); diff --git a/panda/src/pgraph/audioVolumeAttrib.h b/panda/src/pgraph/audioVolumeAttrib.h index 5f616425a0..ebfab1077d 100644 --- a/panda/src/pgraph/audioVolumeAttrib.h +++ b/panda/src/pgraph/audioVolumeAttrib.h @@ -73,7 +73,7 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; @@ -82,7 +82,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "AudioVolumeAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new AudioVolumeAttrib(false, 1)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/auxBitplaneAttrib.cxx b/panda/src/pgraph/auxBitplaneAttrib.cxx index 2972bcd227..5f836a0b87 100644 --- a/panda/src/pgraph/auxBitplaneAttrib.cxx +++ b/panda/src/pgraph/auxBitplaneAttrib.cxx @@ -88,8 +88,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int AuxBitplaneAttrib:: compare_to_impl(const RenderAttrib *other) const { - const AuxBitplaneAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const AuxBitplaneAttrib *ta = (const AuxBitplaneAttrib *)other; + int compare_result = _outputs - ta->_outputs; if (compare_result != 0) { return compare_result; diff --git a/panda/src/pgraph/auxBitplaneAttrib.h b/panda/src/pgraph/auxBitplaneAttrib.h index 7c918db7bc..4285294f33 100644 --- a/panda/src/pgraph/auxBitplaneAttrib.h +++ b/panda/src/pgraph/auxBitplaneAttrib.h @@ -108,7 +108,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "AuxBitplaneAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new AuxBitplaneAttrib(0)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/clipPlaneAttrib.h b/panda/src/pgraph/clipPlaneAttrib.h index f8651800b0..f6f6a05b96 100644 --- a/panda/src/pgraph/clipPlaneAttrib.h +++ b/panda/src/pgraph/clipPlaneAttrib.h @@ -148,7 +148,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ClipPlaneAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new ClipPlaneAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx index 9e0b299e13..9cb2095bc9 100644 --- a/panda/src/pgraph/colorAttrib.cxx +++ b/panda/src/pgraph/colorAttrib.cxx @@ -122,8 +122,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ColorAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ColorAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorAttrib *ta = (const ColorAttrib *)other; + if (_type != ta->_type) { return (int)_type - (int)ta->_type; } diff --git a/panda/src/pgraph/colorAttrib.h b/panda/src/pgraph/colorAttrib.h index c30131159a..8a7e70a6e1 100644 --- a/panda/src/pgraph/colorAttrib.h +++ b/panda/src/pgraph/colorAttrib.h @@ -86,7 +86,8 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ColorAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, + new ColorAttrib(T_off, LColor(1, 1, 1, 1))); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/colorBlendAttrib.cxx b/panda/src/pgraph/colorBlendAttrib.cxx index 2ad7bb5065..7c6c5aea23 100644 --- a/panda/src/pgraph/colorBlendAttrib.cxx +++ b/panda/src/pgraph/colorBlendAttrib.cxx @@ -113,8 +113,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ColorBlendAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ColorBlendAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorBlendAttrib *ta = (const ColorBlendAttrib *)other; if (_mode != ta->_mode) { return (int)_mode - (int)ta->_mode; diff --git a/panda/src/pgraph/colorBlendAttrib.h b/panda/src/pgraph/colorBlendAttrib.h index 85ee3b2164..dc2975985f 100644 --- a/panda/src/pgraph/colorBlendAttrib.h +++ b/panda/src/pgraph/colorBlendAttrib.h @@ -129,7 +129,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ColorBlendAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new ColorBlendAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/colorScaleAttrib.cxx b/panda/src/pgraph/colorScaleAttrib.cxx index 04d9db0b9b..dbdf0511cd 100644 --- a/panda/src/pgraph/colorScaleAttrib.cxx +++ b/panda/src/pgraph/colorScaleAttrib.cxx @@ -186,8 +186,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ColorScaleAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ColorScaleAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other; if (is_off() != ta->is_off()) { return (int)is_off() - (int)ta->is_off(); @@ -233,8 +232,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ColorScaleAttrib:: compose_impl(const RenderAttrib *other) const { - const ColorScaleAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other; if (ta->is_off()) { return ta; @@ -263,8 +261,8 @@ invert_compose_impl(const RenderAttrib *other) const { if (is_off()) { return other; } - const ColorScaleAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorScaleAttrib *ta = (const ColorScaleAttrib *)other; + LVecBase4 new_scale(_scale[0] == 0.0f ? 1.0f : ta->_scale[0] / _scale[0], _scale[1] == 0.0f ? 1.0f : ta->_scale[1] / _scale[1], _scale[2] == 0.0f ? 1.0f : ta->_scale[2] / _scale[2], diff --git a/panda/src/pgraph/colorScaleAttrib.h b/panda/src/pgraph/colorScaleAttrib.h index ca947ec049..2fd09b5c3c 100644 --- a/panda/src/pgraph/colorScaleAttrib.h +++ b/panda/src/pgraph/colorScaleAttrib.h @@ -92,7 +92,8 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ColorScaleAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, + new ColorScaleAttrib(false, LVecBase4(1, 1, 1, 1))); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/colorWriteAttrib.cxx b/panda/src/pgraph/colorWriteAttrib.cxx index 66b7218e35..66e2ab329f 100644 --- a/panda/src/pgraph/colorWriteAttrib.cxx +++ b/panda/src/pgraph/colorWriteAttrib.cxx @@ -89,8 +89,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ColorWriteAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ColorWriteAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ColorWriteAttrib *ta = (const ColorWriteAttrib *)other; return (int)_channels - (int)ta->_channels; } diff --git a/panda/src/pgraph/colorWriteAttrib.h b/panda/src/pgraph/colorWriteAttrib.h index bb77709bc4..a9c4442e14 100644 --- a/panda/src/pgraph/colorWriteAttrib.h +++ b/panda/src/pgraph/colorWriteAttrib.h @@ -85,7 +85,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ColorWriteAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new ColorWriteAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index a79eb0c23d..2c879aba12 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -310,11 +310,6 @@ ConfigVariableInt max_lenses "this can be used as a simple sanity check. Set it larger or " "smaller to suit your needs.")); -ConfigVariableBool default_antialias_enable -("default-antialias-enable", false, - PRC_DESC("Set this true to enable the M_auto antialiasing mode for all " - "nodes by default.")); - ConfigVariableBool polylight_info ("polylight-info", false, PRC_DESC("Set this true to view some info statements regarding the polylight. " diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index a7158b5a86..876eae7485 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -58,7 +58,6 @@ extern EXPCL_PANDA_PGRAPH ConfigVariableBool premunge_data; extern ConfigVariableBool preserve_geom_nodes; extern ConfigVariableBool flatten_geoms; extern EXPCL_PANDA_PGRAPH ConfigVariableInt max_lenses; -extern ConfigVariableBool default_antialias_enable; extern ConfigVariableBool polylight_info; diff --git a/panda/src/pgraph/cullBinAttrib.cxx b/panda/src/pgraph/cullBinAttrib.cxx index 7b4773bfc7..3d7707b93e 100644 --- a/panda/src/pgraph/cullBinAttrib.cxx +++ b/panda/src/pgraph/cullBinAttrib.cxx @@ -84,8 +84,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int CullBinAttrib:: compare_to_impl(const RenderAttrib *other) const { - const CullBinAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const CullBinAttrib *ta = (const CullBinAttrib *)other; + if (_draw_order != ta->_draw_order) { return _draw_order - ta->_draw_order; } diff --git a/panda/src/pgraph/cullBinAttrib.h b/panda/src/pgraph/cullBinAttrib.h index 09430302fb..f1a0809caf 100644 --- a/panda/src/pgraph/cullBinAttrib.h +++ b/panda/src/pgraph/cullBinAttrib.h @@ -73,7 +73,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "CullBinAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new CullBinAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/cullFaceAttrib.cxx b/panda/src/pgraph/cullFaceAttrib.cxx index 88d9586081..8fa8b1c19b 100644 --- a/panda/src/pgraph/cullFaceAttrib.cxx +++ b/panda/src/pgraph/cullFaceAttrib.cxx @@ -154,8 +154,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int CullFaceAttrib:: compare_to_impl(const RenderAttrib *other) const { - const CullFaceAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const CullFaceAttrib *ta = (const CullFaceAttrib *)other; + if (_mode != ta->_mode) { return (int)_mode - (int)ta->_mode; } @@ -199,8 +199,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) CullFaceAttrib:: compose_impl(const RenderAttrib *other) const { - const CullFaceAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const CullFaceAttrib *ta = (const CullFaceAttrib *)other; if (!_reverse && ta->_mode != M_cull_unchanged) { // The normal case (there is nothing funny going on): the second @@ -231,8 +230,7 @@ compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) CullFaceAttrib:: invert_compose_impl(const RenderAttrib *other) const { - const CullFaceAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const CullFaceAttrib *ta = (const CullFaceAttrib *)other; // The invert case is the same as the normal case, except that the // meaning of _reverse is inverted. See compose_impl(), above. diff --git a/panda/src/pgraph/cullFaceAttrib.h b/panda/src/pgraph/cullFaceAttrib.h index 54e55b4173..7ac2427e91 100644 --- a/panda/src/pgraph/cullFaceAttrib.h +++ b/panda/src/pgraph/cullFaceAttrib.h @@ -84,7 +84,8 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "CullFaceAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, + new CullFaceAttrib(M_cull_clockwise, false)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/cullResult.cxx b/panda/src/pgraph/cullResult.cxx index 67a80b4c43..cd27cc29f5 100644 --- a/panda/src/pgraph/cullResult.cxx +++ b/panda/src/pgraph/cullResult.cxx @@ -237,9 +237,8 @@ add_object(CullableObject *object, const CullTraverser *traverser) { } // Check for a special wireframe setting. - const RenderModeAttrib *rmode = (const RenderModeAttrib *) - object->_state->get_attrib(RenderModeAttrib::get_class_slot()); - if (rmode != (const RenderModeAttrib *)NULL) { + const RenderModeAttrib *rmode; + if (object->_state->get_attrib(rmode)) { if (rmode->get_mode() == RenderModeAttrib::M_filled_wireframe) { CullableObject *wireframe_part = new CullableObject(*object); wireframe_part->_state = get_wireframe_overlay_state(rmode); diff --git a/panda/src/pgraph/cullTraverserData.cxx b/panda/src/pgraph/cullTraverserData.cxx index ce665e4806..2fc0f1665c 100644 --- a/panda/src/pgraph/cullTraverserData.cxx +++ b/panda/src/pgraph/cullTraverserData.cxx @@ -93,7 +93,9 @@ apply_transform_and_state(CullTraverser *trav, // Copy the bounding volumes for the frustums so we can // transform them. if (_view_frustum != (GeometricBoundingVolume *)NULL) { - _view_frustum = DCAST(GeometricBoundingVolume, _view_frustum->make_copy()); + _view_frustum = _view_frustum->make_copy()->as_geometric_bounding_volume(); + nassertv(_view_frustum != (GeometricBoundingVolume *)NULL); + _view_frustum->xform(inv_transform->get_mat()); } @@ -106,9 +108,9 @@ apply_transform_and_state(CullTraverser *trav, if (clip_plane_cull) { _cull_planes = _cull_planes->apply_state(trav, this, - DCAST(ClipPlaneAttrib, node_state->get_attrib(ClipPlaneAttrib::get_class_slot())), + (const ClipPlaneAttrib *)node_state->get_attrib(ClipPlaneAttrib::get_class_slot()), DCAST(ClipPlaneAttrib, off_clip_planes), - DCAST(OccluderEffect, node_effects->get_effect(OccluderEffect::get_class_type()))); + (const OccluderEffect *)node_effects->get_effect(OccluderEffect::get_class_type())); } } @@ -122,7 +124,8 @@ is_in_view_impl() { const GeometricBoundingVolume *node_gbv = NULL; if (_view_frustum != (GeometricBoundingVolume *)NULL) { - DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false) + node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume(); + nassertr(node_gbv != (const GeometricBoundingVolume *)NULL, false); int result = _view_frustum->contains(node_gbv); @@ -168,7 +171,8 @@ is_in_view_impl() { if (!_cull_planes->is_empty()) { if (node_gbv == (const GeometricBoundingVolume *)NULL) { - DCAST_INTO_R(node_gbv, _node_reader.get_bounds(), false) + node_gbv = _node_reader.get_bounds()->as_geometric_bounding_volume(); + nassertr(node_gbv != (const GeometricBoundingVolume *)NULL, false); } // Also cull against the current clip planes. diff --git a/panda/src/pgraph/cullableObject.cxx b/panda/src/pgraph/cullableObject.cxx index b842850db7..5ad7a9b5f2 100644 --- a/panda/src/pgraph/cullableObject.cxx +++ b/panda/src/pgraph/cullableObject.cxx @@ -140,8 +140,7 @@ munge_geom(GraphicsStateGuardianBase *gsg, } } - StateMunger *state_munger; - DCAST_INTO_R(state_munger, munger, false); + StateMunger *state_munger = (StateMunger *)munger; _state = state_munger->munge_state(_state); // If there is any animation left in the vertex data after it diff --git a/panda/src/pgraph/depthOffsetAttrib.cxx b/panda/src/pgraph/depthOffsetAttrib.cxx index f30fd68266..8861947048 100644 --- a/panda/src/pgraph/depthOffsetAttrib.cxx +++ b/panda/src/pgraph/depthOffsetAttrib.cxx @@ -95,8 +95,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int DepthOffsetAttrib:: compare_to_impl(const RenderAttrib *other) const { - const DepthOffsetAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other; + if (_offset != ta->_offset) { return _offset - ta->_offset; } @@ -147,8 +147,8 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) DepthOffsetAttrib:: compose_impl(const RenderAttrib *other) const { - const DepthOffsetAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other; + int new_offset = ta->_offset + _offset; DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value); @@ -166,8 +166,8 @@ compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) DepthOffsetAttrib:: invert_compose_impl(const RenderAttrib *other) const { - const DepthOffsetAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const DepthOffsetAttrib *ta = (const DepthOffsetAttrib *)other; + int new_offset = ta->_offset - _offset; DepthOffsetAttrib *attrib = new DepthOffsetAttrib(new_offset, ta->_min_value, ta->_max_value); diff --git a/panda/src/pgraph/depthOffsetAttrib.h b/panda/src/pgraph/depthOffsetAttrib.h index 8ff94e8c2c..626d24707f 100644 --- a/panda/src/pgraph/depthOffsetAttrib.h +++ b/panda/src/pgraph/depthOffsetAttrib.h @@ -107,7 +107,8 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "DepthOffsetAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, + new DepthOffsetAttrib(0, 0, 1)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/depthTestAttrib.cxx b/panda/src/pgraph/depthTestAttrib.cxx index 2c80d010af..f1cb49a429 100644 --- a/panda/src/pgraph/depthTestAttrib.cxx +++ b/panda/src/pgraph/depthTestAttrib.cxx @@ -74,8 +74,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int DepthTestAttrib:: compare_to_impl(const RenderAttrib *other) const { - const DepthTestAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const DepthTestAttrib *ta = (const DepthTestAttrib *)other; + return (int)_mode - (int)ta->_mode; } diff --git a/panda/src/pgraph/depthTestAttrib.h b/panda/src/pgraph/depthTestAttrib.h index a2cea148c7..373fd48723 100644 --- a/panda/src/pgraph/depthTestAttrib.h +++ b/panda/src/pgraph/depthTestAttrib.h @@ -69,7 +69,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "DepthTestAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new DepthTestAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/depthWriteAttrib.cxx b/panda/src/pgraph/depthWriteAttrib.cxx index 8aaa94159e..db0d724a54 100644 --- a/panda/src/pgraph/depthWriteAttrib.cxx +++ b/panda/src/pgraph/depthWriteAttrib.cxx @@ -81,8 +81,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int DepthWriteAttrib:: compare_to_impl(const RenderAttrib *other) const { - const DepthWriteAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const DepthWriteAttrib *ta = (const DepthWriteAttrib *)other; + return (int)_mode - (int)ta->_mode; } diff --git a/panda/src/pgraph/depthWriteAttrib.h b/panda/src/pgraph/depthWriteAttrib.h index a9e601a971..9b6af606a5 100644 --- a/panda/src/pgraph/depthWriteAttrib.h +++ b/panda/src/pgraph/depthWriteAttrib.h @@ -75,7 +75,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "DepthWriteAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new DepthWriteAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/fogAttrib.cxx b/panda/src/pgraph/fogAttrib.cxx index 4c0cd2e0cf..c830277651 100644 --- a/panda/src/pgraph/fogAttrib.cxx +++ b/panda/src/pgraph/fogAttrib.cxx @@ -91,8 +91,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int FogAttrib:: compare_to_impl(const RenderAttrib *other) const { - const FogAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const FogAttrib *ta = (const FogAttrib *)other; // Comparing pointers by subtraction is problematic. Instead of // doing this, we'll just depend on the built-in != and < operators diff --git a/panda/src/pgraph/fogAttrib.h b/panda/src/pgraph/fogAttrib.h index 99afd79cde..0b93e24126 100644 --- a/panda/src/pgraph/fogAttrib.h +++ b/panda/src/pgraph/fogAttrib.h @@ -72,7 +72,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "FogAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new FogAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/lightAttrib.cxx b/panda/src/pgraph/lightAttrib.cxx index 4a0f0f2fe1..c063746824 100644 --- a/panda/src/pgraph/lightAttrib.cxx +++ b/panda/src/pgraph/lightAttrib.cxx @@ -696,8 +696,7 @@ write(ostream &out, int indent_level) const { //////////////////////////////////////////////////////////////////// int LightAttrib:: compare_to_impl(const RenderAttrib *other) const { - const LightAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const LightAttrib *ta = (const LightAttrib *)other; if (_off_all_lights != ta->_off_all_lights) { return (int)_off_all_lights - (int)ta->_off_all_lights; @@ -803,8 +802,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) LightAttrib:: compose_impl(const RenderAttrib *other) const { - const LightAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const LightAttrib *ta = (const LightAttrib *)other; if (ta->_off_all_lights) { // If the other type turns off all lights, it doesn't matter what diff --git a/panda/src/pgraph/lightAttrib.h b/panda/src/pgraph/lightAttrib.h index 393e5436b6..af45e5570f 100644 --- a/panda/src/pgraph/lightAttrib.h +++ b/panda/src/pgraph/lightAttrib.h @@ -162,7 +162,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "LightAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 20, make_default); + _attrib_slot = register_slot(_type_handle, 20, new LightAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/lightRampAttrib.cxx b/panda/src/pgraph/lightRampAttrib.cxx index 399754a69c..3f9c15cfbb 100644 --- a/panda/src/pgraph/lightRampAttrib.cxx +++ b/panda/src/pgraph/lightRampAttrib.cxx @@ -241,8 +241,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int LightRampAttrib:: compare_to_impl(const RenderAttrib *other) const { - const LightRampAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const LightRampAttrib *ta = (const LightRampAttrib *)other; + int compare_result = ((int)_mode - (int)ta->_mode) ; if (compare_result != 0) { return compare_result; diff --git a/panda/src/pgraph/lightRampAttrib.h b/panda/src/pgraph/lightRampAttrib.h index 1fc427c1ea..bb7236cd3f 100644 --- a/panda/src/pgraph/lightRampAttrib.h +++ b/panda/src/pgraph/lightRampAttrib.h @@ -95,7 +95,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "LightRampAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new LightRampAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/materialAttrib.cxx b/panda/src/pgraph/materialAttrib.cxx index 26912d6d09..d77c47a969 100644 --- a/panda/src/pgraph/materialAttrib.cxx +++ b/panda/src/pgraph/materialAttrib.cxx @@ -92,8 +92,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int MaterialAttrib:: compare_to_impl(const RenderAttrib *other) const { - const MaterialAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const MaterialAttrib *ta = (const MaterialAttrib *)other; // Comparing pointers by subtraction is problematic. Instead of // doing this, we'll just depend on the built-in != and < operators diff --git a/panda/src/pgraph/materialAttrib.h b/panda/src/pgraph/materialAttrib.h index 5272375852..f43ec7e07c 100644 --- a/panda/src/pgraph/materialAttrib.h +++ b/panda/src/pgraph/materialAttrib.h @@ -75,7 +75,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "MaterialAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new MaterialAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/renderAttrib.I b/panda/src/pgraph/renderAttrib.I index a32e666c3c..91ab7332a0 100644 --- a/panda/src/pgraph/renderAttrib.I +++ b/panda/src/pgraph/renderAttrib.I @@ -49,20 +49,6 @@ invert_compose(const RenderAttrib *other) const { return invert_compose_impl(other); } -//////////////////////////////////////////////////////////////////// -// Function: RenderAttrib::always_reissue -// Access: Public -// Description: Returns true if the RenderAttrib should be reissued -// to the GSG with every state change, even if it is the -// same pointer as it was before; or false for the -// normal case, to reissue only when the RenderAttrib -// pointer changes. -//////////////////////////////////////////////////////////////////// -INLINE bool RenderAttrib:: -always_reissue() const { - return _always_reissue; -} - //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::compare_to // Access: Published @@ -160,8 +146,7 @@ calc_hash() { // number. See RenderAttribRegistry. //////////////////////////////////////////////////////////////////// INLINE int RenderAttrib:: -register_slot(TypeHandle type_handle, int sort, - RenderAttribRegistry::MakeDefaultFunc *make_default_func) { +register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) { RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr(); - return reg->register_slot(type_handle, sort, make_default_func); + return reg->register_slot(type_handle, sort, default_attrib); } diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 419a9094c9..c7397d0429 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -38,8 +38,6 @@ RenderAttrib() { init_attribs(); } _saved_entry = -1; - - _always_reissue = false; } //////////////////////////////////////////////////////////////////// @@ -435,13 +433,14 @@ return_unique(RenderAttrib *attrib) { return attrib; } - // Save the attrib in a local PointerTo so that it will be freed at - // the end of this function if no one else uses it. - CPT(RenderAttrib) pt_attrib = attrib; - int si = _attribs->find(attrib); if (si != -1) { // There's an equivalent attrib already in the set. Return it. + // If this is a newly created RenderAttrib, though, be sure to + // delete it. + if (attrib->get_ref_count() == 0) { + delete attrib; + } return _attribs->get_key(si); } @@ -456,7 +455,7 @@ return_unique(RenderAttrib *attrib) { // Save the index and return the input attrib. attrib->_saved_entry = si; - return pt_attrib; + return attrib; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index d3d9c67c40..92386cba1e 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -73,8 +73,6 @@ PUBLISHED: virtual bool lower_attrib_can_override() const; public: - INLINE bool always_reissue() const; - virtual bool has_cull_callback() const; virtual bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; @@ -190,14 +188,11 @@ protected: public: INLINE static int register_slot(TypeHandle type_handle, int sort, - RenderAttribRegistry::MakeDefaultFunc *make_default_func); + RenderAttrib *default_attrib); private: void release_new(); -protected: - bool _always_reissue; - public: static void init_attribs(); @@ -218,6 +213,8 @@ private: static PStatCollector _garbage_collect_pcollector; + friend class RenderAttribRegistry; + public: virtual void write_datagram(BamWriter *manager, Datagram &dg); static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); diff --git a/panda/src/pgraph/renderAttribRegistry.I b/panda/src/pgraph/renderAttribRegistry.I index ba8da15691..6b3da8d567 100644 --- a/panda/src/pgraph/renderAttribRegistry.I +++ b/panda/src/pgraph/renderAttribRegistry.I @@ -30,7 +30,7 @@ get_slot(TypeHandle type_handle) const { //////////////////////////////////////////////////////////////////// // Function: RenderAttribRegistry::get_max_slots -// Access: Published +// Access: Published, Static // Description: Returns the maximum number that any slot number is // allowed to grow. Actually, this number will be one // higher than the highest possible slot number. This @@ -41,8 +41,8 @@ get_slot(TypeHandle type_handle) const { // This number will not change during the lifetime of // the application. //////////////////////////////////////////////////////////////////// -INLINE int RenderAttribRegistry:: -get_max_slots() const { +CONSTEXPR int RenderAttribRegistry:: +get_max_slots() { return _max_slots; } @@ -80,6 +80,20 @@ get_slot_sort(int slot) const { return _registry[slot]._sort; } +//////////////////////////////////////////////////////////////////// +// Function: RenderAttribRegistry::get_slot_default +// Access: Published +// Description: Returns the default RenderAttrib object associated +// with slot n. This is the attrib that should be +// applied in the absence of any other attrib of this +// type. +//////////////////////////////////////////////////////////////////// +INLINE const RenderAttrib *RenderAttribRegistry:: +get_slot_default(int slot) const { + nassertr(slot >= 0 && slot < (int)_registry.size(), 0); + return _registry[slot]._default_attrib; +} + //////////////////////////////////////////////////////////////////// // Function: RenderAttribRegistry::get_num_sorted_slots // Access: Published @@ -104,18 +118,6 @@ get_sorted_slot(int n) const { return _sorted_slots[n]; } -//////////////////////////////////////////////////////////////////// -// Function: RenderAttribRegistry::get_array_chain -// Access: Published -// Description: Returns the DeletedBufferChain object that may be -// used to allocated appropriately-sized arrays of -// RenderState::Attribute objects. -//////////////////////////////////////////////////////////////////// -INLINE DeletedBufferChain *RenderAttribRegistry:: -get_array_chain() const { - return _array_chain; -} - //////////////////////////////////////////////////////////////////// // Function: RenderAttribRegistry::get_global_ptr // Access: Published, Static @@ -154,9 +156,21 @@ SortSlots(RenderAttribRegistry *reg) : _reg(reg) { //////////////////////////////////////////////////////////////////// // Function: RenderAttribRegistry::SortSlots::operator () // Access: Public -// Description: +// Description: //////////////////////////////////////////////////////////////////// INLINE bool RenderAttribRegistry::SortSlots:: operator () (int a, int b) const { return _reg->get_slot_sort(a) < _reg->get_slot_sort(b); } + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttribRegistry::RegistryNode::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +INLINE RenderAttribRegistry::RegistryNode:: +RegistryNode(TypeHandle type, int sort, const RenderAttrib *default_attrib) : + _type(type), + _sort(sort), + _default_attrib(default_attrib) { +} diff --git a/panda/src/pgraph/renderAttribRegistry.cxx b/panda/src/pgraph/renderAttribRegistry.cxx index 7dd633fb0e..fc7f8d1076 100644 --- a/panda/src/pgraph/renderAttribRegistry.cxx +++ b/panda/src/pgraph/renderAttribRegistry.cxx @@ -26,37 +26,12 @@ RenderAttribRegistry *RenderAttribRegistry::_global_ptr; //////////////////////////////////////////////////////////////////// RenderAttribRegistry:: RenderAttribRegistry() { - ConfigVariableInt max_attribs - ("max-attribs", SlotMask::get_max_num_bits(), - PRC_DESC("This specifies the maximum number of different RenderAttrib " - "types that may be defined at runtime. Normally you should " - "never need to change this, but if the default value is too " - "low for the number of attribs that Panda actually defines, " - "you may need to raise this number.")); - - // Assign this number once, at startup, and never change it again. - _max_slots = max((int)max_attribs, 1); - if (_max_slots > SlotMask::get_max_num_bits()) { - pgraph_cat->warning() - << "Value for max-attribs too large: cannot exceed " - << SlotMask::get_max_num_bits() - << " in this build. To raise this limit, change the typedef " - << "for SlotMask in renderAttribRegistry.h and recompile.\n"; - - _max_slots = SlotMask::get_max_num_bits(); - } - - // Get a DeletedBufferChain to manage the arrays of RenderAttribs that are - // allocated within each RenderState object. - init_memory_hook(); - _array_chain = memory_hook->get_deleted_chain(_max_slots * sizeof(RenderState::Attribute)); + _registry.reserve(_max_slots); + _sorted_slots.reserve(_max_slots); // Reserve slot 0 for TypeHandle::none(), and for types that exceed // max_slots. - RegistryNode node; - node._sort = 0; - node._make_default_func = NULL; - _registry.push_back(node); + _registry.push_back(RegistryNode(TypeHandle::none(), 0, NULL)); } //////////////////////////////////////////////////////////////////// @@ -86,9 +61,9 @@ RenderAttribRegistry:: // RenderAttribs (that is, those which are more // expensive to change) have lower sort values. // -// The make_default_func pointer is a function that may -// be called to generate a default RenderAttrib to apply -// in the absence of any other attrib of this type. +// The default_attrib pointer should be a newly +// created instance of this attribute that represents +// the default state for this attribute. // // register_slot() is intended to be called at // application start for each different RenderAttrib @@ -96,8 +71,11 @@ RenderAttribRegistry:: // slot number to each one. //////////////////////////////////////////////////////////////////// int RenderAttribRegistry:: -register_slot(TypeHandle type_handle, int sort, - RenderAttribRegistry::MakeDefaultFunc *make_default_func) { +register_slot(TypeHandle type_handle, int sort, RenderAttrib *default_attrib) { + // Sanity check; if this triggers, you either passed a wrong argument, + // or you didn't use the type system correctly. + nassertr(default_attrib->get_type() == type_handle, 0); + int type_index = type_handle.get_index(); while (type_index >= (int)_slots_by_type.size()) { _slots_by_type.push_back(0); @@ -111,19 +89,33 @@ register_slot(TypeHandle type_handle, int sort, int slot = (int)_registry.size(); if (slot >= _max_slots) { pgraph_cat->error() - << "Too many registered RenderAttribs; not registering " + << "Too many registered RenderAttribs; not registering " << type_handle << "\n"; nassertr(false, 0); return 0; } + // Register the default attribute. We don't use return_unique and + // register it even if the state cache is disabled, because we can't read + // the state_cache config variable yet at this time. It probably doesn't + // hurt to have these 32 entries around in the attrib cache. + if (default_attrib != (RenderAttrib *)NULL) { + default_attrib->calc_hash(); + + if (default_attrib->_saved_entry == -1) { + // If this attribute was already registered, something odd is going on. + nassertr(RenderAttrib::_attribs->find(default_attrib) == -1, 0); + default_attrib->_saved_entry = + RenderAttrib::_attribs->store(default_attrib, RenderAttrib::Empty()); + } + + // It effectively lives forever. Might as well make it official. + default_attrib->local_object(); + } + _slots_by_type[type_index] = slot; - RegistryNode node; - node._type = type_handle; - node._sort = sort; - node._make_default_func = make_default_func; - _registry.push_back(node); + _registry.push_back(RegistryNode(type_handle, sort, default_attrib)); _sorted_slots.push_back(slot); ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this)); @@ -143,27 +135,12 @@ set_slot_sort(int slot, int sort) { // Re-sort the slot list. _sorted_slots.clear(); - _sorted_slots.reserve(_registry.size() - 1); for (int i = 1; i < (int)_registry.size(); ++i) { _sorted_slots.push_back(i); } ::sort(_sorted_slots.begin(), _sorted_slots.end(), SortSlots(this)); } -//////////////////////////////////////////////////////////////////// -// Function: RenderAttribRegistry::get_slot_default -// Access: Published -// Description: Returns the default RenderAttrib object associated -// with slot n. This is the attrib that should be -// applied in the absence of any other attrib of this -// type. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) RenderAttribRegistry:: -get_slot_default(int slot) const { - nassertr(slot >= 0 && slot < (int)_registry.size(), 0); - return (*_registry[slot]._make_default_func)(); -} - //////////////////////////////////////////////////////////////////// // Function: RenderAttribRegistry::init_global_ptr // Access: Private, Static diff --git a/panda/src/pgraph/renderAttribRegistry.h b/panda/src/pgraph/renderAttribRegistry.h index 207171c505..7c8f049ddb 100644 --- a/panda/src/pgraph/renderAttribRegistry.h +++ b/panda/src/pgraph/renderAttribRegistry.h @@ -48,24 +48,26 @@ public: // or a DoubleBitMask will be faster on a 32-bit machine. typedef BitMask32 SlotMask; + // Raise this number whenever we add a new attrib. This used to be + // determined at runtime, but it's better to have it as a constexpr. + static const int _max_slots = 29; + int register_slot(TypeHandle type_handle, int sort, - MakeDefaultFunc *make_default_func); + RenderAttrib *default_attrib); PUBLISHED: INLINE int get_slot(TypeHandle type_handle) const; - INLINE int get_max_slots() const; + static CONSTEXPR int get_max_slots(); INLINE int get_num_slots() const; INLINE TypeHandle get_slot_type(int slot) const; INLINE int get_slot_sort(int slot) const; void set_slot_sort(int slot, int sort); - CPT(RenderAttrib) get_slot_default(int slot) const; + INLINE const RenderAttrib *get_slot_default(int slot) const; INLINE int get_num_sorted_slots() const; INLINE int get_sorted_slot(int n) const; - INLINE DeletedBufferChain *get_array_chain() const; - INLINE static RenderAttribRegistry *get_global_ptr(); public: @@ -75,8 +77,6 @@ private: static void init_global_ptr(); private: - int _max_slots; - class SortSlots { public: INLINE SortSlots(RenderAttribRegistry *reg); @@ -86,9 +86,12 @@ private: class RegistryNode { public: + INLINE RegistryNode(TypeHandle type, int sort, + const RenderAttrib *default_attrib); + TypeHandle _type; int _sort; - MakeDefaultFunc *_make_default_func; + const RenderAttrib *_default_attrib; }; typedef pvector Registry; Registry _registry; @@ -96,12 +99,9 @@ private: vector_int _slots_by_type; vector_int _sorted_slots; - DeletedBufferChain *_array_chain; - static RenderAttribRegistry *_global_ptr; }; #include "renderAttribRegistry.I" #endif - diff --git a/panda/src/pgraph/renderModeAttrib.cxx b/panda/src/pgraph/renderModeAttrib.cxx index cb91cdcf6e..83a3fe9282 100644 --- a/panda/src/pgraph/renderModeAttrib.cxx +++ b/panda/src/pgraph/renderModeAttrib.cxx @@ -128,8 +128,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int RenderModeAttrib:: compare_to_impl(const RenderAttrib *other) const { - const RenderModeAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const RenderModeAttrib *ta = (const RenderModeAttrib *)other; + if (_mode != ta->_mode) { return (int)_mode - (int)ta->_mode; } @@ -186,8 +186,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) RenderModeAttrib:: compose_impl(const RenderAttrib *other) const { - const RenderModeAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const RenderModeAttrib *ta = (const RenderModeAttrib *)other; // The special mode M_unchanged means to keep the current mode. Mode mode = ta->get_mode(); diff --git a/panda/src/pgraph/renderModeAttrib.h b/panda/src/pgraph/renderModeAttrib.h index 401b1d0152..1003abc328 100644 --- a/panda/src/pgraph/renderModeAttrib.h +++ b/panda/src/pgraph/renderModeAttrib.h @@ -106,7 +106,8 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "RenderModeAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, + new RenderModeAttrib(M_filled, 1, false)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index 6bce566751..bc7bbad4fe 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -58,35 +58,9 @@ has_cull_callback() const { //////////////////////////////////////////////////////////////////// INLINE CPT(RenderState) RenderState:: make_empty() { - // The empty state is asked for so often, we make it a special case - // and store a pointer forever once we find it the first time. - if (_empty_state == (RenderState *)NULL) { - RenderState *state = new RenderState; - _empty_state = return_unique(state); - } - return _empty_state; } -//////////////////////////////////////////////////////////////////// -// Function: RenderState::make_full_default -// Access: Published, Static -// Description: Returns a RenderState with all possible attributes -// set to their default value. -//////////////////////////////////////////////////////////////////// -INLINE CPT(RenderState) RenderState:: -make_full_default() { - // The empty state is asked for so often, we make it a special case - // and store a pointer forever once we find it the first time. - if (_full_default_state == (RenderState *)NULL) { - RenderState *state = new RenderState; - state->fill_default(); - _full_default_state = return_unique(state); - } - - return _full_default_state; -} - //////////////////////////////////////////////////////////////////// // Function: RenderState::remove_attrib // Access: Published @@ -144,7 +118,7 @@ get_attrib(TypeHandle type) const { // index, or NULL if there is no such RenderAttrib in // the state. //////////////////////////////////////////////////////////////////// -INLINE const RenderAttrib *RenderState:: +ALWAYS_INLINE const RenderAttrib *RenderState:: get_attrib(int slot) const { return _attributes[slot]._attrib; } @@ -161,7 +135,8 @@ get_attrib_def(int slot) const { if (_attributes[slot]._attrib != (RenderAttrib *)NULL) { return _attributes[slot]._attrib; } - return make_full_default()->get_attrib(slot); + RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr(); + return reg->get_slot_default(slot); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index a7cf3ecddc..69a5f502f7 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -40,8 +40,7 @@ LightReMutex *RenderState::_states_lock = NULL; RenderState::States *RenderState::_states = NULL; -CPT(RenderState) RenderState::_empty_state; -CPT(RenderState) RenderState::_full_default_state; +const RenderState *RenderState::_empty_state = NULL; UpdateSeq RenderState::_last_cycle_detect; int RenderState::_garbage_index = 0; @@ -72,20 +71,11 @@ RenderState() : _auto_shader_state(NULL), _lock("RenderState") { - // Allocate the _attributes array. - RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr(); - _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type()); - - // Also make sure each element gets initialized. - for (int i = 0; i < reg->get_max_slots(); ++i) { - new(&_attributes[i]) Attribute(); - } - if (_states == (States *)NULL) { init_states(); } _saved_entry = -1; - _last_mi = _mungers.end(); + _last_mi = -1; _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; @@ -103,17 +93,13 @@ RenderState(const RenderState ©) : _auto_shader_state(NULL), _lock("RenderState") { - // Allocate the _attributes array. - RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr(); - _attributes = (Attribute *)reg->get_array_chain()->allocate(reg->get_max_slots() * sizeof(Attribute), get_class_type()); - - // Also make sure each element gets initialized, as a copy. - for (int i = 0; i < reg->get_max_slots(); ++i) { - new(&_attributes[i]) Attribute(copy._attributes[i]); + // Copy over the attributes. + for (int i = 0; i < RenderAttribRegistry::_max_slots; ++i) { + _attributes[i] = copy._attributes[i]; } _saved_entry = -1; - _last_mi = _mungers.end(); + _last_mi = -1; _cache_stats.add_num_states(1); _read_overrides = NULL; _generated_shader = NULL; @@ -159,14 +145,6 @@ RenderState:: // longer true now, probably we've been double-deleted. nassertv(get_ref_count() == 0); _cache_stats.add_num_states(-1); - - // Free the _attributes array. - RenderAttribRegistry *reg = RenderAttribRegistry::get_global_ptr(); - for (int i = 0; i < reg->get_max_slots(); ++i) { - _attributes[i].~Attribute(); - } - reg->get_array_chain()->deallocate(_attributes, get_class_type()); - _attributes = NULL; } //////////////////////////////////////////////////////////////////// @@ -360,7 +338,7 @@ make(const RenderAttrib *attrib1, CPT(RenderState) RenderState:: make(const RenderAttrib * const *attrib, int num_attribs, int override) { if (num_attribs == 0) { - return make_empty(); + return _empty_state; } RenderState *state = new RenderState; for (int i = 0; i < num_attribs; i++) { @@ -490,7 +468,7 @@ invert_compose(const RenderState *other) const { if (other == this) { // a->invert_compose(a) always produces identity. - return make_empty(); + return _empty_state; } if (!state_cache) { @@ -633,7 +611,7 @@ remove_attrib(int slot) const { // Will this bring us down to the empty state? if (_filled_slots.get_num_on_bits() == 1) { - return make_empty(); + return _empty_state; } RenderState *new_state = new RenderState(*this); @@ -1110,7 +1088,7 @@ clear_munger_cache() { } RenderState *state = (RenderState *)(_states->get_key(si)); state->_mungers.clear(); - state->_last_mi = state->_mungers.end(); + state->_last_mi = -1; } } @@ -1314,17 +1292,17 @@ validate_states() { //////////////////////////////////////////////////////////////////// int RenderState:: get_geom_rendering(int geom_rendering) const { - const RenderModeAttrib *render_mode = DCAST(RenderModeAttrib, get_attrib(RenderModeAttrib::get_class_slot())); - const TexGenAttrib *tex_gen = DCAST(TexGenAttrib, get_attrib(TexGenAttrib::get_class_slot())); - const TexMatrixAttrib *tex_matrix = DCAST(TexMatrixAttrib, get_attrib(TexMatrixAttrib::get_class_slot())); + const RenderModeAttrib *render_mode; + const TexGenAttrib *tex_gen; + const TexMatrixAttrib *tex_matrix; - if (render_mode != (const RenderModeAttrib *)NULL) { + if (get_attrib(render_mode)) { geom_rendering = render_mode->get_geom_rendering(geom_rendering); } - if (tex_gen != (const TexGenAttrib *)NULL) { + if (get_attrib(tex_gen)) { geom_rendering = tex_gen->get_geom_rendering(geom_rendering); } - if (tex_matrix != (const TexMatrixAttrib *)NULL) { + if (get_attrib(tex_matrix)) { geom_rendering = tex_matrix->get_geom_rendering(geom_rendering); } @@ -1507,7 +1485,7 @@ return_new(RenderState *state) { //////////////////////////////////////////////////////////////////// CPT(RenderState) RenderState:: return_unique(RenderState *state) { - nassertr(state != (RenderState *)NULL, state); + nassertr(state != (RenderState *)NULL, NULL); if (!state_cache) { return state; @@ -1523,14 +1501,10 @@ return_unique(RenderState *state) { if (state->_saved_entry != -1) { // This state is already in the cache. - //nassertr(_states->find(state) == state->_saved_entry, state); + //nassertr(_states->find(state) == state->_saved_entry, pt_state); return state; } - // Save the state in a local PointerTo so that it will be freed at - // the end of this function if no one else uses it. - CPT(RenderState) pt_state = state; - // Ensure each of the individual attrib pointers has been uniquified // before we add the state to the cache. if (!uniquify_attribs && !state->is_empty()) { @@ -1538,7 +1512,7 @@ return_unique(RenderState *state) { int slot = mask.get_lowest_on_bit(); while (slot >= 0) { Attribute &attrib = state->_attributes[slot]; - nassertr(attrib._attrib != (RenderAttrib *)NULL, state); + nassertd(attrib._attrib != (RenderAttrib *)NULL) continue; attrib._attrib = attrib._attrib->get_unique(); mask.clear_bit(slot); slot = mask.get_lowest_on_bit(); @@ -1548,6 +1522,11 @@ return_unique(RenderState *state) { int si = _states->find(state); if (si != -1) { // There's an equivalent state already in the set. Return it. + // The state that was passed may be newly created and therefore + // may not be automatically deleted. Do that if necessary. + if (state->get_ref_count() == 0) { + delete state; + } return _states->get_key(si); } @@ -1562,7 +1541,7 @@ return_unique(RenderState *state) { // Save the index and return the input state. state->_saved_entry = si; - return pt_state; + return state; } //////////////////////////////////////////////////////////////////// @@ -1621,15 +1600,6 @@ do_compose(const RenderState *other) const { slot = mask.get_lowest_on_bit(); } - // If we have any ShaderAttrib with auto-shader enabled, - // remove any shader inputs on it. This is a workaround for an - // issue that makes the shader-generator regenerate the shader - // every time a shader input changes. - CPT(ShaderAttrib) sattrib = DCAST(ShaderAttrib, new_state->get_attrib_def(ShaderAttrib::get_class_slot())); - if (sattrib->auto_shader()) { - sattrib = DCAST(ShaderAttrib, sattrib->clear_all_shader_inputs()); - } - return return_new(new_state); } @@ -1660,9 +1630,8 @@ do_invert_compose(const RenderState *other) const { } else if (b._attrib == NULL) { // A wins. Invert it. - CPT(RenderState) full_default = make_full_default(); - CPT(RenderAttrib) default_attrib = full_default->get_attrib(slot); - result.set(a._attrib->invert_compose(default_attrib), 0); + RenderAttribRegistry *reg = RenderAttribRegistry::quick_get_global_ptr(); + result.set(a._attrib->invert_compose(reg->get_slot_default(slot)), 0); } else { // Both are good. (Overrides are not used in invert_compose.) @@ -2162,8 +2131,14 @@ init_states() { _states_lock = new LightReMutex("RenderState::_states_lock"); _cache_stats.init(); nassertv(Thread::get_current_thread() == Thread::get_main_thread()); -} + // Initialize the empty state object as well. It is used so often + // that it is declared globally, and lives forever. + RenderState *state = new RenderState; + state->local_object(); + state->_saved_entry = _states->store(state, Empty()); + _empty_state = state; +} //////////////////////////////////////////////////////////////////// // Function: RenderState::register_with_read_factory diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 4a59fb5302..bd97d7594e 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -31,10 +31,11 @@ #include "lightMutex.h" #include "deletedChain.h" #include "simpleHashMap.h" +#include "weakKeyHashMap.h" #include "cacheStats.h" #include "renderAttribRegistry.h" +#include "graphicsStateGuardianBase.h" -class GraphicsStateGuardianBase; class FactoryParams; class ShaderAttrib; @@ -76,7 +77,6 @@ PUBLISHED: bool cull_callback(CullTraverser *trav, const CullTraverserData &data) const; INLINE static CPT(RenderState) make_empty(); - INLINE static CPT(RenderState) make_full_default(); static CPT(RenderState) make(const RenderAttrib *attrib, int override = 0); static CPT(RenderState) make(const RenderAttrib *attrib1, const RenderAttrib *attrib2, int override = 0); @@ -104,7 +104,7 @@ PUBLISHED: INLINE bool has_attrib(TypeHandle type) const; INLINE bool has_attrib(int slot) const; INLINE const RenderAttrib *get_attrib(TypeHandle type) const; - INLINE const RenderAttrib *get_attrib(int slot) const; + ALWAYS_INLINE const RenderAttrib *get_attrib(int slot) const; INLINE const RenderAttrib *get_attrib_def(int slot) const; INLINE int get_override(TypeHandle type) const; INLINE int get_override(int slot) const; @@ -233,8 +233,7 @@ private: }; typedef SimpleHashMap > States; static States *_states; - static CPT(RenderState) _empty_state; - static CPT(RenderState) _full_default_state; + static const RenderState *_empty_state; // This iterator records the entry corresponding to this // RenderState object in the above global set. We keep the index @@ -270,9 +269,9 @@ private: // since there are likely to be far fewer GSG's than RenderStates. // The code to manage this map lives in // GraphicsStateGuardian::get_geom_munger(). - typedef pmap Mungers; + typedef WeakKeyHashMap Mungers; mutable Mungers _mungers; - mutable Mungers::const_iterator _last_mi; + mutable int _last_mi; // This is used to mark nodes as we visit them to detect cycles. UpdateSeq _cycle_detect; @@ -307,7 +306,7 @@ private: CPT(RenderAttrib) _attrib; int _override; }; - Attribute *_attributes; + Attribute _attributes[RenderAttribRegistry::_max_slots]; // We also store a bitmask of the non-NULL attributes in the above // array. This is redundant, but it is a useful cache. diff --git a/panda/src/pgraph/rescaleNormalAttrib.I b/panda/src/pgraph/rescaleNormalAttrib.I index ed9633bf81..2825f44431 100644 --- a/panda/src/pgraph/rescaleNormalAttrib.I +++ b/panda/src/pgraph/rescaleNormalAttrib.I @@ -25,6 +25,19 @@ RescaleNormalAttrib(RescaleNormalAttrib::Mode mode) : { } +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::make_default +// Access: Published, Static +// Description: Constructs a RescaleNormalAttrib object that's +// suitable for putting at the top of a scene graph. +// This will contain whatever attrib was suggested by +// the user's rescale-normals Config variable. +//////////////////////////////////////////////////////////////////// +INLINE CPT(RenderAttrib) RescaleNormalAttrib:: +make_default() { + return RenderAttribRegistry::quick_get_global_ptr()->get_slot_default(_attrib_slot); +} + //////////////////////////////////////////////////////////////////// // Function: RescaleNormalAttrib::get_mode // Access: Published diff --git a/panda/src/pgraph/rescaleNormalAttrib.cxx b/panda/src/pgraph/rescaleNormalAttrib.cxx index 7c20896810..33de69efe7 100644 --- a/panda/src/pgraph/rescaleNormalAttrib.cxx +++ b/panda/src/pgraph/rescaleNormalAttrib.cxx @@ -25,18 +25,7 @@ TypeHandle RescaleNormalAttrib::_type_handle; int RescaleNormalAttrib::_attrib_slot; - -// This variable is defined here instead of in config_pgraph.cxx, -// because it depends on rescaleNormalAttrib.h having already been -// included. -static ConfigVariableEnum rescale_normals -("rescale-normals", RescaleNormalAttrib::M_auto, - PRC_DESC("Specifies the kind of RescaleNormalAttrib that should be " - "created for the top of the scene graph. This can automatically " - "ensure that your lighting normals are unit-length, which may be " - "particularly necessary in the presence of scales in the scene " - "graph. Turning it off ('none') may produce a small performance " - "benefit.")); +CPT(RenderAttrib) RescaleNormalAttrib::_attribs[RescaleNormalAttrib::M_auto + 1]; //////////////////////////////////////////////////////////////////// // Function: RescaleNormalAttrib::make @@ -47,28 +36,18 @@ static ConfigVariableEnum rescale_normals //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) RescaleNormalAttrib:: make(RescaleNormalAttrib::Mode mode) { - RescaleNormalAttrib *attrib = new RescaleNormalAttrib(mode); - return return_new(attrib); -} - -//////////////////////////////////////////////////////////////////// -// Function: RescaleNormalAttrib::make_default -// Access: Published, Static -// Description: Constructs a RescaleNoramlAttrib object that's -// suitable for putting at the top of a scene graph. -// This will contain whatever attrib was suggested by -// the user's rescale-normals Config variable. -//////////////////////////////////////////////////////////////////// -CPT(RenderAttrib) RescaleNormalAttrib:: -make_default() { - RescaleNormalAttrib *attrib = new RescaleNormalAttrib(rescale_normals); - return return_new(attrib); + if (_attribs[mode].is_null()) { + // Don't bother with return_new, since this is the only way a + // RescaleNormalAttrib can be made anyway. + _attribs[mode] = new RescaleNormalAttrib(mode); + } + return _attribs[mode]; } //////////////////////////////////////////////////////////////////// // Function: RescaleNormalAttrib::output // Access: Public, Virtual -// Description: +// Description: //////////////////////////////////////////////////////////////////// void RescaleNormalAttrib:: output(ostream &out) const { @@ -92,8 +71,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int RescaleNormalAttrib:: compare_to_impl(const RenderAttrib *other) const { - const RescaleNormalAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const RescaleNormalAttrib *ta = (const RescaleNormalAttrib *)other; return (int)_mode - (int)ta->_mode; } @@ -187,6 +165,35 @@ fillin(DatagramIterator &scan, BamReader *manager) { _mode = (Mode)scan.get_int8(); } +//////////////////////////////////////////////////////////////////// +// Function: RescaleNormalAttrib::init_type +// Access: Public, Static +// Description: +//////////////////////////////////////////////////////////////////// +void RescaleNormalAttrib:: +init_type() { + RenderAttrib::init_type(); + register_type(_type_handle, "RescaleNormalAttrib", + RenderAttrib::get_class_type()); + + // This is defined here, since we have otherwise no guarantee that + // the config var has already been constructed by the time we call + // init_type() at static init time. + static ConfigVariableEnum rescale_normals + ("rescale-normals", RescaleNormalAttrib::M_auto, + PRC_DESC("Specifies the kind of RescaleNormalAttrib that should be " + "created for the top of the scene graph. This can automatically " + "ensure that your lighting normals are unit-length, which may be " + "particularly necessary in the presence of scales in the scene " + "graph. Turning it off ('none') may produce a small performance " + "benefit.")); + + Mode mode = rescale_normals; + RescaleNormalAttrib *attrib = new RescaleNormalAttrib(mode); + _attrib_slot = register_slot(_type_handle, 100, attrib); + _attribs[mode] = attrib; +} + //////////////////////////////////////////////////////////////////// // Function: RescaleNormalAttrib::Mode output operator // Description: diff --git a/panda/src/pgraph/rescaleNormalAttrib.h b/panda/src/pgraph/rescaleNormalAttrib.h index 04f5575614..4634d504bb 100644 --- a/panda/src/pgraph/rescaleNormalAttrib.h +++ b/panda/src/pgraph/rescaleNormalAttrib.h @@ -49,7 +49,7 @@ private: PUBLISHED: static CPT(RenderAttrib) make(Mode mode); - static CPT(RenderAttrib) make_default(); + INLINE static CPT(RenderAttrib) make_default(); INLINE Mode get_mode() const; @@ -64,6 +64,10 @@ protected: private: Mode _mode; + // There are so few possible combinations, and it's used fairly often, so + // we keep an array of the possible attributes. + static CPT(RenderAttrib) _attribs[M_auto + 1]; + PUBLISHED: static int get_class_slot() { return _attrib_slot; @@ -79,17 +83,12 @@ public: protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); void fillin(DatagramIterator &scan, BamReader *manager); - + public: static TypeHandle get_class_type() { return _type_handle; } - static void init_type() { - RenderAttrib::init_type(); - register_type(_type_handle, "RescaleNormalAttrib", - RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); - } + static void init_type(); virtual TypeHandle get_type() const { return get_class_type(); } diff --git a/panda/src/pgraph/scissorAttrib.cxx b/panda/src/pgraph/scissorAttrib.cxx index 24b5111f99..29814d9668 100644 --- a/panda/src/pgraph/scissorAttrib.cxx +++ b/panda/src/pgraph/scissorAttrib.cxx @@ -113,8 +113,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ScissorAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ScissorAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ScissorAttrib *ta = (const ScissorAttrib *)other; if (!_off && !ta->_off) { return 0; @@ -173,8 +172,7 @@ compose_impl(const RenderAttrib *other) const { return other; } - const ScissorAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ScissorAttrib *ta = (const ScissorAttrib *)other; if (ta->_off) { return this; diff --git a/panda/src/pgraph/scissorAttrib.h b/panda/src/pgraph/scissorAttrib.h index e3e63f6685..88475a50fc 100644 --- a/panda/src/pgraph/scissorAttrib.h +++ b/panda/src/pgraph/scissorAttrib.h @@ -89,7 +89,10 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ScissorAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + + ScissorAttrib *attrib = new ScissorAttrib(LVecBase4(0, 1, 0, 1)); + attrib->_off = true; + _attrib_slot = register_slot(_type_handle, 100, attrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/shadeModelAttrib.cxx b/panda/src/pgraph/shadeModelAttrib.cxx index 1787ec3411..24f6ef3585 100644 --- a/panda/src/pgraph/shadeModelAttrib.cxx +++ b/panda/src/pgraph/shadeModelAttrib.cxx @@ -84,8 +84,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int ShadeModelAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ShadeModelAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ShadeModelAttrib *ta = (const ShadeModelAttrib *)other; return (int)_mode - (int)ta->_mode; } @@ -125,8 +124,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) ShadeModelAttrib:: compose_impl(const RenderAttrib *other) const { - const ShadeModelAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const ShadeModelAttrib *ta = (const ShadeModelAttrib *)other; Mode mode = ta->get_mode(); return make(mode); diff --git a/panda/src/pgraph/shadeModelAttrib.h b/panda/src/pgraph/shadeModelAttrib.h index b120b5555b..b2edff59ed 100644 --- a/panda/src/pgraph/shadeModelAttrib.h +++ b/panda/src/pgraph/shadeModelAttrib.h @@ -77,7 +77,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ShadeModelAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new ShadeModelAttrib(M_smooth)); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/shaderAttrib.cxx b/panda/src/pgraph/shaderAttrib.cxx index 82f05cfbad..21145802d6 100644 --- a/panda/src/pgraph/shaderAttrib.cxx +++ b/panda/src/pgraph/shaderAttrib.cxx @@ -542,8 +542,7 @@ get_shader() const { //////////////////////////////////////////////////////////////////// int ShaderAttrib:: compare_to_impl(const RenderAttrib *other) const { - const ShaderAttrib *that; - DCAST_INTO_R(that, other, 0); + const ShaderAttrib *that = (const ShaderAttrib *)other; if (this->_shader != that->_shader) { return (this->_shader < that->_shader) ? -1 : 1; @@ -643,8 +642,8 @@ get_hash_impl() const { CPT(RenderAttrib) ShaderAttrib:: compose_impl(const RenderAttrib *other) const { ShaderAttrib *attr = new ShaderAttrib(*this); - const ShaderAttrib *over; - DCAST_INTO_R(over, other, 0); + const ShaderAttrib *over = (const ShaderAttrib *)other; + // Update the shader portion. if (over->_has_shader) { if ((attr->_has_shader == false) || diff --git a/panda/src/pgraph/shaderAttrib.h b/panda/src/pgraph/shaderAttrib.h index d146e80bab..fd6b26dffc 100644 --- a/panda/src/pgraph/shaderAttrib.h +++ b/panda/src/pgraph/shaderAttrib.h @@ -156,7 +156,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "ShaderAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 10, make_default); + _attrib_slot = register_slot(_type_handle, 10, new ShaderAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/stateMunger.cxx b/panda/src/pgraph/stateMunger.cxx index e6ef2321ff..4ab909127b 100644 --- a/panda/src/pgraph/stateMunger.cxx +++ b/panda/src/pgraph/stateMunger.cxx @@ -32,18 +32,15 @@ StateMunger:: //////////////////////////////////////////////////////////////////// CPT(RenderState) StateMunger:: munge_state(const RenderState *state) { - WCPT(RenderState) pt_state = state; - - StateMap::iterator mi = _state_map.find(pt_state); - if (mi != _state_map.end()) { - if (!(*mi).first.was_deleted() && - !(*mi).second.was_deleted()) { - return (*mi).second.p(); + int mi = _state_map.find(state); + if (mi != -1) { + if (!_state_map.get_data(mi).was_deleted()) { + return _state_map.get_data(mi).p(); } } CPT(RenderState) result = munge_state_impl(state); - _state_map[pt_state] = result; + _state_map.store(state, result.p()); return result; } diff --git a/panda/src/pgraph/stateMunger.h b/panda/src/pgraph/stateMunger.h index 3385890deb..3a317ffa14 100644 --- a/panda/src/pgraph/stateMunger.h +++ b/panda/src/pgraph/stateMunger.h @@ -18,7 +18,7 @@ #include "pandabase.h" #include "geomMunger.h" #include "renderState.h" -#include "weakPointerTo.h" +#include "weakKeyHashMap.h" //////////////////////////////////////////////////////////////////// // Class : StateMunger @@ -36,7 +36,7 @@ public: protected: virtual CPT(RenderState) munge_state_impl(const RenderState *state); - typedef pmap< WCPT(RenderState), WCPT(RenderState) > StateMap; + typedef WeakKeyHashMap StateMap; StateMap _state_map; public: diff --git a/panda/src/pgraph/stencilAttrib.cxx b/panda/src/pgraph/stencilAttrib.cxx index 07657fbf96..481626047e 100644 --- a/panda/src/pgraph/stencilAttrib.cxx +++ b/panda/src/pgraph/stencilAttrib.cxx @@ -311,8 +311,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int StencilAttrib:: compare_to_impl(const RenderAttrib *other) const { - const StencilAttrib *sa; - DCAST_INTO_R(sa, other, 0); + const StencilAttrib *sa = (const StencilAttrib *)other; int a; int b; diff --git a/panda/src/pgraph/stencilAttrib.h b/panda/src/pgraph/stencilAttrib.h index 5e456b29d6..ea19401ccd 100644 --- a/panda/src/pgraph/stencilAttrib.h +++ b/panda/src/pgraph/stencilAttrib.h @@ -175,7 +175,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "StencilAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new StencilAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/texGenAttrib.cxx b/panda/src/pgraph/texGenAttrib.cxx index ca22d7942c..5cd538f600 100644 --- a/panda/src/pgraph/texGenAttrib.cxx +++ b/panda/src/pgraph/texGenAttrib.cxx @@ -297,8 +297,7 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int TexGenAttrib:: compare_to_impl(const RenderAttrib *other) const { - const TexGenAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TexGenAttrib *ta = (const TexGenAttrib *)other; Stages::const_iterator ai, bi; ai = _stages.begin(); @@ -383,8 +382,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexGenAttrib:: compose_impl(const RenderAttrib *other) const { - const TexGenAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TexGenAttrib *ta = (const TexGenAttrib *)other; // The composition is the union of the two attribs. In the case // when a stage is in both attribs, we compose the stages. @@ -441,8 +439,7 @@ compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexGenAttrib:: invert_compose_impl(const RenderAttrib *other) const { - const TexGenAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TexGenAttrib *ta = (const TexGenAttrib *)other; // The inverse composition works a lot like the composition, except // we invert the ai stages. diff --git a/panda/src/pgraph/texGenAttrib.h b/panda/src/pgraph/texGenAttrib.h index 71840a83aa..be92aff106 100644 --- a/panda/src/pgraph/texGenAttrib.h +++ b/panda/src/pgraph/texGenAttrib.h @@ -139,7 +139,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "TexGenAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new TexGenAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/texMatrixAttrib.cxx b/panda/src/pgraph/texMatrixAttrib.cxx index 7afe6f9014..26dad659e3 100644 --- a/panda/src/pgraph/texMatrixAttrib.cxx +++ b/panda/src/pgraph/texMatrixAttrib.cxx @@ -247,9 +247,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int TexMatrixAttrib:: compare_to_impl(const RenderAttrib *other) const { - const TexMatrixAttrib *ta; - DCAST_INTO_R(ta, other, 0); - + const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other; + Stages::const_iterator ai, bi; ai = _stages.begin(); bi = ta->_stages.begin(); @@ -326,8 +325,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: compose_impl(const RenderAttrib *other) const { - const TexMatrixAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other; // The composition is the union of the two attribs. In the case // when a stage is in both attribs, we compose the stages. @@ -396,8 +394,7 @@ compose_impl(const RenderAttrib *other) const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TexMatrixAttrib:: invert_compose_impl(const RenderAttrib *other) const { - const TexMatrixAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TexMatrixAttrib *ta = (const TexMatrixAttrib *)other; // The inverse composition works a lot like the composition, except // we invert the ai stages. diff --git a/panda/src/pgraph/texMatrixAttrib.h b/panda/src/pgraph/texMatrixAttrib.h index a6a29e155a..a1e6d90c94 100644 --- a/panda/src/pgraph/texMatrixAttrib.h +++ b/panda/src/pgraph/texMatrixAttrib.h @@ -123,7 +123,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "TexMatrixAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new TexMatrixAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index bb7a4808e5..6de455327e 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -507,8 +507,7 @@ cull_callback(CullTraverser *trav, const CullTraverserData &data) const { //////////////////////////////////////////////////////////////////// int TextureAttrib:: compare_to_impl(const RenderAttrib *other) const { - const TextureAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TextureAttrib *ta = (const TextureAttrib *)other; if (_off_all_stages != ta->_off_all_stages) { return (int)_off_all_stages - (int)ta->_off_all_stages; @@ -664,8 +663,7 @@ get_hash_impl() const { //////////////////////////////////////////////////////////////////// CPT(RenderAttrib) TextureAttrib:: compose_impl(const RenderAttrib *other) const { - const TextureAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TextureAttrib *ta = (const TextureAttrib *)other; if (ta->_off_all_stages) { // If the other type turns off all stages, it doesn't matter what diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 0c27a018eb..a5f5ed9bf6 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -179,7 +179,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "TextureAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 30, make_default); + _attrib_slot = register_slot(_type_handle, 30, new TextureAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/pgraph/transparencyAttrib.cxx b/panda/src/pgraph/transparencyAttrib.cxx index 2b20559bc8..b2cb9cd75f 100644 --- a/panda/src/pgraph/transparencyAttrib.cxx +++ b/panda/src/pgraph/transparencyAttrib.cxx @@ -101,8 +101,8 @@ output(ostream &out) const { //////////////////////////////////////////////////////////////////// int TransparencyAttrib:: compare_to_impl(const RenderAttrib *other) const { - const TransparencyAttrib *ta; - DCAST_INTO_R(ta, other, 0); + const TransparencyAttrib *ta = (const TransparencyAttrib *)other; + return (int)_mode - (int)ta->_mode; } diff --git a/panda/src/pgraph/transparencyAttrib.h b/panda/src/pgraph/transparencyAttrib.h index b653641207..1831db44f3 100644 --- a/panda/src/pgraph/transparencyAttrib.h +++ b/panda/src/pgraph/transparencyAttrib.h @@ -92,7 +92,7 @@ public: RenderAttrib::init_type(); register_type(_type_handle, "TransparencyAttrib", RenderAttrib::get_class_type()); - _attrib_slot = register_slot(_type_handle, 100, make_default); + _attrib_slot = register_slot(_type_handle, 100, new TransparencyAttrib); } virtual TypeHandle get_type() const { return get_class_type(); diff --git a/panda/src/putil/p3putil_composite2.cxx b/panda/src/putil/p3putil_composite2.cxx index 1f3b46718d..a4ce5c9cfc 100644 --- a/panda/src/putil/p3putil_composite2.cxx +++ b/panda/src/putil/p3putil_composite2.cxx @@ -23,6 +23,7 @@ #include "vector_typedWritable.cxx" #include "vector_ushort.cxx" #include "vector_writable.cxx" +#include "weakKeyHashMap.cxx" #include "writableConfigurable.cxx" #include "writableParam.cxx" diff --git a/panda/src/putil/weakKeyHashMap.I b/panda/src/putil/weakKeyHashMap.I new file mode 100644 index 0000000000..05f9f4266d --- /dev/null +++ b/panda/src/putil/weakKeyHashMap.I @@ -0,0 +1,714 @@ +// Filename: weakKeyHashMap.I +// Created by: rdb (13Jul15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::Constructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE WeakKeyHashMap:: +WeakKeyHashMap() : + _table(NULL), + _deleted_chain(NULL), + _table_size(0), + _num_entries(0) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::Destructor +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +INLINE WeakKeyHashMap:: +~WeakKeyHashMap() { + clear(); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::swap +// Access: Public +// Description: Quickly exchanges the contents of this map and the +// other map. +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakKeyHashMap:: +swap(WeakKeyHashMap &other) { + TableEntry *t0 = _table; + _table = other._table; + other._table = t0; + + DeletedBufferChain *t1 = _deleted_chain; + _deleted_chain = other._deleted_chain; + other._deleted_chain = t1; + + size_t t2 = _table_size; + _table_size = other._table_size; + other._table_size = t2; + + size_t t3 = _num_entries; + _num_entries = other._num_entries; + other._num_entries = t3; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::find +// Access: Public +// Description: Searches for the indicated key in the table. Returns +// its index number if it is found, or -1 if it is not +// present in the table. +//////////////////////////////////////////////////////////////////// +template +int WeakKeyHashMap:: +find(const Key *key) const { + if (_table_size == 0) { + // Special case: the table is empty. + return -1; + } + + size_t index = get_hash(key); + if (!has_element(index)) { + return -1; + } + if (is_element(index, key)) { + return index; + } + + // There was some other key at the hashed slot. That's a hash + // conflict. Maybe our entry was recorded at a later slot position; + // scan the subsequent positions until we find the entry or an + // unused slot, indicating the end of the scan. + size_t i = index; + i = (i + 1) & (_table_size - 1); + while (i != index && has_element(i)) { + if (is_element(i, key)) { + return i; + } + i = (i + 1) & (_table_size - 1); + } + + // The key is not in the table. + return -1; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::store +// Access: Public +// Description: Records the indicated key/data pair in the map. If +// the key was already present, silently replaces it. +// Returns the index at which it was stored. +//////////////////////////////////////////////////////////////////// +template +int WeakKeyHashMap:: +store(const Key *key, const Value &data) { + if (_table_size == 0) { + // Special case: the first key in an empty table. + nassertr(_num_entries == 0, -1); + new_table(); + size_t index = get_hash(key); + store_new_element(index, key, data); + ++_num_entries; +#ifdef _DEBUG + nassertr(validate(), index); +#endif + return index; + } + + size_t index = get_hash(key); + if (!has_element(index)) { + // This element is not already in the map; add it. + if (consider_expand_table()) { + return store(key, data); + } + store_new_element(index, key, data); + ++_num_entries; +#ifdef _DEBUG + nassertr(validate(), index); +#endif + return index; + } + if (is_element(index, key)) { + // This element is already in the map; replace the data at that + // key. + _table[index]._data = data; +#ifdef _DEBUG + nassertr(validate(), index); +#endif + return index; + } + + // There was some other key at the hashed slot. That's a hash + // conflict. Record this entry at a later position. + size_t i = index; + i = (i + 1) & (_table_size - 1); + while (i != index) { + if (!has_element(i)) { + if (consider_expand_table()) { + return store(key, data); + } + store_new_element(i, key, data); + ++_num_entries; +#ifdef _DEBUG + nassertr(validate(), i); +#endif + return i; + } + if (is_element(i, key)) { + _table[i]._data = data; +#ifdef _DEBUG + nassertr(validate(), i); +#endif + return i; + } + i = (i + 1) & (_table_size - 1); + } + + // Shouldn't get here unless _num_entries == _table_size, which + // shouldn't be possible due to consider_expand_table(). + nassertr(false, -1); + return -1; // To satisfy compiler +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::remove +// Access: Public +// Description: Removes the indicated key and its associated data +// from the table. Returns true if the key was removed, +// false if it was not present. +//////////////////////////////////////////////////////////////////// +template +INLINE bool WeakKeyHashMap:: +remove(const Key *key) { + int index = find(key); + if (index == -1) { + return false; + } + remove_element(index); + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::clear +// Access: Public +// Description: Completely empties the table. +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +clear() { + if (_table_size != 0) { + for (size_t i = 0; i < _table_size; ++i) { + if (get_exists_array()[i] != 0) { + clear_element(i); + } + } + + _deleted_chain->deallocate(_table, TypeHandle::none()); + _table = NULL; + _deleted_chain = NULL; + _table_size = 0; + _num_entries = 0; + } +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::operator [] +// Access: Public +// Description: Returns a modifiable reference to the data associated +// with the indicated key, or creates a new data entry +// and returns its reference. +//////////////////////////////////////////////////////////////////// +template +INLINE Value &WeakKeyHashMap:: +operator [] (const Key *key) { + int index = find(key); + if (index == -1) { + index = store(key, Value()); + } + return modify_data(index); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_size +// Access: Public +// Description: Returns the total number of slots in the table. +//////////////////////////////////////////////////////////////////// +template +INLINE int WeakKeyHashMap:: +get_size() const { + return _table_size; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::has_element +// Access: Public +// Description: Returns true if there is an element stored in the nth +// slot, false otherwise. +// +// n should be in the range 0 <= n < get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE bool WeakKeyHashMap:: +has_element(int n) const { + nassertr(n >= 0 && n < (int)_table_size, false); + return (get_exists_array()[n] != 0 && !_table[n]._key.was_deleted()); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_key +// Access: Public +// Description: Returns the key in the nth slot of the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE const Key *WeakKeyHashMap:: +get_key(int n) const { + nassertr(has_element(n), _table[n]._key); + return _table[n]._key; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_data +// Access: Public +// Description: Returns the data in the nth slot of the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE const Value &WeakKeyHashMap:: +get_data(int n) const { + nassertr(has_element(n), _table[n]._data); + return _table[n]._data; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::modify_data +// Access: Public +// Description: Returns a modifiable reference to the data in the nth +// slot of the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE Value &WeakKeyHashMap:: +modify_data(int n) { + nassertr(has_element(n), _table[n]._data); + return _table[n]._data; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::set_data +// Access: Public +// Description: Changes the data for the nth slot of the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakKeyHashMap:: +set_data(int n, const Value &data) { + nassertv(has_element(n)); + _table[n]._data = data; +} + +#ifdef USE_MOVE_SEMANTICS +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::set_data +// Access: Public +// Description: Changes the data for the nth slot of the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakKeyHashMap:: +set_data(int n, Value &&data) { + nassertv(has_element(n)); + _table[n]._data = std::move(data); +} +#endif // USE_MOVE_SEMANTICS + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::remove_element +// Access: Public +// Description: Removes the nth slot from the table. +// +// It is an error to call this if there is nothing +// stored in the nth slot (use has_element() to check +// this first). n should be in the range 0 <= n < +// get_size(). +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +remove_element(int n) { + nassertv(get_exists_array()[n] != 0); + + clear_element(n); + nassertv(_num_entries > 0); + --_num_entries; + + // 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 = n; + i = (i + 1) & (_table_size - 1); + while (get_exists_array()[i] != 0) { + if (_table[i]._key.was_deleted()) { + // It was deleted. Forget about it. + clear_element(i); + --_num_entries; + } else { + size_t wants_index = get_hash(_table[i]._key); + if (wants_index != i) { + // This one was a hash conflict; try to put it where it belongs. + // We can't just put it in n, since maybe it belongs somewhere + // after n. + while (wants_index != i && has_element(wants_index)) { + // Hash conflict; move it up. + wants_index = (wants_index + 1) & (_table_size - 1); + } + if (wants_index != i) { + store_new_element(wants_index, _table[i]._key, _table[i]._data); + clear_element(i); + } + } + } + + // Continue until we encounter the next unused slot. Until we do, + // we can't be sure we've found all of the potential hash + // conflicts. + i = (i + 1) & (_table_size - 1); + } + +#ifdef _DEBUG + nassertv(validate()); +#endif +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_num_entries +// Access: Public +// Description: Returns the number of active entries in the table. +// This is not necessarily related to the number of +// slots in the table as reported by get_size(). Use +// get_size() to iterate through all of the slots, not +// get_num_entries(). +// +// This is merely an upper bound on the number of +// entries; it may also count false positives for +// pointers that were recently deleted. +//////////////////////////////////////////////////////////////////// +template +INLINE int WeakKeyHashMap:: +get_num_entries() const { + return _num_entries; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::is_empty +// Access: Public +// Description: Returns true if the table is empty; +// i.e. get_num_entries() == 0. This may return a +// false negatives if a pointer was recently deleted; +// if this returns true, though, you can be sure it's +// empty. +//////////////////////////////////////////////////////////////////// +template +INLINE bool WeakKeyHashMap:: +is_empty() const { + return (_num_entries == 0); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::output +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +output(ostream &out) const { + out << "WeakKeyHashMap (" << _num_entries << " entries): ["; + for (size_t i = 0; i < _table_size; ++i) { + if (get_exists_array()[i] == 0) { + out << " *"; + + } else { + out << " " << _table[i]._key; + size_t index = get_hash(_table[i]._key.get_orig()); + if (index != i) { + // This was misplaced as the result of a hash conflict. + // Report how far off it is. + out << "(" << ((_table_size + i - index) & (_table_size - 1)) << ")"; + } + } + } + out << " ]"; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::write +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +write(ostream &out) const { + output(out); + out << "\n"; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::validate +// Access: Public +// Description: Returns true if the internal table appears to be +// consistent, false if there are some internal errors. +//////////////////////////////////////////////////////////////////// +template +bool WeakKeyHashMap:: +validate() const { + size_t count = 0; + + for (size_t i = 0; i < _table_size; ++i) { + if (get_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) { + wants_index = (wants_index + 1) & (_table_size - 1); + } + if (wants_index != i) { + util_cat.error() + << "WeakKeyHashMap is invalid: key " << _table[i]._key + << " should be in slot " << wants_index << " instead of " + << i << " (ideal is " << ideal_index << ")\n"; + write(util_cat.error(false)); + return false; + } + } + } + + if (count != _num_entries) { + util_cat.error() + << "WeakKeyHashMap is invalid: reports " << _num_entries + << " entries, actually has " << count << "\n"; + write(util_cat.error(false)); + return false; + } + + return true; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_hash +// Access: Private +// Description: Computes an appropriate index number to store the +// given pointer. +//////////////////////////////////////////////////////////////////// +template +INLINE size_t WeakKeyHashMap:: +get_hash(const Key *key) const { + /* + // We want a hash constant 0 < k < 1. This one is suggested by + // Knuth: + static const double hash_constant = (sqrt(5.0) - 1.0) / 2.0; + double f = ((double)(size_t)key * hash_constant); + f -= floor(f); + return (size_t)floor(f * _table_size); + */ + + return (((size_t)key * (size_t)9973) >> 8) & (_table_size - 1); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::is_element +// Access: Private +// Description: Returns true if element n matches key. +//////////////////////////////////////////////////////////////////// +template +INLINE bool WeakKeyHashMap:: +is_element(int n, const Key *key) const { + nassertr(has_element(n), false); + return _table[n]._key == key; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::store_new_element +// Access: Private +// Description: Constructs a new TableEntry at position n, storing +// the indicated key and value. +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakKeyHashMap:: +store_new_element(int 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. + nassertv(_table[n]._key.was_deleted()); + _table[n].~TableEntry(); + --_num_entries; + } + new(&_table[n]) TableEntry(key, data); + get_exists_array()[n] = true; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::clear_element +// Access: Private +// Description: Destructs the TableEntry at position n. +//////////////////////////////////////////////////////////////////// +template +INLINE void WeakKeyHashMap:: +clear_element(int n) { + _table[n].~TableEntry(); + get_exists_array()[n] = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::get_exists_array +// Access: Private +// Description: Returns the beginning of the array of _table_size +// unsigned chars that are the boolean flags for whether +// each element exists (has been constructed) within the +// table. +//////////////////////////////////////////////////////////////////// +template +INLINE unsigned char *WeakKeyHashMap:: +get_exists_array() const { + return (unsigned char *)(_table + _table_size); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::new_table +// Access: Private +// Description: Allocates a brand new table. +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +new_table() { + nassertv(_table_size == 0 && _num_entries == 0); + + // Pick a good initial table size. For now, we make it really + // small. Maybe that's the right answer. + _table_size = 4; + + // We allocate enough bytes for _table_size elements of TableEntry, + // plus _table_size more bytes at the end (for the exists array). + size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size; + + _deleted_chain = memory_hook->get_deleted_chain(alloc_size); + _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none()); + memset(get_exists_array(), 0, _table_size); +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::consider_expand_table +// Access: Private +// Description: Expands the table if it will need it (assuming one +// more element is about to be added). Returns true if +// the table was modified, false otherwise. +//////////////////////////////////////////////////////////////////// +template +INLINE bool WeakKeyHashMap:: +consider_expand_table() { + if (_num_entries >= (_table_size >> 1)) { + // Actually, first, we should see if there are any deleted pointers. + // Clean those up and see how much space we save. + for (size_t i = 0; i < _table_size; ++i) { + if (get_exists_array()[i] != 0 && _table[i]._key.was_deleted()) { + remove_element(i); + } + } + if (_num_entries >= (_table_size >> 1)) { + // Still not enough space. + expand_table(); + } + return true; + } + return false; +} + +//////////////////////////////////////////////////////////////////// +// Function: WeakKeyHashMap::expand_table +// Access: Private +// Description: Doubles the size of the existing table. +//////////////////////////////////////////////////////////////////// +template +void WeakKeyHashMap:: +expand_table() { + nassertv(_table_size != 0); + + WeakKeyHashMap old_map; + swap(old_map); + + // Double the table size. + size_t old_table_size = old_map._table_size; + _table_size = (old_table_size << 1); + nassertv(_table == NULL); + + // We allocate enough bytes for _table_size elements of TableEntry, + // plus _table_size more bytes at the end (for the exists array). + size_t alloc_size = _table_size * sizeof(TableEntry) + _table_size; + _deleted_chain = memory_hook->get_deleted_chain(alloc_size); + _table = (TableEntry *)_deleted_chain->allocate(alloc_size, TypeHandle::none()); + unsigned char *exists_array = get_exists_array(); + memset(exists_array, 0, _table_size); + nassertv(_num_entries == 0); + + // Now copy the entries from the old table into the new table. + int num_added = 0; + for (size_t i = 0; i < old_table_size; ++i) { + if (old_map.has_element(i)) { + size_t new_index = get_hash(old_map._table[i]._key.get_orig()); + + while (exists_array[new_index] != 0) { + // Hash conflict; look for a better spot. This has to succeed. + new_index = (new_index + 1) & (_table_size - 1); + } + +#ifdef USE_MOVE_SEMANTICS + // Use C++11 rvalue references to invoke the move constructor, + // which may be more efficient. + new(&_table[new_index]) TableEntry(move(old_map._table[i])); +#else + new(&_table[new_index]) TableEntry(old_map._table[i]); +#endif + exists_array[new_index] = true; + ++_num_entries; + } + } + + nassertv(validate()); + nassertv(old_map.validate()); + + nassertv(_num_entries == old_map._num_entries); +} diff --git a/panda/src/putil/weakKeyHashMap.cxx b/panda/src/putil/weakKeyHashMap.cxx new file mode 100644 index 0000000000..620603cc82 --- /dev/null +++ b/panda/src/putil/weakKeyHashMap.cxx @@ -0,0 +1,15 @@ +// Filename: weakKeyHashMap.cxx +// Created by: rdb (13Jul15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#include "weakKeyHashMap.h" diff --git a/panda/src/putil/weakKeyHashMap.h b/panda/src/putil/weakKeyHashMap.h new file mode 100644 index 0000000000..b84213567c --- /dev/null +++ b/panda/src/putil/weakKeyHashMap.h @@ -0,0 +1,115 @@ +// Filename: weakKeyHashMap.h +// Created by: rdb (13Jul15) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) Carnegie Mellon University. All rights reserved. +// +// All use of this software is subject to the terms of the revised BSD +// license. You should have received a copy of this license along +// with this source code in a file named "LICENSE." +// +//////////////////////////////////////////////////////////////////// + +#ifndef WEAKKEYHASHMAP_H +#define WEAKKEYHASHMAP_H + +#include "pandabase.h" +#include "pvector.h" +#include "config_util.h" +#include "weakPointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : WeakKeyHashMap +// Description : This is a variation on WeakKeyHashMap that stores +// weak pointers as keys, and automatically frees up +// entries from the map when the associated key has +// been deleted. +// +// This is more efficient than using a naive map of +// WeakPointerTo keys since that would incur the cost +// of constructing a weak reference every time a find +// operation is used. +//////////////////////////////////////////////////////////////////// +template +class WeakKeyHashMap { +public: +#ifndef CPPPARSER + INLINE WeakKeyHashMap(); + INLINE ~WeakKeyHashMap(); + + INLINE void swap(WeakKeyHashMap &other); + + int find(const Key *key) const; + int store(const Key *key, const Value &data); + INLINE bool remove(const Key *key); + void clear(); + + INLINE Value &operator [] (const Key *key); + + INLINE int 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); +#ifdef USE_MOVE_SEMANTICS + INLINE void set_data(int n, Value &&data); +#endif + void remove_element(int n); + + INLINE int get_num_entries() const; + INLINE bool is_empty() const; + + void output(ostream &out) const; + void write(ostream &out) const; + bool validate() const; + +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 unsigned char *get_exists_array() const; + + void new_table(); + INLINE bool consider_expand_table(); + void expand_table(); + + class TableEntry { + public: + INLINE TableEntry(const Key *key, const Value &data) : + _key(key), + _data(data) {} + INLINE TableEntry(const TableEntry ©) : + _key(copy._key), + _data(copy._data) {} +#ifdef USE_MOVE_SEMANTICS + INLINE TableEntry(TableEntry &&from) NOEXCEPT : + _key(move(from._key)), + _data(move(from._data)) {} +#endif + WCPT(Key) _key; + Value _data; + }; + + TableEntry *_table; + DeletedBufferChain *_deleted_chain; + size_t _table_size; + size_t _num_entries; +#endif // CPPPARSER +}; + +template +inline ostream &operator << (ostream &out, const WeakKeyHashMap &shm) { + shm.output(out); + return out; +} + +#ifndef CPPPARSER +#include "weakKeyHashMap.I" +#endif // CPPPARSER + +#endif