steps toward async flatten

This commit is contained in:
David Rose 2007-04-03 23:21:49 +00:00
parent 301e051f35
commit 9b575fbe58
30 changed files with 392 additions and 96 deletions

View File

@ -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];
}

View File

@ -30,6 +30,8 @@
#include "bamWriter.h"
#include "configVariableEnum.h"
#include <algorithm>
TypeHandle PartBundle::_type_handle;
@ -64,8 +66,7 @@ PartBundle(const PartBundle &copy) :
////////////////////////////////////////////////////////////////////
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);
}
////////////////////////////////////////////////////////////////////

View File

@ -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<PartBundleNode *> Nodes;
Nodes _nodes;
// This is the data that must be cycled between pipeline stages.
class CData : public CycleData {

View File

@ -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;

View File

@ -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:

View File

@ -40,25 +40,29 @@ PStatCollector Character::_animation_pcollector("*:Animation");
// Description: Use make_copy() or copy_subgraph() to copy a Character.
////////////////////////////////////////////////////////////////////
Character::
Character(const Character &copy) :
Character(const Character &copy, 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

View File

@ -44,13 +44,14 @@ class ComputedVertices;
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA Character : public PartBundleNode {
protected:
Character(const Character &copy);
Character(const Character &copy, 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<const PandaNode *, PandaNode *> NodeMap;
typedef pmap<const PartGroup *, PartGroup *> JointMap;

View File

@ -37,10 +37,10 @@ CharacterJointBundle(const CharacterJointBundle &copy) :
////////////////////////////////////////////////////////////////////
// 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));
}

View File

@ -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

View File

@ -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);

View File

@ -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 {

View File

@ -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);

View File

@ -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 \

View File

@ -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();

View File

@ -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;

View File

@ -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());
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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"

View File

@ -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 {

View File

@ -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);

View File

@ -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 "

View File

@ -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;

View File

@ -233,6 +233,9 @@ get_current_pipeline_stage() {
////////////////////////////////////////////////////////////////////
INLINE bool Thread::
is_threading_supported() {
if (!support_threads) {
return false;
}
return ThreadImpl::is_threading_supported();
}

View File

@ -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) {

View File

@ -25,6 +25,7 @@
#include "threadPriority.h"
#include "threadImpl.h"
#include "pnotify.h"
#include "config_pipeline.h"
class Mutex;
class ReMutex;

View File

@ -29,9 +29,6 @@
#include "mutexWin32Impl.h"
#include "conditionVarWin32Impl.h"
#define WIN32_LEAN_AND_MEAN 1
#include <windows.h>
class Thread;
////////////////////////////////////////////////////////////////////