From 9b575fbe58cc450a408f38e8615bb3b2d415db99 Mon Sep 17 00:00:00 2001 From: David Rose Date: Tue, 3 Apr 2007 23:21:49 +0000 Subject: [PATCH] steps toward async flatten --- panda/src/chan/partBundle.I | 20 +++++-- panda/src/chan/partBundle.cxx | 36 +++++++++--- panda/src/chan/partBundle.h | 10 +++- panda/src/chan/partBundleNode.cxx | 39 ++++++++----- panda/src/chan/partBundleNode.h | 2 +- panda/src/char/character.cxx | 72 +++++++++++------------ panda/src/char/character.h | 4 +- panda/src/char/characterJointBundle.I | 8 +-- panda/src/char/characterJointBundle.cxx | 34 ++++++++--- panda/src/char/characterJointBundle.h | 5 +- panda/src/display/graphicsOutput.cxx | 2 +- panda/src/framework/windowFramework.cxx | 2 +- panda/src/pgraph/Sources.pp | 3 + panda/src/pgraph/config_pgraph.cxx | 8 +++ panda/src/pgraph/config_pgraph.h | 1 + panda/src/pgraph/findApproxLevelEntry.I | 1 + panda/src/pgraph/modelFlattenRequest.I | 66 +++++++++++++++++++++ panda/src/pgraph/modelFlattenRequest.cxx | 42 ++++++++++++++ panda/src/pgraph/modelFlattenRequest.h | 74 ++++++++++++++++++++++++ panda/src/pgraph/pandaNode.cxx | 26 ++++++++- panda/src/pgraph/pandaNode.h | 1 + panda/src/pgraph/pgraph_composite3.cxx | 1 + panda/src/pgraph/sceneGraphReducer.cxx | 8 ++- panda/src/pgraph/workingNodePath.h | 2 +- panda/src/pipeline/config_pipeline.cxx | 7 +++ panda/src/pipeline/config_pipeline.h | 1 + panda/src/pipeline/thread.I | 3 + panda/src/pipeline/thread.cxx | 6 ++ panda/src/pipeline/thread.h | 1 + panda/src/pipeline/threadWin32Impl.h | 3 - 30 files changed, 392 insertions(+), 96 deletions(-) create mode 100644 panda/src/pgraph/modelFlattenRequest.I create mode 100644 panda/src/pgraph/modelFlattenRequest.cxx create mode 100644 panda/src/pgraph/modelFlattenRequest.h diff --git a/panda/src/chan/partBundle.I b/panda/src/chan/partBundle.I index 22fb5be0b1..f37ce246bf 100644 --- a/panda/src/chan/partBundle.I +++ b/panda/src/chan/partBundle.I @@ -146,15 +146,27 @@ get_root_xform() const { return cdata->_root_xform; } +//////////////////////////////////////////////////////////////////// +// Function: PartBundle::get_num_nodes +// Access: Published +// Description: Returns the number of PartBundleNodes that contain a +// pointer to this PartBundle. +//////////////////////////////////////////////////////////////////// +INLINE int PartBundle:: +get_num_nodes() const { + return _nodes.size(); +} + //////////////////////////////////////////////////////////////////// // Function: PartBundle::get_node // Access: Published -// Description: Returns the PartBundleNode associated with this -// PartBundle. +// Description: Returns the nth PartBundleNode associated with +// this PartBundle. //////////////////////////////////////////////////////////////////// INLINE PartBundleNode *PartBundle:: -get_node() const { - return _node; +get_node(int n) const { + nassertr(n >= 0 && n < (int)_nodes.size(), NULL); + return _nodes[n]; } diff --git a/panda/src/chan/partBundle.cxx b/panda/src/chan/partBundle.cxx index 144cd8606e..be01436b2b 100644 --- a/panda/src/chan/partBundle.cxx +++ b/panda/src/chan/partBundle.cxx @@ -30,6 +30,8 @@ #include "bamWriter.h" #include "configVariableEnum.h" +#include + TypeHandle PartBundle::_type_handle; @@ -64,8 +66,7 @@ PartBundle(const PartBundle ©) : //////////////////////////////////////////////////////////////////// PartBundle:: PartBundle(const string &name) : - PartGroup(name), - _node(NULL) + PartGroup(name) { } @@ -319,16 +320,33 @@ control_activated(AnimControl *control) { } //////////////////////////////////////////////////////////////////// -// Function: PartBundle::set_node +// Function: PartBundle::add_node // Access: Protected, Virtual -// Description: Changes the PartBundleNode pointer associated with -// the PartBundle. Normally called only by the -// PartBundleNode itself, for instance when the bundle -// is flattened with another node. +// Description: Adds the PartBundleNode pointer to the set of nodes +// associated with the PartBundle. Normally called only +// by the PartBundleNode itself, for instance when the +// bundle is flattened with another node. //////////////////////////////////////////////////////////////////// void PartBundle:: -set_node(PartBundleNode *node) { - _node = node; +add_node(PartBundleNode *node) { + nassertv(find(_nodes.begin(), _nodes.end(), node) == _nodes.end()); + _nodes.push_back(node); +} + +//////////////////////////////////////////////////////////////////// +// Function: PartBundle::remove_node +// Access: Protected, Virtual +// Description: Removes the PartBundleNode pointer from the set of +// nodes associated with the PartBundle. Normally +// called only by the PartBundleNode itself, for +// instance when the bundle is flattened with another +// node. +//////////////////////////////////////////////////////////////////// +void PartBundle:: +remove_node(PartBundleNode *node) { + Nodes::iterator ni = find(_nodes.begin(), _nodes.end(), node); + nassertv(ni != _nodes.end()); + _nodes.erase(ni); } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/chan/partBundle.h b/panda/src/chan/partBundle.h index 7d428f3bed..72df4373f0 100644 --- a/panda/src/chan/partBundle.h +++ b/panda/src/chan/partBundle.h @@ -31,6 +31,7 @@ #include "cycleDataReader.h" #include "cycleDataWriter.h" #include "luse.h" +#include "pvector.h" class AnimBundle; class PartBundleNode; @@ -105,7 +106,8 @@ PUBLISHED: INLINE void xform(const LMatrix4f &mat); INLINE const LMatrix4f &get_root_xform() const; - INLINE PartBundleNode *get_node() const; + INLINE int get_num_nodes() const; + INLINE PartBundleNode *get_node(int n) const; void clear_control_effects(); INLINE void set_control_effect(AnimControl *control, float effect); @@ -128,7 +130,8 @@ public: virtual void control_activated(AnimControl *control); protected: - virtual void set_node(PartBundleNode *node); + virtual void add_node(PartBundleNode *node); + virtual void remove_node(PartBundleNode *node); private: class CData; @@ -138,7 +141,8 @@ private: void recompute_net_blend(CData *cdata); void clear_and_stop_intersecting(AnimControl *control, CData *cdata); - PartBundleNode *_node; + typedef pvector Nodes; + Nodes _nodes; // This is the data that must be cycled between pipeline stages. class CData : public CycleData { diff --git a/panda/src/chan/partBundleNode.cxx b/panda/src/chan/partBundleNode.cxx index c028822d65..2c5d16f342 100644 --- a/panda/src/chan/partBundleNode.cxx +++ b/panda/src/chan/partBundleNode.cxx @@ -33,23 +33,29 @@ PartBundleNode:: ~PartBundleNode() { Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { - nassertv((*bi)->_node == this); - (*bi)->_node = NULL; + (*bi)->remove_node(this); } } //////////////////////////////////////////////////////////////////// -// Function: PartBundleNode::safe_to_flatten +// Function: PartBundleNode::safe_to_transform // Access: Public, Virtual -// Description: Returns true if it is generally safe to flatten out -// this particular kind of Node by duplicating -// instances, false otherwise (for instance, a Camera -// cannot be safely flattened, because the Camera -// pointer itself is meaningful). +// Description: Returns true if it is generally safe to transform +// this particular kind of PandaNode by calling the +// xform() method, false otherwise. //////////////////////////////////////////////////////////////////// bool PartBundleNode:: -safe_to_flatten() const { - return false; +safe_to_transform() const { + // If any of our bundles appear on multiple nodes, we can't + // transform any of them without transforming all of them at once. + Bundles::const_iterator bi; + for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { + if ((*bi)->get_num_nodes() > 1) { + return false; + } + } + + return true; } //////////////////////////////////////////////////////////////////// @@ -61,6 +67,11 @@ safe_to_flatten() const { //////////////////////////////////////////////////////////////////// void PartBundleNode:: xform(const LMatrix4f &mat) { + if (mat.almost_equal(LMatrix4f::ident_mat())) { + // Don't bother. + return; + } + Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { (*bi)->xform(mat); @@ -74,9 +85,8 @@ xform(const LMatrix4f &mat) { //////////////////////////////////////////////////////////////////// void PartBundleNode:: add_bundle(PartBundle *bundle) { - nassertv(bundle->_node == NULL); _bundles.push_back(bundle); - bundle->set_node(this); + bundle->add_node(this); } //////////////////////////////////////////////////////////////////// @@ -91,7 +101,8 @@ steal_bundles(PartBundleNode *other) { for (bi = other->_bundles.begin(); bi != other->_bundles.end(); ++bi) { PartBundle *bundle = (*bi); _bundles.push_back(bundle); - bundle->set_node(this); + bundle->remove_node(other); + bundle->add_node(this); } other->_bundles.clear(); } @@ -127,7 +138,7 @@ complete_pointers(TypedWritable **p_list, BamReader* manager) { Bundles::iterator bi; for (bi = _bundles.begin(); bi != _bundles.end(); ++bi) { (*bi) = DCAST(PartBundle, p_list[pi++]); - (*bi)->_node = this; + (*bi)->add_node(this); } return pi; diff --git a/panda/src/chan/partBundleNode.h b/panda/src/chan/partBundleNode.h index f046f8b51a..ee318ea912 100644 --- a/panda/src/chan/partBundleNode.h +++ b/panda/src/chan/partBundleNode.h @@ -43,7 +43,7 @@ protected: public: virtual ~PartBundleNode(); - virtual bool safe_to_flatten() const; + virtual bool safe_to_transform() const; virtual void xform(const LMatrix4f &mat); PUBLISHED: diff --git a/panda/src/char/character.cxx b/panda/src/char/character.cxx index 37284647ba..ec204508dc 100644 --- a/panda/src/char/character.cxx +++ b/panda/src/char/character.cxx @@ -40,25 +40,29 @@ PStatCollector Character::_animation_pcollector("*:Animation"); // Description: Use make_copy() or copy_subgraph() to copy a Character. //////////////////////////////////////////////////////////////////// Character:: -Character(const Character ©) : +Character(const Character ©, bool copy_bundles) : PartBundleNode(copy), _joints_pcollector(copy._joints_pcollector), _skinning_pcollector(copy._skinning_pcollector) { set_cull_callback(); - // Copy the bundle(s). - int num_bundles = copy.get_num_bundles(); - for (int i = 0; i < num_bundles; ++i) { - PartBundle *orig_bundle = copy.get_bundle(i); - PartBundle *new_bundle = - new CharacterJointBundle(orig_bundle->get_name()); - add_bundle(new_bundle); - - // Make a copy of the joint/slider hierarchy. - copy_joints(new_bundle, orig_bundle); - } - + if (copy_bundles) { + // Copy the bundle(s). + int num_bundles = copy.get_num_bundles(); + for (int i = 0; i < num_bundles; ++i) { + PartBundle *orig_bundle = copy.get_bundle(i); + PT(PartBundle) new_bundle = DCAST(PartBundle, orig_bundle->copy_subgraph()); + add_bundle(new_bundle); + } + } else { + // Share the bundles. + int num_bundles = copy.get_num_bundles(); + for (int i = 0; i < num_bundles; ++i) { + PartBundle *orig_bundle = copy.get_bundle(i); + add_bundle(orig_bundle); + } + } _last_auto_update = -1.0; } @@ -102,7 +106,22 @@ Character:: //////////////////////////////////////////////////////////////////// PandaNode *Character:: make_copy() const { - return new Character(*this); + return new Character(*this, true); +} + +//////////////////////////////////////////////////////////////////// +// Function: Character::dupe_for_flatten +// Access: Public, Virtual +// Description: This is similar to make_copy(), but it makes a copy +// for the specific purpose of flatten. Typically, this +// will be a new PandaNode with a new pointer, but all +// of the internal data will always be shared with the +// original; whereas the new node returned by +// make_copy() might not share the internal data. +//////////////////////////////////////////////////////////////////// +PandaNode *Character:: +dupe_for_flatten() const { + return new Character(*this, false); } //////////////////////////////////////////////////////////////////// @@ -352,31 +371,6 @@ do_update() { } } -//////////////////////////////////////////////////////////////////// -// Function: Character::copy_joints -// Access: Private -// Description: Recursively walks the joint/slider hierarchy and -// creates a new copy of the hierarchy. -//////////////////////////////////////////////////////////////////// -void Character:: -copy_joints(PartGroup *copy, PartGroup *orig) { - if (copy->get_type() != orig->get_type()) { - char_cat.warning() - << "Don't know how to copy " << orig->get_type() << "\n"; - } - - PartGroup::Children::const_iterator ci; - for (ci = orig->_children.begin(); ci != orig->_children.end(); ++ci) { - PartGroup *orig_child = (*ci); - PartGroup *copy_child = orig_child->make_copy(); - if (copy_child->is_of_type(CharacterJoint::get_class_type())) { - DCAST(CharacterJoint, copy_child)->set_character(this); - } - copy->_children.push_back(copy_child); - copy_joints(copy_child, orig_child); - } -} - //////////////////////////////////////////////////////////////////// // Function: Character::r_copy_children // Access: Protected, Virtual diff --git a/panda/src/char/character.h b/panda/src/char/character.h index c6cdbd8a90..87f3a76089 100644 --- a/panda/src/char/character.h +++ b/panda/src/char/character.h @@ -44,13 +44,14 @@ class ComputedVertices; //////////////////////////////////////////////////////////////////// class EXPCL_PANDA Character : public PartBundleNode { protected: - Character(const Character ©); + Character(const Character ©, bool copy_bundles); public: Character(const string &name); virtual ~Character(); virtual PandaNode *make_copy() const; + virtual PandaNode *dupe_for_flatten() const; virtual PandaNode *combine_with(PandaNode *other); virtual bool cull_callback(CullTraverser *trav, CullTraverserData &data); @@ -76,7 +77,6 @@ PUBLISHED: private: void do_update(); - void copy_joints(PartGroup *copy, PartGroup *orig); typedef pmap NodeMap; typedef pmap JointMap; diff --git a/panda/src/char/characterJointBundle.I b/panda/src/char/characterJointBundle.I index 636729a41c..47f30d727a 100644 --- a/panda/src/char/characterJointBundle.I +++ b/panda/src/char/characterJointBundle.I @@ -37,10 +37,10 @@ CharacterJointBundle(const CharacterJointBundle ©) : //////////////////////////////////////////////////////////////////// // Function: CharacterJointBundle::get_node // Access: Public -// Description: Returns the Character node associated with this -// PartBundle. +// Description: Returns the nth Character associated with +// this PartBundle. //////////////////////////////////////////////////////////////////// INLINE Character *CharacterJointBundle:: -get_node() const { - return DCAST(Character, PartBundle::get_node()); +get_node(int n) const { + return DCAST(Character, PartBundle::get_node(n)); } diff --git a/panda/src/char/characterJointBundle.cxx b/panda/src/char/characterJointBundle.cxx index f89f9b8081..fa6fa40b7b 100644 --- a/panda/src/char/characterJointBundle.cxx +++ b/panda/src/char/characterJointBundle.cxx @@ -45,22 +45,42 @@ make_copy() const { } //////////////////////////////////////////////////////////////////// -// Function: CharacterJointBundle::set_node +// Function: CharacterJointBundle::add_node // Access: Protected, Virtual -// Description: Changes the PartBundleNode pointer associated with -// the PartBundle. Normally called only by the -// PartBundleNode itself, for instance when the bundle -// is flattened with another node. +// Description: Adds the PartBundleNode pointer to the set of nodes +// associated with the PartBundle. Normally called only +// by the PartBundleNode itself, for instance when the +// bundle is flattened with another node. //////////////////////////////////////////////////////////////////// void CharacterJointBundle:: -set_node(PartBundleNode *node) { - PartBundle::set_node(node); +add_node(PartBundleNode *node) { + PartBundle::add_node(node); if (node->is_of_type(Character::get_class_type())) { Character *character = DCAST(Character, node); r_set_character(this, character); } } +//////////////////////////////////////////////////////////////////// +// Function: CharacterJointBundle::remove_node +// Access: Protected, Virtual +// Description: Removes the PartBundleNode pointer from the set of +// nodes associated with the PartBundle. Normally +// called only by the PartBundleNode itself, for +// instance when the bundle is flattened with another +// node. +//////////////////////////////////////////////////////////////////// +void CharacterJointBundle:: +remove_node(PartBundleNode *node) { + PartBundle::remove_node(node); + + // If there is still a Character on the list, assign that one to all + // of the joints. + if (get_num_nodes() > 0) { + r_set_character(this, get_node(get_num_nodes() - 1)); + } +} + //////////////////////////////////////////////////////////////////// // Function: CharacterJointBundle::r_set_character // Access: Private diff --git a/panda/src/char/characterJointBundle.h b/panda/src/char/characterJointBundle.h index ec08035d30..bd029f3813 100644 --- a/panda/src/char/characterJointBundle.h +++ b/panda/src/char/characterJointBundle.h @@ -40,11 +40,12 @@ public: CharacterJointBundle(const string &name = ""); PUBLISHED: - INLINE Character *get_node() const; + INLINE Character *get_node(int n) const; protected: virtual PartGroup *make_copy() const; - virtual void set_node(PartBundleNode *node); + virtual void add_node(PartBundleNode *node); + virtual void remove_node(PartBundleNode *node); private: void r_set_character(PartGroup *group, Character *character); diff --git a/panda/src/display/graphicsOutput.cxx b/panda/src/display/graphicsOutput.cxx index e445d6d96e..315bc65f2e 100644 --- a/panda/src/display/graphicsOutput.cxx +++ b/panda/src/display/graphicsOutput.cxx @@ -315,7 +315,7 @@ add_render_texture(Texture *tex, RenderTextureMode mode, tex->set_x_size(Texture::up_to_power_2(get_x_size())); tex->set_y_size(Texture::up_to_power_2(get_y_size())); - if ((mode == RTM_bind_or_copy)&&(support_render_texture==0)) { + if (mode == RTM_bind_or_copy && !support_render_texture) { mode = RTM_copy_texture; } else { diff --git a/panda/src/framework/windowFramework.cxx b/panda/src/framework/windowFramework.cxx index 4cb631a617..3709bed2fe 100644 --- a/panda/src/framework/windowFramework.cxx +++ b/panda/src/framework/windowFramework.cxx @@ -1043,7 +1043,7 @@ make_camera() { PT(Lens) lens = new PerspectiveLens; - if (aspect_ratio != 0.0f) { + if (aspect_ratio != 0.0) { // If we're given an explict aspect ratio, use it lens->set_aspect_ratio(aspect_ratio); diff --git a/panda/src/pgraph/Sources.pp b/panda/src/pgraph/Sources.pp index b7b18d4d29..b29f071624 100644 --- a/panda/src/pgraph/Sources.pp +++ b/panda/src/pgraph/Sources.pp @@ -69,6 +69,7 @@ lodNode.I lodNode.h \ materialAttrib.I materialAttrib.h \ materialCollection.I materialCollection.h \ + modelFlattenRequest.I modelFlattenRequest.h \ modelLoadRequest.I modelLoadRequest.h \ modelNode.I modelNode.h \ modelPool.I modelPool.h \ @@ -176,6 +177,7 @@ lodNode.cxx \ materialAttrib.cxx \ materialCollection.cxx \ + modelFlattenRequest.cxx \ modelLoadRequest.cxx \ modelNode.cxx \ modelPool.cxx \ @@ -278,6 +280,7 @@ lodNode.I lodNode.h \ materialAttrib.I materialAttrib.h \ materialCollection.I materialCollection.h \ + modelFlattenRequest.I modelFlattenRequest.h \ modelLoadRequest.I modelLoadRequest.h \ modelNode.I modelNode.h \ modelPool.I modelPool.h \ diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index fb28e23549..75b4b48468 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -60,6 +60,7 @@ #include "loaderFileTypeRegistry.h" #include "lodNode.h" #include "materialAttrib.h" +#include "modelFlattenRequest.h" #include "modelLoadRequest.h" #include "modelNode.h" #include "modelRoot.h" @@ -127,6 +128,12 @@ ConfigVariableBool unambiguous_graph "assertion failure instead of just a warning (which can then be " "trapped with assert-abort).")); +ConfigVariableBool no_unsupported_copy +("no-unsupported-copy", false, + PRC_DESC("Set this true to make an attempt to copy an unsupported type " + "generate an assertion failure instead of just a warning (which " + "can then be trapped with assert-abort).")); + ConfigVariableBool allow_unrelated_wrt ("allow-unrelated-wrt", true, PRC_DESC("Set this true to allow unrelated NodePaths (that is, nodes which " @@ -341,6 +348,7 @@ init_libpgraph() { LoaderFileType::init_type(); LoaderFileTypeBam::init_type(); MaterialAttrib::init_type(); + ModelFlattenRequest::init_type(); ModelLoadRequest::init_type(); ModelNode::init_type(); ModelRoot::init_type(); diff --git a/panda/src/pgraph/config_pgraph.h b/panda/src/pgraph/config_pgraph.h index 7bf75978d3..c2801c54e9 100644 --- a/panda/src/pgraph/config_pgraph.h +++ b/panda/src/pgraph/config_pgraph.h @@ -37,6 +37,7 @@ NotifyCategoryDecl(portal, EXPCL_PANDA, EXPTP_PANDA); extern ConfigVariableBool fake_view_frustum_cull; extern ConfigVariableBool allow_portal_cull; extern ConfigVariableBool unambiguous_graph; +extern ConfigVariableBool no_unsupported_copy; extern ConfigVariableBool allow_unrelated_wrt; extern ConfigVariableBool paranoid_compose; extern ConfigVariableBool compose_componentwise; diff --git a/panda/src/pgraph/findApproxLevelEntry.I b/panda/src/pgraph/findApproxLevelEntry.I index 3a58a41353..270b7758d4 100644 --- a/panda/src/pgraph/findApproxLevelEntry.I +++ b/panda/src/pgraph/findApproxLevelEntry.I @@ -47,6 +47,7 @@ FindApproxLevelEntry(const FindApproxLevelEntry &parent, _approx_path(parent._approx_path), _next(next) { + nassertv(validate_ptr(this) && validate_ptr(&parent)); nassertv(_node_path.is_valid()); } diff --git a/panda/src/pgraph/modelFlattenRequest.I b/panda/src/pgraph/modelFlattenRequest.I new file mode 100644 index 0000000000..cb2129eb7e --- /dev/null +++ b/panda/src/pgraph/modelFlattenRequest.I @@ -0,0 +1,66 @@ +// Filename: modelFlattenRequest.I +// Created by: drose (30Mar07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + + +//////////////////////////////////////////////////////////////////// +// Function: ModelFlattenRequest::Constructor +// Access: Published +// Description: Create a new ModelFlattenRequest, and add it to the loader +// via load_async(), to begin an asynchronous load. +//////////////////////////////////////////////////////////////////// +INLINE ModelFlattenRequest:: +ModelFlattenRequest(PandaNode *orig) : + AsyncTask(orig->get_name()), + _orig(orig), + _is_ready(false) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelFlattenRequest::get_orig +// Access: Published +// Description: Returns the original, unflattened node. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *ModelFlattenRequest:: +get_orig() const { + return _orig; +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelFlattenRequest::is_ready +// Access: Published +// Description: Returns true if this request has completed, false if +// it is still pending. When this returns true, you may +// retrieve the model loaded by calling get_result(). +//////////////////////////////////////////////////////////////////// +INLINE bool ModelFlattenRequest:: +is_ready() const { + return _is_ready; +} + +//////////////////////////////////////////////////////////////////// +// Function: ModelFlattenRequest::get_model +// Access: Published +// Description: Returns the flattened copy of the model. It is an +// error to call this unless is_ready() returns true. +//////////////////////////////////////////////////////////////////// +INLINE PandaNode *ModelFlattenRequest:: +get_model() const { + nassertr(_is_ready, NULL); + return _model; +} diff --git a/panda/src/pgraph/modelFlattenRequest.cxx b/panda/src/pgraph/modelFlattenRequest.cxx new file mode 100644 index 0000000000..6c814915dc --- /dev/null +++ b/panda/src/pgraph/modelFlattenRequest.cxx @@ -0,0 +1,42 @@ +// Filename: modelFlattenRequest.cxx +// Created by: drose (30Mar07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#include "modelFlattenRequest.h" +#include "nodePath.h" + +TypeHandle ModelFlattenRequest::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: ModelFlattenRequest::do_task +// Access: Protected, Virtual +// Description: Performs the task: that is, copies and flattens the +// model. +//////////////////////////////////////////////////////////////////// +bool ModelFlattenRequest:: +do_task() { + // We make another instance of the original node, so we can safely + // flatten that without affecting the original copy. + NodePath np("flatten_root"); + np.attach_new_node(_orig); + np.flatten_strong(); + _model = np.get_child(0).node(); + _is_ready = true; + + // Don't continue the task; we're done. + return false; +} diff --git a/panda/src/pgraph/modelFlattenRequest.h b/panda/src/pgraph/modelFlattenRequest.h new file mode 100644 index 0000000000..1cb2e835cf --- /dev/null +++ b/panda/src/pgraph/modelFlattenRequest.h @@ -0,0 +1,74 @@ +// Filename: modelFlattenRequest.h +// Created by: drose (30Mar07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef MODELFLATTENREQUEST +#define MODELFLATTENREQUEST + +#include "pandabase.h" + +#include "asyncTask.h" +#include "pandaNode.h" +#include "pointerTo.h" + +//////////////////////////////////////////////////////////////////// +// Class : ModelFlattenRequest +// Description : This class object manages a single asynchronous +// request to flatten a model. The model will be +// duplicated and flattened in a sub-thread (if +// threading is available), without affecting the +// original model; and when the result is done it may be +// retrieved from this object. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA ModelFlattenRequest : public AsyncTask { +PUBLISHED: + INLINE ModelFlattenRequest(PandaNode *orig); + + INLINE PandaNode *get_orig() const; + + INLINE bool is_ready() const; + INLINE PandaNode *get_model() const; + +protected: + virtual bool do_task(); + +private: + PT(PandaNode) _orig; + bool _is_ready; + PT(PandaNode) _model; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + AsyncTask::init_type(); + register_type(_type_handle, "ModelFlattenRequest", + AsyncTask::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "modelFlattenRequest.I" + +#endif diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 04a64896ff..9ee62137b4 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -196,14 +196,30 @@ make_copy() const { return new PandaNode(*this); } +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::dupe_for_flatten +// Access: Public, Virtual +// Description: This is similar to make_copy(), but it makes a copy +// for the specific purpose of flatten. Typically, this +// will be a new PandaNode with a new pointer, but all +// of the internal data will always be shared with the +// original; whereas the new node returned by +// make_copy() might not share the internal data. +//////////////////////////////////////////////////////////////////// +PandaNode *PandaNode:: +dupe_for_flatten() const { + return make_copy(); +} + //////////////////////////////////////////////////////////////////// // Function: PandaNode::safe_to_flatten // Access: Public, Virtual // Description: Returns true if it is generally safe to flatten out // this particular kind of PandaNode by duplicating -// instances, false otherwise (for instance, a Camera -// cannot be safely flattened, because the Camera -// pointer itself is meaningful). +// instances (by calling dupe_for_flatten()), false +// otherwise (for instance, a Camera cannot be safely +// flattened, because the Camera pointer itself is +// meaningful). //////////////////////////////////////////////////////////////////// bool PandaNode:: safe_to_flatten() const { @@ -2397,6 +2413,10 @@ r_copy_subgraph(PandaNode::InstanceMap &inst_map, Thread *current_thread) const if (copy->get_type() != get_type()) { pgraph_cat.warning() << "Don't know how to copy nodes of type " << get_type() << "\n"; + + if (no_unsupported_copy) { + nassertr(false, NULL); + } } copy->r_copy_children(this, inst_map, current_thread); diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 4e4cc0c67f..17cbe7bb18 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -83,6 +83,7 @@ private: public: virtual PandaNode *make_copy() const; + virtual PandaNode *dupe_for_flatten() const; virtual bool safe_to_flatten() const; virtual bool safe_to_transform() const; diff --git a/panda/src/pgraph/pgraph_composite3.cxx b/panda/src/pgraph/pgraph_composite3.cxx index 3b3dae5359..9b36d5ab1c 100644 --- a/panda/src/pgraph/pgraph_composite3.cxx +++ b/panda/src/pgraph/pgraph_composite3.cxx @@ -12,6 +12,7 @@ #include "lodNode.cxx" #include "materialAttrib.cxx" #include "materialCollection.cxx" +#include "modelFlattenRequest.cxx" #include "modelLoadRequest.cxx" #include "modelNode.cxx" #include "modelPool.cxx" diff --git a/panda/src/pgraph/sceneGraphReducer.cxx b/panda/src/pgraph/sceneGraphReducer.cxx index 06b54ab2d9..828c1730a8 100644 --- a/panda/src/pgraph/sceneGraphReducer.cxx +++ b/panda/src/pgraph/sceneGraphReducer.cxx @@ -175,15 +175,19 @@ r_apply_attribs(PandaNode *node, const AccumulatedAttribs &attribs, pgraph_cat.spam() << "Cannot duplicate nodes of type " << child_node->get_type() << ".\n"; - resist_copy = true; } + resist_copy = true; } else { - PT(PandaNode) new_node = child_node->make_copy(); + PT(PandaNode) new_node = child_node->dupe_for_flatten(); if (new_node->get_type() != child_node->get_type()) { pgraph_cat.error() << "Don't know how to copy nodes of type " << child_node->get_type() << "\n"; + + if (no_unsupported_copy) { + nassertv(false); + } resist_copy = true; } else { diff --git a/panda/src/pgraph/workingNodePath.h b/panda/src/pgraph/workingNodePath.h index 1d8f569b13..83d0269c4b 100644 --- a/panda/src/pgraph/workingNodePath.h +++ b/panda/src/pgraph/workingNodePath.h @@ -74,7 +74,7 @@ private: const WorkingNodePath *_next; PT(NodePathComponent) _start; - PandaNode *_node; + PT(PandaNode) _node; }; INLINE ostream &operator << (ostream &out, const WorkingNodePath &node_path); diff --git a/panda/src/pipeline/config_pipeline.cxx b/panda/src/pipeline/config_pipeline.cxx index 693b479589..6afcba8e6f 100644 --- a/panda/src/pipeline/config_pipeline.cxx +++ b/panda/src/pipeline/config_pipeline.cxx @@ -32,6 +32,13 @@ ConfigureFn(config_pipeline) { init_libpipeline(); } +ConfigVariableBool support_threads +("support-threads", true, + PRC_DESC("Set this false to disallow the creation of threads using Panda's " + "Thread interface, even if threading support is compiled in. This " + "does not affect the operation of mutexes and other synchronization " + "primitives, just the creation of threads.")); + ConfigVariableInt thread_stack_size ("thread-stack-size", 4194304, PRC_DESC("Specifies the minimum size, in bytes, of the stack that will be " diff --git a/panda/src/pipeline/config_pipeline.h b/panda/src/pipeline/config_pipeline.h index d3fb189c5b..ab2d779529 100644 --- a/panda/src/pipeline/config_pipeline.h +++ b/panda/src/pipeline/config_pipeline.h @@ -29,6 +29,7 @@ ConfigureDecl(config_pipeline, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(pipeline, EXPCL_PANDA, EXPTP_PANDA); NotifyCategoryDecl(thread, EXPCL_PANDA, EXPTP_PANDA); +extern ConfigVariableBool support_threads; extern ConfigVariableInt thread_stack_size; extern ConfigVariableBool threads_always_global; extern ConfigVariableBool threads_never_global; diff --git a/panda/src/pipeline/thread.I b/panda/src/pipeline/thread.I index f56c0040ec..5373e9f6dd 100644 --- a/panda/src/pipeline/thread.I +++ b/panda/src/pipeline/thread.I @@ -233,6 +233,9 @@ get_current_pipeline_stage() { //////////////////////////////////////////////////////////////////// INLINE bool Thread:: is_threading_supported() { + if (!support_threads) { + return false; + } return ThreadImpl::is_threading_supported(); } diff --git a/panda/src/pipeline/thread.cxx b/panda/src/pipeline/thread.cxx index 12da6c6e5f..3e75cb1ee5 100644 --- a/panda/src/pipeline/thread.cxx +++ b/panda/src/pipeline/thread.cxx @@ -146,6 +146,12 @@ bool Thread:: start(ThreadPriority priority, bool global, bool joinable) { nassertr(!_started, false); + if (!support_threads) { + thread_cat.warning() + << *this << " could not be started: support-threads is false.\n"; + return false; + } + if (threads_always_global) { global = true; } else if (threads_never_global) { diff --git a/panda/src/pipeline/thread.h b/panda/src/pipeline/thread.h index d1837b59c4..d8167fb242 100644 --- a/panda/src/pipeline/thread.h +++ b/panda/src/pipeline/thread.h @@ -25,6 +25,7 @@ #include "threadPriority.h" #include "threadImpl.h" #include "pnotify.h" +#include "config_pipeline.h" class Mutex; class ReMutex; diff --git a/panda/src/pipeline/threadWin32Impl.h b/panda/src/pipeline/threadWin32Impl.h index ff721099c5..79ed1f887d 100644 --- a/panda/src/pipeline/threadWin32Impl.h +++ b/panda/src/pipeline/threadWin32Impl.h @@ -29,9 +29,6 @@ #include "mutexWin32Impl.h" #include "conditionVarWin32Impl.h" -#define WIN32_LEAN_AND_MEAN 1 -#include - class Thread; ////////////////////////////////////////////////////////////////////