mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -04:00
progress on multithreaded Panda
This commit is contained in:
parent
08693413e8
commit
c3d8f81581
@ -188,7 +188,13 @@ ConfigVariableBool auto_break_cycles
|
|||||||
PRC_DESC("Set this true to automatically detect and break reference-count "
|
PRC_DESC("Set this true to automatically detect and break reference-count "
|
||||||
"cycles in the TransformState and RenderState caches. When this "
|
"cycles in the TransformState and RenderState caches. When this "
|
||||||
"is false, you must explicitly call TransformState.clear_cache() "
|
"is false, you must explicitly call TransformState.clear_cache() "
|
||||||
"from time to time to prevent gradual memory bloat."));
|
"from time to time to prevent gradual memory bloat. This has "
|
||||||
|
"no meaning when garbage-collect-states is true."));
|
||||||
|
|
||||||
|
ConfigVariableBool garbage_collect_states
|
||||||
|
("garbage-collect-states", false,
|
||||||
|
PRC_DESC("This temporary config variable is used for development only. "
|
||||||
|
"Do not set!"));
|
||||||
|
|
||||||
ConfigVariableBool transform_cache
|
ConfigVariableBool transform_cache
|
||||||
("transform-cache", true,
|
("transform-cache", true,
|
||||||
|
@ -44,6 +44,7 @@ extern ConfigVariableBool compose_componentwise;
|
|||||||
extern ConfigVariableBool uniquify_matrix;
|
extern ConfigVariableBool uniquify_matrix;
|
||||||
extern ConfigVariableBool paranoid_const;
|
extern ConfigVariableBool paranoid_const;
|
||||||
extern ConfigVariableBool auto_break_cycles;
|
extern ConfigVariableBool auto_break_cycles;
|
||||||
|
extern ConfigVariableBool garbage_collect_states;
|
||||||
extern ConfigVariableBool transform_cache;
|
extern ConfigVariableBool transform_cache;
|
||||||
extern ConfigVariableBool state_cache;
|
extern ConfigVariableBool state_cache;
|
||||||
extern ConfigVariableBool uniquify_transforms;
|
extern ConfigVariableBool uniquify_transforms;
|
||||||
|
@ -144,6 +144,11 @@ cull_callback(CullTraverser *, const CullTraverserData &) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderAttrib::
|
bool RenderAttrib::
|
||||||
unref() const {
|
unref() const {
|
||||||
|
// This is flawed, but this is development only.
|
||||||
|
if (garbage_collect_states) {
|
||||||
|
return ReferenceCount::unref();
|
||||||
|
}
|
||||||
|
|
||||||
// We always have to grab the lock, since we will definitely need to
|
// We always have to grab the lock, since we will definitely need to
|
||||||
// be holding it if we happen to drop the reference count to 0.
|
// be holding it if we happen to drop the reference count to 0.
|
||||||
LightReMutexHolder holder(*_attribs_lock);
|
LightReMutexHolder holder(*_attribs_lock);
|
||||||
|
@ -419,11 +419,9 @@ compose(const RenderState *other) const {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!state_cache) {
|
if (!state_cache) {
|
||||||
return do_compose(other);
|
return do_compose(other);
|
||||||
}
|
}
|
||||||
#endif // NDEBUG
|
|
||||||
|
|
||||||
LightReMutexHolder holder(*_states_lock);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
|
|
||||||
@ -516,11 +514,9 @@ invert_compose(const RenderState *other) const {
|
|||||||
return make_empty();
|
return make_empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!state_cache) {
|
if (!state_cache) {
|
||||||
return do_invert_compose(other);
|
return do_invert_compose(other);
|
||||||
}
|
}
|
||||||
#endif // NDEBUG
|
|
||||||
|
|
||||||
LightReMutexHolder holder(*_states_lock);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
|
|
||||||
@ -706,6 +702,11 @@ adjust_all_priorities(int adjustment) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool RenderState::
|
bool RenderState::
|
||||||
unref() const {
|
unref() const {
|
||||||
|
// This is flawed, but this is development only.
|
||||||
|
if (garbage_collect_states) {
|
||||||
|
return ReferenceCount::unref();
|
||||||
|
}
|
||||||
|
|
||||||
// We always have to grab the lock, since we will definitely need to
|
// We always have to grab the lock, since we will definitely need to
|
||||||
// be holding it if we happen to drop the reference count to 0.
|
// be holding it if we happen to drop the reference count to 0.
|
||||||
LightReMutexHolder holder(*_states_lock);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
@ -1460,11 +1461,9 @@ CPT(RenderState) RenderState::
|
|||||||
return_unique(RenderState *state) {
|
return_unique(RenderState *state) {
|
||||||
nassertr(state != (RenderState *)NULL, state);
|
nassertr(state != (RenderState *)NULL, state);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!state_cache) {
|
if (!state_cache) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (paranoid_const) {
|
if (paranoid_const) {
|
||||||
|
@ -579,10 +579,6 @@ set_shear2d(float shear) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
CPT(TransformState) TransformState::
|
CPT(TransformState) TransformState::
|
||||||
compose(const TransformState *other) const {
|
compose(const TransformState *other) const {
|
||||||
// This method isn't strictly const, because it updates the cache,
|
|
||||||
// but we pretend that it is because it's only a cache which is
|
|
||||||
// transparent to the rest of the interface.
|
|
||||||
|
|
||||||
// We handle identity as a trivial special case.
|
// We handle identity as a trivial special case.
|
||||||
if (is_identity()) {
|
if (is_identity()) {
|
||||||
return other;
|
return other;
|
||||||
@ -599,72 +595,37 @@ compose(const TransformState *other) const {
|
|||||||
return other;
|
return other;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!transform_cache) {
|
if (!transform_cache) {
|
||||||
return do_compose(other);
|
return do_compose(other);
|
||||||
}
|
}
|
||||||
#endif // NDEBUG
|
|
||||||
|
|
||||||
LightReMutexHolder holder(*_states_lock);
|
|
||||||
|
|
||||||
// Is this composition already cached?
|
// Is this composition already cached?
|
||||||
int index = _composition_cache.find(other);
|
CPT(TransformState) result;
|
||||||
if (index != -1) {
|
{
|
||||||
Composition &comp = ((TransformState *)this)->_composition_cache.modify_data(index);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
if (comp._result == (const TransformState *)NULL) {
|
int index = _composition_cache.find(other);
|
||||||
// Well, it wasn't cached already, but we already had an entry
|
if (index != -1) {
|
||||||
// (probably created for the reverse direction), so use the same
|
const Composition &comp = _composition_cache.get_data(index);
|
||||||
// entry to store the new result.
|
result = comp._result;
|
||||||
CPT(TransformState) result = do_compose(other);
|
}
|
||||||
comp._result = result;
|
if (result != (TransformState *)NULL) {
|
||||||
|
_cache_stats.inc_hits();
|
||||||
if (result != (const TransformState *)this) {
|
|
||||||
// See the comments below about the need to up the reference
|
|
||||||
// count only when the result is not the same as this.
|
|
||||||
result->cache_ref();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Here's the cache!
|
|
||||||
_cache_stats.inc_hits();
|
|
||||||
return comp._result;
|
|
||||||
}
|
|
||||||
_cache_stats.inc_misses();
|
|
||||||
|
|
||||||
// We need to make a new cache entry, both in this object and in the
|
|
||||||
// other object. We make both records so the other TransformState
|
|
||||||
// object will know to delete the entry from this object when it
|
|
||||||
// destructs, and vice-versa.
|
|
||||||
|
|
||||||
// The cache entry in this object is the only one that indicates the
|
|
||||||
// result; the other will be NULL for now.
|
|
||||||
CPT(TransformState) result = do_compose(other);
|
|
||||||
|
|
||||||
_cache_stats.add_total_size(1);
|
|
||||||
_cache_stats.inc_adds(_composition_cache.get_size() == 0);
|
|
||||||
|
|
||||||
((TransformState *)this)->_composition_cache[other]._result = result;
|
|
||||||
|
|
||||||
if (other != this) {
|
|
||||||
_cache_stats.add_total_size(1);
|
|
||||||
_cache_stats.inc_adds(other->_composition_cache.get_size() == 0);
|
|
||||||
((TransformState *)other)->_composition_cache[this]._result = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != (const TransformState *)this) {
|
if (result != (TransformState *)NULL) {
|
||||||
// If the result of compose() is something other than this,
|
// Success!
|
||||||
// explicitly increment the reference count. We have to be sure
|
return result;
|
||||||
// to decrement it again later, when the composition entry is
|
|
||||||
// removed from the cache.
|
|
||||||
result->cache_ref();
|
|
||||||
|
|
||||||
// (If the result was just this again, we still store the
|
|
||||||
// result, but we don't increment the reference count, since
|
|
||||||
// that would be a self-referential leak.)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_cache_stats.maybe_report("TransformState");
|
// Not in the cache. Compute a new result. It's important that we
|
||||||
|
// don't hold the lock while we do this, or we lose the benefit of
|
||||||
|
// parallelization.
|
||||||
|
result = do_compose(other);
|
||||||
|
|
||||||
return result;
|
// It's OK to cast away the constness of this pointer, because the
|
||||||
|
// cache is a transparent property of the class.
|
||||||
|
return ((TransformState *)this)->store_compose(other, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -704,69 +665,38 @@ invert_compose(const TransformState *other) const {
|
|||||||
return make_identity();
|
return make_identity();
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!transform_cache) {
|
if (!transform_cache) {
|
||||||
return do_invert_compose(other);
|
return do_invert_compose(other);
|
||||||
}
|
}
|
||||||
#endif // NDEBUG
|
|
||||||
|
|
||||||
LightReMutexHolder holder(*_states_lock);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
|
|
||||||
// Is this composition already cached?
|
CPT(TransformState) result;
|
||||||
int index = _invert_composition_cache.find(other);
|
{
|
||||||
if (index != -1) {
|
LightReMutexHolder holder(*_states_lock);
|
||||||
Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index);
|
int index = _invert_composition_cache.find(other);
|
||||||
if (comp._result == (const TransformState *)NULL) {
|
if (index != -1) {
|
||||||
// Well, it wasn't cached already, but we already had an entry
|
const Composition &comp = _invert_composition_cache.get_data(index);
|
||||||
// (probably created for the reverse direction), so use the same
|
result = comp._result;
|
||||||
// entry to store the new result.
|
}
|
||||||
CPT(TransformState) result = do_invert_compose(other);
|
if (result != (TransformState *)NULL) {
|
||||||
comp._result = result;
|
_cache_stats.inc_hits();
|
||||||
|
|
||||||
if (result != (const TransformState *)this) {
|
|
||||||
// See the comments below about the need to up the reference
|
|
||||||
// count only when the result is not the same as this.
|
|
||||||
result->cache_ref();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
// Here's the cache!
|
|
||||||
_cache_stats.inc_hits();
|
|
||||||
return comp._result;
|
|
||||||
}
|
|
||||||
_cache_stats.inc_misses();
|
|
||||||
|
|
||||||
// We need to make a new cache entry, both in this object and in the
|
|
||||||
// other object. We make both records so the other TransformState
|
|
||||||
// object will know to delete the entry from this object when it
|
|
||||||
// destructs, and vice-versa.
|
|
||||||
|
|
||||||
// The cache entry in this object is the only one that indicates the
|
|
||||||
// result; the other will be NULL for now.
|
|
||||||
CPT(TransformState) result = do_invert_compose(other);
|
|
||||||
|
|
||||||
_cache_stats.add_total_size(1);
|
|
||||||
_cache_stats.inc_adds(_invert_composition_cache.get_size() == 0);
|
|
||||||
((TransformState *)this)->_invert_composition_cache[other]._result = result;
|
|
||||||
|
|
||||||
if (other != this) {
|
|
||||||
_cache_stats.add_total_size(1);
|
|
||||||
_cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0);
|
|
||||||
((TransformState *)other)->_invert_composition_cache[this]._result = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result != (const TransformState *)this) {
|
if (result != (TransformState *)NULL) {
|
||||||
// If the result of compose() is something other than this,
|
// Success!
|
||||||
// explicitly increment the reference count. We have to be sure
|
return result;
|
||||||
// to decrement it again later, when the composition entry is
|
|
||||||
// removed from the cache.
|
|
||||||
result->cache_ref();
|
|
||||||
|
|
||||||
// (If the result was just this again, we still store the
|
|
||||||
// result, but we don't increment the reference count, since
|
|
||||||
// that would be a self-referential leak.)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
// Not in the cache. Compute a new result. It's important that we
|
||||||
|
// don't hold the lock while we do this, or we lose the benefit of
|
||||||
|
// parallelization.
|
||||||
|
result = do_invert_compose(other);
|
||||||
|
|
||||||
|
// It's OK to cast away the constness of this pointer, because the
|
||||||
|
// cache is a transparent property of the class.
|
||||||
|
return ((TransformState *)this)->store_invert_compose(other, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
@ -781,6 +711,11 @@ invert_compose(const TransformState *other) const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
bool TransformState::
|
bool TransformState::
|
||||||
unref() const {
|
unref() const {
|
||||||
|
// This is flawed, but this is development only.
|
||||||
|
if (garbage_collect_states) {
|
||||||
|
return ReferenceCount::unref();
|
||||||
|
}
|
||||||
|
|
||||||
// We always have to grab the lock, since we will definitely need to
|
// We always have to grab the lock, since we will definitely need to
|
||||||
// be holding it if we happen to drop the reference count to 0.
|
// be holding it if we happen to drop the reference count to 0.
|
||||||
LightReMutexHolder holder(*_states_lock);
|
LightReMutexHolder holder(*_states_lock);
|
||||||
@ -1526,11 +1461,9 @@ CPT(TransformState) TransformState::
|
|||||||
return_unique(TransformState *state) {
|
return_unique(TransformState *state) {
|
||||||
nassertr(state != (TransformState *)NULL, state);
|
nassertr(state != (TransformState *)NULL, state);
|
||||||
|
|
||||||
#ifndef NDEBUG
|
|
||||||
if (!transform_cache) {
|
if (!transform_cache) {
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
if (paranoid_const) {
|
if (paranoid_const) {
|
||||||
@ -1647,6 +1580,158 @@ do_compose(const TransformState *other) const {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TransformState::store_compose
|
||||||
|
// Access: Private
|
||||||
|
// Description: Stores the result of a composition in the cache.
|
||||||
|
// Returns the stored result (it may be a different
|
||||||
|
// object than the one passed in, due to another thread
|
||||||
|
// having computed the composition first).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
CPT(TransformState) TransformState::
|
||||||
|
store_compose(const TransformState *other, const TransformState *result) {
|
||||||
|
// Identity should have already been screened.
|
||||||
|
nassertr(!is_identity(), other);
|
||||||
|
nassertr(!other->is_identity(), this);
|
||||||
|
|
||||||
|
// So should have validity.
|
||||||
|
nassertr(!is_invalid(), this);
|
||||||
|
nassertr(!other->is_invalid(), other);
|
||||||
|
|
||||||
|
LightReMutexHolder holder(*_states_lock);
|
||||||
|
|
||||||
|
// Is this composition already cached?
|
||||||
|
int index = _composition_cache.find(other);
|
||||||
|
if (index != -1) {
|
||||||
|
Composition &comp = _composition_cache.modify_data(index);
|
||||||
|
if (comp._result == (const TransformState *)NULL) {
|
||||||
|
// Well, it wasn't cached already, but we already had an entry
|
||||||
|
// (probably created for the reverse direction), so use the same
|
||||||
|
// entry to store the new result.
|
||||||
|
comp._result = result;
|
||||||
|
|
||||||
|
if (result != (const TransformState *)this) {
|
||||||
|
// See the comments below about the need to up the reference
|
||||||
|
// count only when the result is not the same as this.
|
||||||
|
result->cache_ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Here's the cache!
|
||||||
|
_cache_stats.inc_hits();
|
||||||
|
return comp._result;
|
||||||
|
}
|
||||||
|
_cache_stats.inc_misses();
|
||||||
|
|
||||||
|
// We need to make a new cache entry, both in this object and in the
|
||||||
|
// other object. We make both records so the other TransformState
|
||||||
|
// object will know to delete the entry from this object when it
|
||||||
|
// destructs, and vice-versa.
|
||||||
|
|
||||||
|
// The cache entry in this object is the only one that indicates the
|
||||||
|
// result; the other will be NULL for now.
|
||||||
|
_cache_stats.add_total_size(1);
|
||||||
|
_cache_stats.inc_adds(_composition_cache.get_size() == 0);
|
||||||
|
|
||||||
|
_composition_cache[other]._result = result;
|
||||||
|
|
||||||
|
if (other != this) {
|
||||||
|
_cache_stats.add_total_size(1);
|
||||||
|
_cache_stats.inc_adds(other->_composition_cache.get_size() == 0);
|
||||||
|
((TransformState *)other)->_composition_cache[this]._result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != (TransformState *)this) {
|
||||||
|
// If the result of do_compose() is something other than this,
|
||||||
|
// explicitly increment the reference count. We have to be sure
|
||||||
|
// to decrement it again later, when the composition entry is
|
||||||
|
// removed from the cache.
|
||||||
|
result->cache_ref();
|
||||||
|
|
||||||
|
// (If the result was just this again, we still store the
|
||||||
|
// result, but we don't increment the reference count, since
|
||||||
|
// that would be a self-referential leak.)
|
||||||
|
}
|
||||||
|
|
||||||
|
_cache_stats.maybe_report("TransformState");
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: TransformState::store_invert_compose
|
||||||
|
// Access: Private
|
||||||
|
// Description: Stores the result of a composition in the cache.
|
||||||
|
// Returns the stored result (it may be a different
|
||||||
|
// object than the one passed in, due to another thread
|
||||||
|
// having computed the composition first).
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
CPT(TransformState) TransformState::
|
||||||
|
store_invert_compose(const TransformState *other, const TransformState *result) {
|
||||||
|
// Identity should have already been screened.
|
||||||
|
nassertr(!is_identity(), other);
|
||||||
|
|
||||||
|
// So should have validity.
|
||||||
|
nassertr(!is_invalid(), this);
|
||||||
|
nassertr(!other->is_invalid(), other);
|
||||||
|
|
||||||
|
nassertr(other != this, make_identity());
|
||||||
|
|
||||||
|
LightReMutexHolder holder(*_states_lock);
|
||||||
|
|
||||||
|
// Is this composition already cached?
|
||||||
|
int index = _invert_composition_cache.find(other);
|
||||||
|
if (index != -1) {
|
||||||
|
Composition &comp = ((TransformState *)this)->_invert_composition_cache.modify_data(index);
|
||||||
|
if (comp._result == (const TransformState *)NULL) {
|
||||||
|
// Well, it wasn't cached already, but we already had an entry
|
||||||
|
// (probably created for the reverse direction), so use the same
|
||||||
|
// entry to store the new result.
|
||||||
|
comp._result = result;
|
||||||
|
|
||||||
|
if (result != (const TransformState *)this) {
|
||||||
|
// See the comments below about the need to up the reference
|
||||||
|
// count only when the result is not the same as this.
|
||||||
|
result->cache_ref();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Here's the cache!
|
||||||
|
_cache_stats.inc_hits();
|
||||||
|
return comp._result;
|
||||||
|
}
|
||||||
|
_cache_stats.inc_misses();
|
||||||
|
|
||||||
|
// We need to make a new cache entry, both in this object and in the
|
||||||
|
// other object. We make both records so the other TransformState
|
||||||
|
// object will know to delete the entry from this object when it
|
||||||
|
// destructs, and vice-versa.
|
||||||
|
|
||||||
|
// The cache entry in this object is the only one that indicates the
|
||||||
|
// result; the other will be NULL for now.
|
||||||
|
_cache_stats.add_total_size(1);
|
||||||
|
_cache_stats.inc_adds(_invert_composition_cache.get_size() == 0);
|
||||||
|
_invert_composition_cache[other]._result = result;
|
||||||
|
|
||||||
|
if (other != this) {
|
||||||
|
_cache_stats.add_total_size(1);
|
||||||
|
_cache_stats.inc_adds(other->_invert_composition_cache.get_size() == 0);
|
||||||
|
((TransformState *)other)->_invert_composition_cache[this]._result = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result != (TransformState *)this) {
|
||||||
|
// If the result of compose() is something other than this,
|
||||||
|
// explicitly increment the reference count. We have to be sure
|
||||||
|
// to decrement it again later, when the composition entry is
|
||||||
|
// removed from the cache.
|
||||||
|
result->cache_ref();
|
||||||
|
|
||||||
|
// (If the result was just this again, we still store the
|
||||||
|
// result, but we don't increment the reference count, since
|
||||||
|
// that would be a self-referential leak.)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: TransformState::do_invert_compose
|
// Function: TransformState::do_invert_compose
|
||||||
// Access: Private
|
// Access: Private
|
||||||
|
@ -234,7 +234,9 @@ private:
|
|||||||
static CPT(TransformState) return_unique(TransformState *state);
|
static CPT(TransformState) return_unique(TransformState *state);
|
||||||
|
|
||||||
CPT(TransformState) do_compose(const TransformState *other) const;
|
CPT(TransformState) do_compose(const TransformState *other) const;
|
||||||
|
CPT(TransformState) store_compose(const TransformState *other, const TransformState *result);
|
||||||
CPT(TransformState) do_invert_compose(const TransformState *other) const;
|
CPT(TransformState) do_invert_compose(const TransformState *other) const;
|
||||||
|
CPT(TransformState) store_invert_compose(const TransformState *other, const TransformState *result);
|
||||||
static bool r_detect_cycles(const TransformState *start_state,
|
static bool r_detect_cycles(const TransformState *start_state,
|
||||||
const TransformState *current_state,
|
const TransformState *current_state,
|
||||||
int length, UpdateSeq this_seq,
|
int length, UpdateSeq this_seq,
|
||||||
|
@ -213,16 +213,20 @@ load_gridded_models(WindowFramework *window,
|
|||||||
// Load up all the files indicated in the list of gridded filenames
|
// Load up all the files indicated in the list of gridded filenames
|
||||||
// and store them in the given vector.
|
// and store them in the given vector.
|
||||||
|
|
||||||
|
Loader loader;
|
||||||
|
LoaderOptions options;
|
||||||
|
options.set_flags(options.get_flags() | LoaderOptions::LF_no_ram_cache);
|
||||||
|
|
||||||
// First, load up each model from disk once, and store them all
|
// First, load up each model from disk once, and store them all
|
||||||
// separate from the scene graph. Also count up the total number of
|
// separate from the scene graph. Also count up the total number of
|
||||||
// models we'll be putting in the grid.
|
// models we'll be putting in the grid.
|
||||||
int grid_count = 0;
|
int grid_count = 0;
|
||||||
NodePath models("models");
|
|
||||||
GriddedFilenames::iterator fi;
|
GriddedFilenames::iterator fi;
|
||||||
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
|
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
|
||||||
GriddedFilename &gf = (*fi);
|
GriddedFilename &gf = (*fi);
|
||||||
gf._model = window->load_model(models, gf._filename);
|
PT(PandaNode) node = loader.load_sync(gf._filename, options);
|
||||||
if (!gf._model.is_empty()) {
|
if (node != (PandaNode *)NULL) {
|
||||||
|
gf._model = NodePath(node);
|
||||||
grid_count += gf._count;
|
grid_count += gf._count;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -254,7 +258,7 @@ load_gridded_models(WindowFramework *window,
|
|||||||
int passnum = 0;
|
int passnum = 0;
|
||||||
bool loaded_any;
|
bool loaded_any;
|
||||||
|
|
||||||
NodePath render = window->get_render();
|
NodePath root = window->get_panda_framework()->get_models();
|
||||||
do {
|
do {
|
||||||
loaded_any = false;
|
loaded_any = false;
|
||||||
|
|
||||||
@ -265,9 +269,15 @@ load_gridded_models(WindowFramework *window,
|
|||||||
// Copy this model into the scene graph, and assign it a
|
// Copy this model into the scene graph, and assign it a
|
||||||
// position on the grid.
|
// position on the grid.
|
||||||
|
|
||||||
string model_name = format_string(++model_count);
|
++model_count;
|
||||||
NodePath model = render.attach_new_node(model_name);
|
PT(PandaNode) node = loader.load_sync(gf._filename, options);
|
||||||
gf._model.copy_to(model);
|
NodePath model;
|
||||||
|
if (node == (PandaNode *)NULL) {
|
||||||
|
model = gf._model.copy_to(NodePath());
|
||||||
|
} else {
|
||||||
|
model = NodePath(node);
|
||||||
|
}
|
||||||
|
model.reparent_to(root);
|
||||||
|
|
||||||
gridded_file_info info;
|
gridded_file_info info;
|
||||||
info.node = model.node();
|
info.node = model.node();
|
||||||
@ -369,14 +379,6 @@ load_gridded_models(WindowFramework *window,
|
|||||||
|
|
||||||
passnum++;
|
passnum++;
|
||||||
} while (loaded_any);
|
} while (loaded_any);
|
||||||
|
|
||||||
// Finally, remove the source models we loaded up. Not a real big deal.
|
|
||||||
for (fi = filenames.begin(); fi != filenames.end(); ++fi) {
|
|
||||||
GriddedFilename &gf = (*fi);
|
|
||||||
if (!gf._model.is_empty()) {
|
|
||||||
gf._model.remove_node();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -402,13 +404,15 @@ main(int argc, char *argv[]) {
|
|||||||
|
|
||||||
window->enable_keyboard();
|
window->enable_keyboard();
|
||||||
window->setup_trackball();
|
window->setup_trackball();
|
||||||
window->load_models(window->get_render(), static_filenames);
|
window->load_models(framework.get_models(), static_filenames);
|
||||||
|
framework.get_models().instance_to(window->get_render());
|
||||||
|
|
||||||
GriddedInfoArray info_arr;
|
GriddedInfoArray info_arr;
|
||||||
load_gridded_models(window, gridded_filenames, info_arr);
|
load_gridded_models(window, gridded_filenames, info_arr);
|
||||||
|
|
||||||
window->loop_animations();
|
window->loop_animations();
|
||||||
window->stagger_animations();
|
window->stagger_animations();
|
||||||
|
window->center_trackball(framework.get_models());
|
||||||
|
|
||||||
framework.enable_default_keys();
|
framework.enable_default_keys();
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user