asynchronous animation binding

This commit is contained in:
David Rose 2008-08-07 17:26:39 +00:00
parent 0f83ba7fe1
commit 6d953de53a
42 changed files with 7191 additions and 6774 deletions

View File

@ -20,7 +20,10 @@
animChannelScalarTable.I animChannelScalarTable.h \
animControl.I animControl.N \
animControl.h animControlCollection.I \
animControlCollection.h animGroup.I animGroup.h auto_bind.h \
animControlCollection.h animGroup.I animGroup.h \
animPreloadTable.I animPreloadTable.h \
auto_bind.h \
bindAnimRequest.I bindAnimRequest.h \
config_chan.h \
movingPart.I movingPart.h \
movingPartBase.I movingPartBase.h \
@ -43,7 +46,10 @@
animChannelScalarDynamic.cxx \
animChannelScalarTable.cxx \
animControl.cxx \
animControlCollection.cxx animGroup.cxx auto_bind.cxx \
animControlCollection.cxx animGroup.cxx \
animPreloadTable.cxx \
auto_bind.cxx \
bindAnimRequest.cxx \
config_chan.cxx movingPartBase.cxx movingPartMatrix.cxx \
movingPartScalar.cxx partBundle.cxx \
partBundleHandle.cxx \
@ -64,7 +70,11 @@
animChannelScalarTable.I animChannelScalarTable.h \
animControl.I animControl.h \
animControlCollection.I animControlCollection.h animGroup.I \
animGroup.h auto_bind.h config_chan.h \
animGroup.h \
animPreloadTable.I animPreloadTable.h \
auto_bind.h \
bindAnimRequest.I bindAnimRequest.h \
config_chan.h \
movingPart.I movingPart.h movingPartBase.I \
movingPartBase.h movingPartMatrix.I movingPartMatrix.h \
movingPartScalar.I movingPartScalar.h partBundle.I partBundle.h \

View File

@ -45,6 +45,38 @@ safe_to_flatten() const {
return false;
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleNode::find_anim_bundle
// Access: Published, Static
// Description: Recursively walks the scene graph beginning at the
// indicated node (which need not be an AnimBundleNode),
// and returns the first AnimBundle found. Returns NULL
// if no AnimBundle can be found.
////////////////////////////////////////////////////////////////////
AnimBundle *AnimBundleNode::
find_anim_bundle(PandaNode *root) {
nassertr(root != (PandaNode *)NULL, NULL);
if (root->is_of_type(AnimBundleNode::get_class_type())) {
AnimBundleNode *anode = DCAST(AnimBundleNode, root);
AnimBundle *anim = anode->get_bundle();
if (anim != (AnimBundle *)NULL) {
return anim;
}
}
Children cr = root->get_children();
int num_children = cr.get_num_children();
for (int i = 0; i < num_children; i++) {
AnimBundle *anim = find_anim_bundle(cr.get_child(i));
if (anim != (AnimBundle *)NULL) {
return anim;
}
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: AnimBundleNode::register_with_read_factory
// Access: Public, Static

View File

@ -42,6 +42,8 @@ public:
PUBLISHED:
INLINE AnimBundle *get_bundle() const;
static AnimBundle *find_anim_bundle(PandaNode *root);
private:
PT(AnimBundle) _bundle;

View File

@ -13,6 +13,33 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: AnimControl::is_pending
// Access: Published
// Description: Returns true if the AnimControl is being bound
// asynchronously, and has not yet finished. If this is
// true, the AnimControl's interface is still available
// and will be perfectly useful (though get_anim() might
// return NULL), but nothing visible will happen
// immediately.
////////////////////////////////////////////////////////////////////
INLINE bool AnimControl::
is_pending() const {
return _pending;
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::has_anim
// Access: Published
// Description: Returns true if the AnimControl was successfully
// loaded, or false if there was a problem. This may
// return false while is_pending() is true.
////////////////////////////////////////////////////////////////////
INLINE bool AnimControl::
has_anim() const {
return (_anim != (AnimBundle *)NULL);
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::get_anim
// Access: Published
@ -56,3 +83,41 @@ INLINE const BitArray &AnimControl::
get_bound_joints() const {
return _bound_joints;
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::set_anim_model
// Access: Published
// Description: Associates the indicated PandaNode with the
// AnimControl. By convention, this node represents the
// root node of the model file that corresponds to this
// AnimControl's animation file, though nothing in this
// code makes this assumption or indeed does anything
// with this node.
//
// The purpose of this is simply to allow the
// AnimControl to keep a reference count on the
// ModelRoot node that generated it, so that the model
// will not disappear from the model pool until it is no
// longer referenced.
////////////////////////////////////////////////////////////////////
INLINE void AnimControl::
set_anim_model(PandaNode *model) {
_anim_model = model;
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::get_anim_model
// Access: Published
// Description: Retrieves the pointer set via set_anim_model(). See
// set_anim_model().
////////////////////////////////////////////////////////////////////
INLINE PandaNode *AnimControl::
get_anim_model() const {
return _anim_model;
}
INLINE ostream &
operator << (ostream &out, const AnimControl &control) {
control.output(out);
return out;
}

View File

@ -17,29 +17,81 @@
#include "partBundle.h"
#include "config_chan.h"
#include "dcast.h"
#include "mutexHolder.h"
#include "throw_event.h"
TypeHandle AnimControl::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AnimControl::Constructor
// Access: Public
// Description:
// Description: This constructor is used to create a temporarily
// uninitialized AnimControl that will serve as a
// placeholder for an animation while the animation is
// being loaded during an asynchronous load-and-bind
// operation.
////////////////////////////////////////////////////////////////////
AnimControl::
AnimControl(PartBundle *part, AnimBundle *anim, int channel_index,
const BitArray &bound_joints) {
AnimControl(const string &name, PartBundle *part,
double frame_rate, int num_frames) :
Namable(name)
{
#ifdef DO_MEMORY_USAGE
MemoryUsage::update_type(this, get_class_type());
#endif
_pending = true;
_part = part;
_anim = NULL;
_channel_index = -1;
set_frame_rate(frame_rate);
set_num_frames(num_frames);
_marked_frame = -1;
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::setup_anim
// Access: Public
// Description: This can only be called once for a given AnimControl.
// It is used to supply the AnimBundle and related
// information.
////////////////////////////////////////////////////////////////////
void AnimControl::
setup_anim(PartBundle *part, AnimBundle *anim, int channel_index,
const BitArray &bound_joints) {
MutexHolder holder(_pending_lock);
nassertv(_pending && part == _part);
nassertv(_anim == (AnimBundle *)NULL);
_anim = anim;
_channel_index = channel_index;
_bound_joints = bound_joints;
set_frame_rate(_anim->get_base_frame_rate());
set_num_frames(_anim->get_num_frames());
// Now the AnimControl is fully set up.
_marked_frame = -1;
_pending = false;
if (!_pending_done_event.empty()) {
throw_event(_pending_done_event);
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::fail_anim
// Access: Public
// Description: This can only be called once for a given AnimControl.
// It indicates the attempt to bind it asynchronously
// has failed.
////////////////////////////////////////////////////////////////////
void AnimControl::
fail_anim(PartBundle *part) {
MutexHolder holder(_pending_lock);
nassertv(_pending && part == _part);
_pending = false;
if (!_pending_done_event.empty()) {
throw_event(_pending_done_event);
}
}
////////////////////////////////////////////////////////////////////
@ -52,6 +104,35 @@ AnimControl::
get_part()->set_control_effect(this, 0.0f);
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::set_pending_done_event
// Access: Published
// Description: Specifies an event name that will be thrown when the
// AnimControl is finished binding asynchronously. If
// the AnimControl has already finished binding, the
// event will be thrown immediately.
////////////////////////////////////////////////////////////////////
void AnimControl::
set_pending_done_event(const string &done_event) {
MutexHolder holder(_pending_lock);
_pending_done_event = done_event;
if (!_pending) {
throw_event(_pending_done_event);
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::get_pending_done_event
// Access: Published
// Description: Returns the event name that will be thrown when the
// AnimControl is finished binding asynchronously.
////////////////////////////////////////////////////////////////////
string AnimControl::
get_pending_done_event() const {
MutexHolder holder(_pending_lock);
return _pending_done_event;
}
////////////////////////////////////////////////////////////////////
// Function: AnimControl::get_part
// Access: Published
@ -70,10 +151,16 @@ get_part() const {
////////////////////////////////////////////////////////////////////
void AnimControl::
output(ostream &out) const {
out << "AnimControl(" << get_part()->get_name()
<< ", " << get_anim()->get_name() << ": ";
out << "AnimControl(" << get_name() << ", " << get_part()->get_name()
<< ": ";
AnimInterface::output(out);
out << ")";
if (is_pending()) {
out << " (pending bind)";
} else if (!has_anim()) {
out << " (failed bind)";
}
}
////////////////////////////////////////////////////////////////////

View File

@ -21,8 +21,10 @@
#include "animBundle.h"
#include "partGroup.h"
#include "bitArray.h"
#include "referenceCount.h"
#include "pandaNode.h"
#include "typedReferenceCount.h"
#include "namable.h"
#include "pmutex.h"
class PartBundle;
class AnimChannelBase;
@ -35,19 +37,30 @@ class AnimChannelBase;
// animation: whether started, stopped, or looping, and
// the current frame number and play rate.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_CHAN AnimControl : public ReferenceCount, public AnimInterface {
class EXPCL_PANDA_CHAN AnimControl : public TypedReferenceCount, public AnimInterface, public Namable {
public:
AnimControl(PartBundle *part, AnimBundle *anim, int channel_index,
const BitArray &bound_joints);
AnimControl(const string &name, PartBundle *part,
double frame_rate, int num_frames);
void setup_anim(PartBundle *part, AnimBundle *anim, int channel_index,
const BitArray &bound_joints);
void fail_anim(PartBundle *part);
PUBLISHED:
virtual ~AnimControl();
INLINE bool is_pending() const;
INLINE bool has_anim() const;
void set_pending_done_event(const string &done_event);
string get_pending_done_event() const;
PartBundle *get_part() const;
INLINE AnimBundle *get_anim() const;
INLINE int get_channel_index() const;
INLINE const BitArray &get_bound_joints() const;
INLINE void set_anim_model(PandaNode *model);
INLINE PandaNode *get_anim_model() const;
virtual void output(ostream &out) const;
public:
@ -65,6 +78,10 @@ private:
// This is a PT(PartGroup) instead of a PT(PartBundle), just because
// we can't include partBundle.h for circular reasons. But it
// actually keeps a pointer to a PartBundle.
bool _pending;
string _pending_done_event;
Mutex _pending_lock; // protects the above two.
PT(PartGroup) _part;
PT(AnimBundle) _anim;
int _channel_index;
@ -80,15 +97,22 @@ private:
// get_bound_joints().
BitArray _bound_joints;
PT(PandaNode) _anim_model;
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ReferenceCount::init_type();
TypedReferenceCount::init_type();
AnimInterface::init_type();
register_type(_type_handle, "AnimControl",
ReferenceCount::get_class_type(),
TypedReferenceCount::get_class_type(),
AnimInterface::get_class_type());
}
@ -96,6 +120,8 @@ private:
static TypeHandle _type_handle;
};
INLINE ostream &operator << (ostream &out, const AnimControl &control);
#include "animControl.I"
#endif

View File

@ -0,0 +1,86 @@
// Filename: animPreloadTable.I
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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: AnimPreloadTable::AnimRecord::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE AnimPreloadTable::AnimRecord::
AnimRecord() {
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::AnimRecord::operator <
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool AnimPreloadTable::AnimRecord::
operator < (const AnimRecord &other) const {
return _basename < other._basename;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::get_basename
// Access: Published
// Description: Returns the basename stored for the nth animation
// record. See find_anim().
////////////////////////////////////////////////////////////////////
INLINE string AnimPreloadTable::
get_basename(int n) const {
nassertr(n >= 0 && n < (int)_anims.size(), string());
consider_sort();
return _anims[n]._basename;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::get_base_frame_rate
// Access: Published
// Description: Returns the frame rate stored for the nth animation
// record.
////////////////////////////////////////////////////////////////////
INLINE float AnimPreloadTable::
get_base_frame_rate(int n) const {
nassertr(n >= 0 && n < (int)_anims.size(), 0.0f);
consider_sort();
return _anims[n]._base_frame_rate;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::get_num_frames
// Access: Published
// Description: Returns the number of frames stored for the nth
// animation record.
////////////////////////////////////////////////////////////////////
INLINE int AnimPreloadTable::
get_num_frames(int n) const {
nassertr(n >= 0 && n < (int)_anims.size(), 0);
consider_sort();
return _anims[n]._num_frames;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::consider_sort
// Access: Private
// Description: Ensures the table is kept in alphabetical order by
// basename.
////////////////////////////////////////////////////////////////////
INLINE void AnimPreloadTable::
consider_sort() const {
if (_needs_sort) {
((AnimPreloadTable *)this)->_anims.sort();
((AnimPreloadTable *)this)->_needs_sort = false;
}
}

View File

@ -0,0 +1,240 @@
// Filename: animPreloadTable.cxx
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 "animPreloadTable.h"
#include "indent.h"
#include "datagram.h"
#include "datagramIterator.h"
#include "bamReader.h"
#include "bamWriter.h"
TypeHandle AnimPreloadTable::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::make_cow_copy
// Access: Protected, Virtual
// Description: Required to implement CopyOnWriteObject.
////////////////////////////////////////////////////////////////////
PT(CopyOnWriteObject) AnimPreloadTable::
make_cow_copy() {
return new AnimPreloadTable(*this);
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
AnimPreloadTable::
AnimPreloadTable() {
_needs_sort = false;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::Destructor
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
AnimPreloadTable::
~AnimPreloadTable() {
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::get_num_anims
// Access: Published
// Description: Returns the number of animation records in the table.
////////////////////////////////////////////////////////////////////
int AnimPreloadTable::
get_num_anims() const {
return (int)_anims.size();
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::find_anim
// Access: Published
// Description: Returns the index number in the table of the
// animation record with the indicated name, or -1 if
// the name is not present. By convention, the basename
// is the filename of the egg or bam file, without the
// directory part and without the extension. That is,
// it is Filename::get_basename_wo_extension().
////////////////////////////////////////////////////////////////////
int AnimPreloadTable::
find_anim(const string &basename) const {
consider_sort();
AnimRecord record;
record._basename = basename;
Anims::const_iterator ai = _anims.find(record);
if (ai != _anims.end()) {
return int(ai - _anims.begin());
}
return -1;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::clear_anims
// Access: Published
// Description: Removes all animation records from the table.
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
clear_anims() {
_anims.clear();
_needs_sort = false;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::remove_anim
// Access: Published
// Description: Removes the nth animation records from the table.
// This renumbers indexes for following animations.
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
remove_anim(int n) {
nassertv(n >= 0 && n < (int)_anims.size());
_anims.erase(_anims.begin() + n);
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::add_anim
// Access: Published
// Description: Adds a new animation record to the table. If there
// is already a record of this name, no operation is
// performed (the original record is unchanged). See
// find_anim(). This will invalidate existing index
// numbers.
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
add_anim(const string &basename, float base_frame_rate, int num_frames) {
AnimRecord record;
record._basename = basename;
record._base_frame_rate = base_frame_rate;
record._num_frames = num_frames;
_anims.push_back(record);
_needs_sort = true;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::add_anims_from
// Access: Published
// Description: Copies the animation records from the other table
// into this one. If a given record name exists in both
// tables, the record in this one supercedes.
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
add_anims_from(const AnimPreloadTable *other) {
_anims.reserve(_anims.size() + other->_anims.size());
Anims::const_iterator ai;
for (ai = other->_anims.begin(); ai != other->_anims.end(); ++ai) {
_anims.push_back(*ai);
}
_needs_sort = true;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::output
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
output(ostream &out) const {
out << "AnimPreloadTable, " << _anims.size() << " animation records.";
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::write
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
write(ostream &out, int indent_level) const {
indent(out, indent_level)
<< "AnimPreloadTable, " << _anims.size() << " animation records:\n";
consider_sort();
Anims::const_iterator ai;
for (ai = _anims.begin(); ai != _anims.end(); ++ai) {
const AnimRecord &record = (*ai);
indent(out, indent_level + 2)
<< record._basename << ": " << record._num_frames << " frames at "
<< record._base_frame_rate << " fps\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::register_with_read_factory
// Access: Public, Static
// Description: Factory method to generate an AnimPreloadTable object
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
register_with_read_factory() {
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::write_datagram
// Access: Public
// Description: Function to write the important information in
// the particular object to a Datagram
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
write_datagram(BamWriter *manager, Datagram &dg) {
consider_sort();
dg.add_uint16(_anims.size());
Anims::const_iterator ai;
for (ai = _anims.begin(); ai != _anims.end(); ++ai) {
const AnimRecord &record = (*ai);
dg.add_string(record._basename);
dg.add_float32(record._base_frame_rate);
dg.add_int32(record._num_frames);
}
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::make_from_bam
// Access: Protected
// Description: Factory method to generate an AnimPreloadTable object
////////////////////////////////////////////////////////////////////
TypedWritable *AnimPreloadTable::
make_from_bam(const FactoryParams &params) {
AnimPreloadTable *me = new AnimPreloadTable;
DatagramIterator scan;
BamReader *manager;
parse_params(params, scan, manager);
me->fillin(scan, manager);
return me;
}
////////////////////////////////////////////////////////////////////
// Function: AnimPreloadTable::fillin
// Access: Protected
// Description: Function that reads out of the datagram (or asks
// manager to read) all of the data that is needed to
// re-create this object and stores it in the appropiate
// place
////////////////////////////////////////////////////////////////////
void AnimPreloadTable::
fillin(DatagramIterator &scan, BamReader *manager) {
int num_anims = scan.get_uint16();
_anims.reserve(num_anims);
for (int i = 0; i < num_anims; ++i) {
AnimRecord record;
record._basename = scan.get_string();
record._base_frame_rate = scan.get_float32();
record._num_frames = scan.get_int32();
_anims.push_back(record);
}
}

View File

@ -0,0 +1,117 @@
// Filename: animPreloadTable.h
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 ANIMPRELOADTABLE_H
#define ANIMPRELOADTABLE_H
#include "pandabase.h"
#include "typedWritableReferenceCount.h"
#include "ordered_vector.h"
#include "copyOnWriteObject.h"
class BamWriter;
class BamReader;
class Datagram;
class DatagramIterator;
class FactoryParams;
////////////////////////////////////////////////////////////////////
// Class : AnimPreloadTable
// Description : This table records data about a list of animations
// for a particular model, such as number of frames and
// frame rate. It's used for implementating
// asynchronous binding.
//
// This table is normally built by an offline tool, such
// as egg-optchar.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_CHAN AnimPreloadTable : public CopyOnWriteObject {
public:
class AnimRecord {
public:
INLINE AnimRecord();
INLINE bool operator < (const AnimRecord &other) const;
string _basename;
float _base_frame_rate;
int _num_frames;
};
protected:
virtual PT(CopyOnWriteObject) make_cow_copy();
PUBLISHED:
AnimPreloadTable();
virtual ~AnimPreloadTable();
int get_num_anims() const;
int find_anim(const string &basename) const;
INLINE string get_basename(int n) const;
INLINE float get_base_frame_rate(int n) const;
INLINE int get_num_frames(int n) const;
void clear_anims();
void remove_anim(int n);
void add_anim(const string &basename, float base_frame_rate, int num_frames);
void add_anims_from(const AnimPreloadTable *other);
virtual void output(ostream &out) const;
virtual void write(ostream &out, int indent_level) const;
private:
INLINE void consider_sort() const;
public:
static void register_with_read_factory();
virtual void write_datagram(BamWriter *manager, Datagram &dg);
static TypedWritable *make_from_bam(const FactoryParams &params);
protected:
void fillin(DatagramIterator &scan, BamReader *manager);
private:
typedef ov_set<AnimRecord> Anims;
Anims _anims;
bool _needs_sort;
public:
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
CopyOnWriteObject::init_type();
register_type(_type_handle, "AnimPreloadTable",
CopyOnWriteObject::get_class_type());
}
private:
static TypeHandle _type_handle;
};
inline ostream &operator << (ostream &out, const AnimPreloadTable &anim) {
anim.output(out);
return out;
}
#include "animPreloadTable.I"
#endif

View File

@ -0,0 +1,32 @@
// Filename: bindAnimRequest.I
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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: BindAnimRequest::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE BindAnimRequest::
BindAnimRequest(const Filename &filename, const LoaderOptions &options,
AnimControl *control, int hierarchy_match_flags,
const PartSubset &subset) :
ModelLoadRequest(filename, options),
_control(control),
_hierarchy_match_flags(hierarchy_match_flags),
_subset(subset)
{
}

View File

@ -0,0 +1,63 @@
// Filename: bindAnimRequest.cxx
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 "bindAnimRequest.h"
#include "animBundleNode.h"
#include "animControl.h"
#include "partBundle.h"
TypeHandle BindAnimRequest::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: BindAnimRequest::do_task
// Access: Protected, Virtual
// Description: Performs the task: that is, loads and binds the
// animation.
////////////////////////////////////////////////////////////////////
bool BindAnimRequest::
do_task() {
ModelLoadRequest::do_task();
PartBundle *part = _control->get_part();
if (_control->get_ref_count() == 1) {
// We're holding the only remaining reference to this AnimControl.
// Therefore, forget the bind attempt; no one cares anyway.
_control->fail_anim(part);
return false;
}
PT(PandaNode) model = get_model();
if (model == (PandaNode *)NULL) {
// Couldn't load the file.
_control->fail_anim(part);
return false;
}
_control->set_anim_model(model);
AnimBundle *anim = AnimBundleNode::find_anim_bundle(model);
if (anim == (AnimBundle *)NULL) {
// No anim bundle.
_control->fail_anim(part);
return false;
}
if (!part->do_bind_anim(_control, anim, _hierarchy_match_flags, _subset)) {
// Couldn't bind.
_control->fail_anim(part);
return false;
}
return false;
}

View File

@ -0,0 +1,70 @@
// Filename: bindAnimRequest.h
// Created by: drose (05Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 BINDANIMREQUEST
#define BINDANIMREQUEST
#include "pandabase.h"
#include "modelLoadRequest.h"
#include "partSubset.h"
class AnimControl;
////////////////////////////////////////////////////////////////////
// Class : BindAnimRequest
// Description : This class object manages an asynchronous
// load-and-bind animation request, as issued through
// PartBundle::load_bind_anim().
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA_PGRAPH BindAnimRequest : public ModelLoadRequest {
public:
ALLOC_DELETED_CHAIN(BindAnimRequest);
PUBLISHED:
INLINE BindAnimRequest(const Filename &filename,
const LoaderOptions &options,
AnimControl *control,
int hierarchy_match_flags,
const PartSubset &subset);
protected:
virtual bool do_task();
private:
PT(AnimControl) _control;
int _hierarchy_match_flags;
PartSubset _subset;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
ModelLoadRequest::init_type();
register_type(_type_handle, "BindAnimRequest",
ModelLoadRequest::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 "bindAnimRequest.I"
#endif

View File

@ -1,3 +1,5 @@
#include "animPreloadTable.cxx"
#include "bindAnimRequest.cxx"
#include "config_chan.cxx"
#include "movingPartBase.cxx"
#include "movingPartMatrix.cxx"

View File

@ -24,6 +24,8 @@
#include "animChannelScalarDynamic.h"
#include "animControl.h"
#include "animGroup.h"
#include "animPreloadTable.h"
#include "bindAnimRequest.h"
#include "movingPartBase.h"
#include "movingPartMatrix.h"
#include "movingPartScalar.h"
@ -86,6 +88,13 @@ PRC_DESC("Set this true to interpolate character animations between frames, "
"also be changed on a per-character basis with "
"PartBundle::set_frame_blend_flag()."));
ConfigVariableBool restore_initial_pose
("restore-initial-pose", true,
PRC_DESC("When this is true, stopping all animations on an Actor causes it "
"to return to its initial, unanimated pose. When false, it retains "
"whatever its last-computed pose was (which may or may not be "
"the unanimated pose)."));
ConfigureFn(config_chan) {
AnimBundle::init_type();
@ -98,6 +107,8 @@ ConfigureFn(config_chan) {
AnimChannelScalarDynamic::init_type();
AnimControl::init_type();
AnimGroup::init_type();
AnimPreloadTable::init_type();
BindAnimRequest::init_type();
MovingPartBase::init_type();
MovingPartMatrix::init_type();
MovingPartScalar::init_type();
@ -125,6 +136,7 @@ ConfigureFn(config_chan) {
AnimChannelMatrixDynamic::register_with_read_factory();
AnimChannelScalarTable::register_with_read_factory();
AnimChannelScalarDynamic::register_with_read_factory();
AnimPreloadTable::register_with_read_factory();
}

View File

@ -27,5 +27,6 @@ EXPCL_PANDA_CHAN extern ConfigVariableBool compress_channels;
EXPCL_PANDA_CHAN extern ConfigVariableInt compress_chan_quality;
EXPCL_PANDA_CHAN extern ConfigVariableBool read_compressed_channels;
EXPCL_PANDA_CHAN extern ConfigVariableBool interpolate_frames;
EXPCL_PANDA_CHAN extern ConfigVariableBool restore_initial_pose;
#endif

View File

@ -116,8 +116,7 @@ output_value(ostream &out) const {
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void MovingPart<SwitchType>::
write_datagram(BamWriter *manager, Datagram &me)
{
write_datagram(BamWriter *manager, Datagram &me) {
MovingPartBase::write_datagram(manager, me);
SwitchType::write_datagram(me, _value);
SwitchType::write_datagram(me, _initial_value);
@ -133,8 +132,7 @@ write_datagram(BamWriter *manager, Datagram &me)
////////////////////////////////////////////////////////////////////
template<class SwitchType>
void MovingPart<SwitchType>::
fillin(DatagramIterator& scan, BamReader* manager)
{
fillin(DatagramIterator &scan, BamReader *manager) {
MovingPartBase::fillin(scan, manager);
SwitchType::read_datagram(scan, _value);
SwitchType::read_datagram(scan, _initial_value);

View File

@ -143,9 +143,12 @@ do_update(PartBundle *root, const CycleData *root_cdata, PartGroup *parent,
!needs_update && bci != cdata->_blend.end();
++bci) {
AnimControl *control = (*bci).first;
AnimChannelBase *channel = NULL;
int channel_index = control->get_channel_index();
nassertr(channel_index >= 0 && channel_index < (int)_channels.size(), false);
AnimChannelBase *channel = _channels[channel_index];
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = _channels[channel_index];
}
if (channel != (AnimChannelBase*)NULL) {
needs_update = control->channel_has_changed(channel, cdata->_frame_blend_flag);
}

View File

@ -73,18 +73,24 @@ get_blend_value(const PartBundle *root) {
if (cdata->_blend.empty()) {
// No channel is bound; supply the default value.
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else if (cdata->_blend.size() == 1 && !cdata->_frame_blend_flag) {
// A single value, the normal case.
AnimControl *control = (*cdata->_blend.begin()).first;
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel == (ChannelType *)NULL) {
// Nothing is actually bound here.
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
channel->get_value(control->get_frame(), _value);
@ -131,7 +137,9 @@ get_blend_value(const PartBundle *root) {
}
if (net == 0.0f) {
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
_value /= net;
}
@ -157,9 +165,11 @@ get_blend_value(const PartBundle *root) {
float effect = (*cbi).second;
nassertv(effect != 0.0f);
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
ValueType v;
@ -195,7 +205,9 @@ get_blend_value(const PartBundle *root) {
}
if (net == 0.0f) {
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
_value /= net;
@ -226,9 +238,11 @@ get_blend_value(const PartBundle *root) {
float effect = (*cbi).second;
nassertv(effect != 0.0f);
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
LVecBase3f iscale, ihpr, ipos, ishear;
@ -270,7 +284,9 @@ get_blend_value(const PartBundle *root) {
}
if (net == 0.0f) {
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
scale /= net;
@ -299,9 +315,11 @@ get_blend_value(const PartBundle *root) {
float effect = (*cbi).second;
nassertv(effect != 0.0f);
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel != (ChannelType *)NULL) {
int frame = control->get_frame();
LVecBase3f iscale, ipos, ishear;
@ -345,7 +363,9 @@ get_blend_value(const PartBundle *root) {
}
if (net == 0.0f) {
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
scale /= net;

View File

@ -58,18 +58,24 @@ get_blend_value(const PartBundle *root) {
if (cdata->_blend.empty()) {
// No channel is bound; supply the default value.
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else if (cdata->_blend.size() == 1 && !cdata->_frame_blend_flag) {
// A single value, the normal case.
AnimControl *control = (*cdata->_blend.begin()).first;
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel == NULL) {
// Nothing is actually bound here.
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
channel->get_value(control->get_frame(), _value);
@ -86,9 +92,11 @@ get_blend_value(const PartBundle *root) {
float effect = (*cbi).second;
nassertv(effect != 0.0f);
ChannelType *channel = NULL;
int channel_index = control->get_channel_index();
nassertv(channel_index >= 0 && channel_index < (int)_channels.size());
ChannelType *channel = DCAST(ChannelType, _channels[channel_index]);
if (channel_index >= 0 && channel_index < (int)_channels.size()) {
channel = DCAST(ChannelType, _channels[channel_index]);
}
if (channel != NULL) {
ValueType v;
channel->get_value(control->get_frame(), v);
@ -109,7 +117,9 @@ get_blend_value(const PartBundle *root) {
}
if (net == 0.0f) {
_value = _initial_value;
if (restore_initial_pose) {
_value = _initial_value;
}
} else {
_value /= net;

View File

@ -13,6 +13,52 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: PartBundle::get_anim_preload
// Access: Published
// Description: Returns the AnimPreloadTable associated with
// the PartBundle. This table, if present, can be used
// for the benefit of load_bind_anim() to allow
// asynchronous binding.
////////////////////////////////////////////////////////////////////
INLINE CPT(AnimPreloadTable) PartBundle::
get_anim_preload() const {
return _anim_preload.get_read_pointer();
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::modify_anim_preload
// Access: Published
// Description: Returns a modifiable pointer to the AnimPreloadTable
// associated with the PartBundle, if any.
////////////////////////////////////////////////////////////////////
INLINE PT(AnimPreloadTable) PartBundle::
modify_anim_preload() {
return _anim_preload.get_write_pointer();
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_anim_preload
// Access: Published
// Description: Replaces the AnimPreloadTable associated with
// the PartBundle.
////////////////////////////////////////////////////////////////////
INLINE void PartBundle::
set_anim_preload(AnimPreloadTable *anim_preload) {
_anim_preload = anim_preload;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::clear_anim_preload
// Access: Published
// Description: Removes any AnimPreloadTable associated with
// the PartBundle.
////////////////////////////////////////////////////////////////////
INLINE void PartBundle::
clear_anim_preload() {
_anim_preload = NULL;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_blend_type
// Access: Published

View File

@ -15,7 +15,10 @@
#include "partBundle.h"
#include "animBundle.h"
#include "animBundleNode.h"
#include "animControl.h"
#include "loader.h"
#include "animPreloadTable.h"
#include "config_chan.h"
#include "bitArray.h"
#include "string_utils.h"
@ -25,6 +28,7 @@
#include "bamReader.h"
#include "bamWriter.h"
#include "configVariableEnum.h"
#include "loaderOptions.h"
#include <algorithm>
@ -49,6 +53,8 @@ PartBundle::
PartBundle(const PartBundle &copy) :
PartGroup(copy)
{
_anim_preload = copy._anim_preload;
CDWriter cdata(_cycler, true);
CDReader cdata_from(copy._cycler);
cdata->_blend_type = cdata_from->_blend_type;
@ -81,6 +87,30 @@ make_copy() const {
return new PartBundle(*this);
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::merge_anim_preloads
// Access: Published
// Description: Copies the contents of the other PartBundle's preload
// table into this one.
////////////////////////////////////////////////////////////////////
void PartBundle::
merge_anim_preloads(const PartBundle *other) {
if (other->_anim_preload == (AnimPreloadTable *)NULL ||
_anim_preload == other->_anim_preload) {
// No-op.
return;
}
if (_anim_preload == (AnimPreloadTable *)NULL) {
// Trivial case.
_anim_preload = other->_anim_preload;
return;
}
// Copy-on-write.
PT(AnimPreloadTable) anim_preload = _anim_preload.get_write_pointer();
anim_preload->add_anims_from(other->_anim_preload.get_read_pointer());
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::set_anim_blend_flag
@ -239,45 +269,95 @@ write(ostream &out, int indent_level) const {
PT(AnimControl) PartBundle::
bind_anim(AnimBundle *anim, int hierarchy_match_flags,
const PartSubset &subset) {
nassertr(Thread::get_current_pipeline_stage() == 0, NULL);
PT(AnimControl) control = new AnimControl(anim->get_name(), this, 1.0f, 0);
if (do_bind_anim(control, anim, hierarchy_match_flags, subset)) {
return control;
}
// Make sure this pointer doesn't destruct during the lifetime of this
// method.
PT(AnimBundle) ptanim = anim;
return NULL;
}
if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
// Make sure the root names match.
if (get_name() != ptanim->get_name()) {
if (chan_cat.is_error()) {
chan_cat.error()
<< "Root name of part (" << get_name()
<< ") does not match that of anim (" << ptanim->get_name()
<< ")\n";
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::load_bind_anim
// Access: Published
// Description: Binds an animation to the bundle. The animation is
// loaded from the disk via the indicated Loader object.
// In other respects, this behaves similarly to
// bind_anim(), with the addition of asynchronous
// support.
//
// If allow_aysnc is true, the load will be asynchronous
// if possible. This requires that the animation
// basename can be found in the PartBundle's preload
// table (see get_anim_preload()).
//
// In an asynchronous load, the animation file will be
// loaded and bound in a sub-thread. This means that
// the animation will not necessarily be available at
// the time this method returns. You may still use the
// returned AnimControl immediately, though, but no
// visible effect will occur until the animation
// eventually becomes available.
//
// You can test AnimControl::is_pending() to see if the
// animation has been loaded yet. You can also set an
// event to be triggered when the animation finishes
// loading with AnimControl::set_pending_done_event().
////////////////////////////////////////////////////////////////////
PT(AnimControl) PartBundle::
load_bind_anim(Loader *loader, const Filename &filename,
int hierarchy_match_flags, const PartSubset &subset,
bool allow_async) {
nassertr(loader != (Loader *)NULL, NULL);
LoaderOptions anim_options(LoaderOptions::LF_search |
LoaderOptions::LF_report_errors |
LoaderOptions::LF_convert_anim);
string basename = filename.get_basename_wo_extension();
int anim_index = -1;
CPT(AnimPreloadTable) anim_preload = _anim_preload.get_read_pointer();
if (anim_preload != (AnimPreloadTable *)NULL) {
anim_index = anim_preload->find_anim(basename);
}
if (anim_index < 0 || !allow_async) {
// The animation is not present in the table, or allow_async is
// false. Therefore, perform an ordinary synchronous
// load-and-bind.
PT(PandaNode) model = loader->load_sync(filename, anim_options);
if (model == (PandaNode *)NULL) {
// Couldn't load the file.
return NULL;
}
AnimBundle *anim = AnimBundleNode::find_anim_bundle(model);
if (anim == (AnimBundle *)NULL) {
// No anim bundle.
return NULL;
}
PT(AnimControl) control = bind_anim(anim, hierarchy_match_flags, subset);
if (control == (AnimControl *)NULL) {
// Couldn't bind.
return NULL;
}
control->set_anim_model(model);
return control;
}
if (!check_hierarchy(anim, NULL, hierarchy_match_flags)) {
return NULL;
}
// The animation is present in the table, so we can perform an
// asynchronous load-and-bind.
float frame_rate = anim_preload->get_base_frame_rate(anim_index);
int num_frames = anim_preload->get_num_frames(anim_index);
PT(AnimControl) control =
new AnimControl(basename, this, frame_rate, num_frames);
plist<int> holes;
int channel_index = 0;
pick_channel_index(holes, channel_index);
PT(BindAnimRequest) request =
new BindAnimRequest(filename, anim_options, control,
hierarchy_match_flags, subset);
loader->load_async(request);
if (!holes.empty()) {
channel_index = holes.front();
}
int joint_index = 0;
BitArray bound_joints;
if (subset.is_include_empty()) {
bound_joints = BitArray::all_on();
}
bind_hierarchy(ptanim, channel_index, joint_index,
subset.is_include_empty(), bound_joints, subset);
return new AnimControl(this, anim, channel_index, bound_joints);
return control;
}
////////////////////////////////////////////////////////////////////
@ -440,6 +520,59 @@ control_activated(AnimControl *control) {
}
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::do_bind_anim
// Access: Public
// Description: The internal implementation of bind_anim(), this
// receives a pointer to an uninitialized AnimControl
// and fills it in if the bind is successful. Returns
// true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool PartBundle::
do_bind_anim(AnimControl *control, AnimBundle *anim,
int hierarchy_match_flags, const PartSubset &subset) {
nassertr(Thread::get_current_pipeline_stage() == 0, false);
// Make sure this pointer doesn't destruct during the lifetime of this
// method.
PT(AnimBundle) ptanim = anim;
if ((hierarchy_match_flags & HMF_ok_wrong_root_name) == 0) {
// Make sure the root names match.
if (get_name() != ptanim->get_name()) {
if (chan_cat.is_error()) {
chan_cat.error()
<< "Root name of part (" << get_name()
<< ") does not match that of anim (" << ptanim->get_name()
<< ")\n";
}
return false;
}
}
if (!check_hierarchy(anim, NULL, hierarchy_match_flags)) {
return false;
}
plist<int> holes;
int channel_index = 0;
pick_channel_index(holes, channel_index);
if (!holes.empty()) {
channel_index = holes.front();
}
int joint_index = 0;
BitArray bound_joints;
if (subset.is_include_empty()) {
bound_joints = BitArray::all_on();
}
bind_hierarchy(ptanim, channel_index, joint_index,
subset.is_include_empty(), bound_joints, subset);
control->setup_anim(this, anim, channel_index, bound_joints);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::add_node
// Access: Protected, Virtual
@ -604,9 +737,26 @@ finalize(BamReader *) {
void PartBundle::
write_datagram(BamWriter *manager, Datagram &dg) {
PartGroup::write_datagram(manager, dg);
manager->write_pointer(dg, _anim_preload.get_read_pointer());
manager->write_cdata(dg, _cycler);
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::complete_pointers
// Access: Public
// Description: Takes in a vector of pointers to TypedWritable
// objects that correspond to all the requests for
// pointers that this object made to BamReader.
////////////////////////////////////////////////////////////////////
int PartBundle::
complete_pointers(TypedWritable **p_list, BamReader *manager) {
int pi = PartGroup::complete_pointers(p_list, manager);
_anim_preload = DCAST(AnimPreloadTable, p_list[pi++]);
return pi;
}
////////////////////////////////////////////////////////////////////
// Function: PartBundle::make_from_bam
// Access: Protected
@ -634,7 +784,9 @@ make_from_bam(const FactoryParams &params) {
void PartBundle::
fillin(DatagramIterator &scan, BamReader *manager) {
PartGroup::fillin(scan, manager);
if (manager->get_file_minor_ver() >= 16) {
manager->read_pointer(scan); // _anim_preload
}
if (manager->get_file_minor_ver() >= 10) {
manager->read_cdata(scan, _cycler);
}

View File

@ -20,6 +20,7 @@
#include "partGroup.h"
#include "animControl.h"
#include "partSubset.h"
#include "animPreloadTable.h"
#include "pointerTo.h"
#include "thread.h"
#include "cycleData.h"
@ -30,11 +31,14 @@
#include "pvector.h"
#include "transformState.h"
#include "weakPointerTo.h"
#include "copyOnWritePointer.h"
class Loader;
class AnimBundle;
class PartBundleNode;
class PartBundleNode;
class TransformState;
class AnimPreloadTable;
////////////////////////////////////////////////////////////////////
// Class : PartBundle
@ -58,6 +62,11 @@ public:
virtual PartGroup *make_copy() const;
PUBLISHED:
INLINE CPT(AnimPreloadTable) get_anim_preload() const;
INLINE PT(AnimPreloadTable) modify_anim_preload();
INLINE void set_anim_preload(AnimPreloadTable *table);
INLINE void clear_anim_preload();
void merge_anim_preloads(const PartBundle *other);
// This is the parameter to set_blend_type() and specifies the kind
// of blending operation to be performed when multiple controls are
@ -119,6 +128,11 @@ PUBLISHED:
PT(AnimControl) bind_anim(AnimBundle *anim,
int hierarchy_match_flags = 0,
const PartSubset &subset = PartSubset());
PT(AnimControl) load_bind_anim(Loader *loader,
const Filename &filename,
int hierarchy_match_flags,
const PartSubset &subset,
bool allow_async);
bool freeze_joint(const string &joint_name, const TransformState *transform);
bool control_joint(const string &joint_name, PandaNode *node);
@ -133,6 +147,9 @@ public:
// bunch of friends.
virtual void control_activated(AnimControl *control);
bool do_bind_anim(AnimControl *control, AnimBundle *anim,
int hierarchy_match_flags, const PartSubset &subset);
protected:
virtual void add_node(PartBundleNode *node);
virtual void remove_node(PartBundleNode *node);
@ -145,6 +162,8 @@ private:
void recompute_net_blend(CData *cdata);
void clear_and_stop_intersecting(AnimControl *control, CData *cdata);
COWPT(AnimPreloadTable) _anim_preload;
typedef pvector<PartBundleNode *> Nodes;
Nodes _nodes;
@ -183,6 +202,8 @@ public:
static void register_with_read_factory();
virtual void finalize(BamReader *manager);
virtual void write_datagram(BamWriter *manager, Datagram &dg);
virtual int complete_pointers(TypedWritable **p_list,
BamReader *manager);
protected:
static TypedWritable *make_from_bam(const FactoryParams &params);

View File

@ -253,6 +253,7 @@ sort_descendants() {
bool PartGroup::
check_hierarchy(const AnimGroup *anim, const PartGroup *,
int hierarchy_match_flags) const {
Thread::consider_yield();
if (anim->get_value_type() != get_value_type()) {
if (chan_cat.is_error()) {
chan_cat.error()
@ -507,6 +508,7 @@ void PartGroup::
bind_hierarchy(AnimGroup *anim, int channel_index, int &joint_index,
bool is_included, BitArray &bound_joints,
const PartSubset &subset) {
Thread::consider_yield();
if (subset.matches_include(get_name())) {
is_included = true;
} else if (subset.matches_exclude(get_name())) {

View File

@ -281,7 +281,11 @@ merge_bundles(PartBundle *old_bundle, PartBundle *new_bundle) {
void Character::
merge_bundles(PartBundleHandle *old_bundle_handle,
PartBundleHandle *new_bundle_handle) {
update_bundle(old_bundle_handle, new_bundle_handle->get_bundle());
PartBundle *old_bundle = old_bundle_handle->get_bundle();
PartBundle *new_bundle = new_bundle_handle->get_bundle();
new_bundle->merge_anim_preloads(old_bundle);
update_bundle(old_bundle_handle, new_bundle);
}
////////////////////////////////////////////////////////////////////

View File

@ -12,7 +12,9 @@
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
#define SOURCES \
config_egg.h eggAnimData.I eggAnimData.h eggAttributes.I \
config_egg.h eggAnimData.I eggAnimData.h \
eggAnimPreload.I eggAnimPreload.h \
eggAttributes.I \
eggAttributes.h eggBin.h eggBinMaker.h eggComment.I \
eggComment.h \
eggCompositePrimitive.I eggCompositePrimitive.h \
@ -54,7 +56,9 @@
vector_PT_EggTexture.h pt_EggVertex.h vector_PT_EggVertex.h
#define INCLUDED_SOURCES \
config_egg.cxx eggAnimData.cxx eggAttributes.cxx eggBin.cxx \
config_egg.cxx eggAnimData.cxx \
eggAnimPreload.cxx \
eggAttributes.cxx eggBin.cxx \
eggBinMaker.cxx eggComment.cxx \
eggCompositePrimitive.cxx \
eggCoordinateSystem.cxx \
@ -85,6 +89,7 @@
#define INSTALL_HEADERS \
eggAnimData.I eggAnimData.h \
eggAnimPreload.I eggAnimPreload.h \
eggAttributes.I eggAttributes.h eggBin.h eggBinMaker.h eggComment.I \
eggComment.h \
eggCompositePrimitive.I eggCompositePrimitive.h \

View File

@ -15,6 +15,7 @@
#include "config_egg.h"
#include "eggRenderMode.h"
#include "eggAnimData.h"
#include "eggAnimPreload.h"
#include "eggAttributes.h"
#include "eggBin.h"
#include "eggBinMaker.h"
@ -166,6 +167,7 @@ init_libegg() {
EggRenderMode::init_type();
EggAnimData::init_type();
EggAnimPreload::init_type();
EggAttributes::init_type();
EggBin::init_type();
EggBinMaker::init_type();

View File

@ -0,0 +1,145 @@
// Filename: eggAnimPreload.I
// Created by: drose (06Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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: EggAnimPreload::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggAnimPreload::
EggAnimPreload(const string &name) : EggNode(name) {
_has_fps = false;
_has_num_frames = false;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::Copy constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggAnimPreload::
EggAnimPreload(const EggAnimPreload &copy) :
EggNode(copy),
_fps(copy._fps),
_has_fps(copy._has_fps),
_num_frames(copy._num_frames),
_has_num_frames(copy._has_num_frames)
{
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::Copy assignment operator
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE EggAnimPreload &EggAnimPreload::
operator = (const EggAnimPreload &copy) {
EggNode::operator = (copy);
_fps = copy._fps;
_has_fps = copy._has_fps;
_num_frames = copy._num_frames;
_has_num_frames = copy._has_num_frames;
return *this;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::set_fps
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggAnimPreload::
set_fps(double fps) {
_fps = fps;
_has_fps = true;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::clear_fps
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggAnimPreload::
clear_fps() {
_has_fps = false;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::has_fps
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool EggAnimPreload::
has_fps() const {
return _has_fps;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::get_fps
// Access: Public
// Description: This is only valid if has_fps() returns true.
////////////////////////////////////////////////////////////////////
INLINE double EggAnimPreload::
get_fps() const {
nassertr(has_fps(), 0.0);
return _fps;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::set_num_frames
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggAnimPreload::
set_num_frames(int num_frames) {
_num_frames = num_frames;
_has_num_frames = true;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::clear_num_frames
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE void EggAnimPreload::
clear_num_frames() {
_has_num_frames = false;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::has_num_frames
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE bool EggAnimPreload::
has_num_frames() const {
return _has_num_frames;
}
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::get_num_frames
// Access: Public
// Description: This is only valid if has_num_frames() returns true.
////////////////////////////////////////////////////////////////////
INLINE int EggAnimPreload::
get_num_frames() const {
nassertr(has_num_frames(), 0);
return _num_frames;
}

View File

@ -0,0 +1,45 @@
// Filename: eggAnimPreload.cxx
// Created by: drose (06Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 "eggAnimPreload.h"
#include "string_utils.h"
#include "indent.h"
TypeHandle EggAnimPreload::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: EggAnimPreload::write
// Access: Public, Virtual
// Description: Writes the table and all of its children to the
// indicated output stream in Egg format.
////////////////////////////////////////////////////////////////////
void EggAnimPreload::
write(ostream &out, int indent_level) const {
test_under_integrity();
write_header(out, indent_level, "<AnimPreload>");
if (has_fps()) {
indent(out, indent_level + 2)
<< "<Scalar> fps { " << get_fps() << " }\n";
}
if (has_num_frames()) {
indent(out, indent_level + 2)
<< "<Scalar> frames { " << get_num_frames() << " }\n";
}
indent(out, indent_level) << "}\n";
}

View File

@ -0,0 +1,71 @@
// Filename: eggAnimPreload.h
// Created by: drose (06Aug08)
//
////////////////////////////////////////////////////////////////////
//
// 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 EGGANIMPRELOAD_H
#define EGGANIMPRELOAD_H
#include "pandabase.h"
#include "eggNode.h"
////////////////////////////////////////////////////////////////////
// Class : EggAnimPreload
// Description : This corresponds to an <AnimPreload> entry.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEGG EggAnimPreload : public EggNode {
PUBLISHED:
INLINE EggAnimPreload(const string &name = "");
INLINE EggAnimPreload(const EggAnimPreload &copy);
INLINE EggAnimPreload &operator = (const EggAnimPreload &copy);
INLINE void set_fps(double fps);
INLINE void clear_fps();
INLINE bool has_fps() const;
INLINE double get_fps() const;
INLINE void set_num_frames(int num_frames);
INLINE void clear_num_frames();
INLINE bool has_num_frames() const;
INLINE int get_num_frames() const;
virtual void write(ostream &out, int indent_level) const;
private:
double _fps;
bool _has_fps;
int _num_frames;
bool _has_num_frames;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
EggNode::init_type();
register_type(_type_handle, "EggAnimPreload",
EggNode::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 "eggAnimPreload.I"
#endif

View File

@ -1,5 +1,6 @@
#include "config_egg.cxx"
#include "eggAnimData.cxx"
#include "eggAnimPreload.cxx"
#include "eggAttributes.cxx"
#include "eggBin.cxx"
#include "eggBinMaker.cxx"

File diff suppressed because it is too large Load Diff

View File

@ -339,6 +339,10 @@ NUMERIC ([+-]?(([0-9]+[.]?)|([0-9]*[.][0-9]+))([eE][+-]?[0-9]+)?)
"<ANIMPRELOAD>" {
accept();
return ANIMPRELOAD;
}
"<BEZIERCURVE>" {
accept();
return BEZIERCURVE;

File diff suppressed because it is too large Load Diff

View File

@ -1,233 +1,92 @@
/* A Bison parser, made by GNU Bison 2.3. */
#define EGG_NUMBER 257
#define EGG_ULONG 258
#define EGG_STRING 259
#define ANIMPRELOAD 260
#define BEZIERCURVE 261
#define BFACE 262
#define BILLBOARD 263
#define BILLBOARDCENTER 264
#define BINORMAL 265
#define BUNDLE 266
#define CLOSED 267
#define COLLIDE 268
#define COMMENT 269
#define COMPONENT 270
#define COORDSYSTEM 271
#define CV 272
#define DART 273
#define DNORMAL 274
#define DRGBA 275
#define DUV 276
#define DXYZ 277
#define DCS 278
#define DISTANCE 279
#define DTREF 280
#define DYNAMICVERTEXPOOL 281
#define EXTERNAL_FILE 282
#define FLIGHT 283
#define GROUP 284
#define HIP 285
#define INTANGENT 286
#define JOINT 287
#define KNOTS 288
#define INCLUDE 289
#define INSTANCE 290
#define LINE 291
#define LOOP 292
#define MATERIAL 293
#define MATRIX3 294
#define MATRIX4 295
#define MODEL 296
#define MREF 297
#define NORMAL 298
#define NURBSCURVE 299
#define NURBSSURFACE 300
#define OBJECTTYPE 301
#define ORDER 302
#define OUTTANGENT 303
#define POINTLIGHT 304
#define POLYGON 305
#define REF 306
#define RGBA 307
#define ROTATE 308
#define ROTX 309
#define ROTY 310
#define ROTZ 311
#define SANIM 312
#define SCALAR 313
#define SCALE 314
#define SEQUENCE 315
#define SHADING 316
#define SWITCH 317
#define SWITCHCONDITION 318
#define TABLE 319
#define TABLE_V 320
#define TAG 321
#define TANGENT 322
#define TEXLIST 323
#define TEXTURE 324
#define TLENGTHS 325
#define TRANSFORM 326
#define TRANSLATE 327
#define TREF 328
#define TRIANGLEFAN 329
#define TRIANGLESTRIP 330
#define TRIM 331
#define TXT 332
#define UKNOTS 333
#define UV 334
#define VKNOTS 335
#define VERTEX 336
#define VERTEXANIM 337
#define VERTEXPOOL 338
#define VERTEXREF 339
#define XFMANIM 340
#define XFMSANIM 341
#define START_EGG 342
#define START_GROUP_BODY 343
#define START_TEXTURE_BODY 344
#define START_PRIMITIVE_BODY 345
/* Skeleton interface for Bison's Yacc-like parsers in C
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
Free Software Foundation, Inc.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA. */
/* As a special exception, you may create a larger work that contains
part or all of the Bison parser skeleton and distribute that work
under terms of your choice, so long as that work isn't itself a
parser generator using the skeleton or a modified version thereof
as a parser skeleton. Alternatively, if you modify or redistribute
the parser skeleton itself, you may (at your option) remove this
special exception, which will cause the skeleton and the resulting
Bison output files to be licensed under the GNU General Public
License without this special exception.
This special exception was added by the Free Software Foundation in
version 2.2 of Bison. */
/* Tokens. */
#ifndef YYTOKENTYPE
# define YYTOKENTYPE
/* Put the tokens into the symbol table, so that GDB and other debuggers
know about them. */
enum yytokentype {
EGG_NUMBER = 258,
EGG_ULONG = 259,
EGG_STRING = 260,
BEZIERCURVE = 261,
BFACE = 262,
BILLBOARD = 263,
BILLBOARDCENTER = 264,
BINORMAL = 265,
BUNDLE = 266,
CLOSED = 267,
COLLIDE = 268,
COMMENT = 269,
COMPONENT = 270,
COORDSYSTEM = 271,
CV = 272,
DART = 273,
DNORMAL = 274,
DRGBA = 275,
DUV = 276,
DXYZ = 277,
DCS = 278,
DISTANCE = 279,
DTREF = 280,
DYNAMICVERTEXPOOL = 281,
EXTERNAL_FILE = 282,
FLIGHT = 283,
GROUP = 284,
HIP = 285,
INTANGENT = 286,
JOINT = 287,
KNOTS = 288,
INCLUDE = 289,
INSTANCE = 290,
LINE = 291,
LOOP = 292,
MATERIAL = 293,
MATRIX3 = 294,
MATRIX4 = 295,
MODEL = 296,
MREF = 297,
NORMAL = 298,
NURBSCURVE = 299,
NURBSSURFACE = 300,
OBJECTTYPE = 301,
ORDER = 302,
OUTTANGENT = 303,
POINTLIGHT = 304,
POLYGON = 305,
REF = 306,
RGBA = 307,
ROTATE = 308,
ROTX = 309,
ROTY = 310,
ROTZ = 311,
SANIM = 312,
SCALAR = 313,
SCALE = 314,
SEQUENCE = 315,
SHADING = 316,
SWITCH = 317,
SWITCHCONDITION = 318,
TABLE = 319,
TABLE_V = 320,
TAG = 321,
TANGENT = 322,
TEXLIST = 323,
TEXTURE = 324,
TLENGTHS = 325,
TRANSFORM = 326,
TRANSLATE = 327,
TREF = 328,
TRIANGLEFAN = 329,
TRIANGLESTRIP = 330,
TRIM = 331,
TXT = 332,
UKNOTS = 333,
UV = 334,
VKNOTS = 335,
VERTEX = 336,
VERTEXANIM = 337,
VERTEXPOOL = 338,
VERTEXREF = 339,
XFMANIM = 340,
XFMSANIM = 341,
START_EGG = 342,
START_GROUP_BODY = 343,
START_TEXTURE_BODY = 344,
START_PRIMITIVE_BODY = 345
};
#endif
/* Tokens. */
#define EGG_NUMBER 258
#define EGG_ULONG 259
#define EGG_STRING 260
#define BEZIERCURVE 261
#define BFACE 262
#define BILLBOARD 263
#define BILLBOARDCENTER 264
#define BINORMAL 265
#define BUNDLE 266
#define CLOSED 267
#define COLLIDE 268
#define COMMENT 269
#define COMPONENT 270
#define COORDSYSTEM 271
#define CV 272
#define DART 273
#define DNORMAL 274
#define DRGBA 275
#define DUV 276
#define DXYZ 277
#define DCS 278
#define DISTANCE 279
#define DTREF 280
#define DYNAMICVERTEXPOOL 281
#define EXTERNAL_FILE 282
#define FLIGHT 283
#define GROUP 284
#define HIP 285
#define INTANGENT 286
#define JOINT 287
#define KNOTS 288
#define INCLUDE 289
#define INSTANCE 290
#define LINE 291
#define LOOP 292
#define MATERIAL 293
#define MATRIX3 294
#define MATRIX4 295
#define MODEL 296
#define MREF 297
#define NORMAL 298
#define NURBSCURVE 299
#define NURBSSURFACE 300
#define OBJECTTYPE 301
#define ORDER 302
#define OUTTANGENT 303
#define POINTLIGHT 304
#define POLYGON 305
#define REF 306
#define RGBA 307
#define ROTATE 308
#define ROTX 309
#define ROTY 310
#define ROTZ 311
#define SANIM 312
#define SCALAR 313
#define SCALE 314
#define SEQUENCE 315
#define SHADING 316
#define SWITCH 317
#define SWITCHCONDITION 318
#define TABLE 319
#define TABLE_V 320
#define TAG 321
#define TANGENT 322
#define TEXLIST 323
#define TEXTURE 324
#define TLENGTHS 325
#define TRANSFORM 326
#define TRANSLATE 327
#define TREF 328
#define TRIANGLEFAN 329
#define TRIANGLESTRIP 330
#define TRIM 331
#define TXT 332
#define UKNOTS 333
#define UV 334
#define VKNOTS 335
#define VERTEX 336
#define VERTEXANIM 337
#define VERTEXPOOL 338
#define VERTEXREF 339
#define XFMANIM 340
#define XFMSANIM 341
#define START_EGG 342
#define START_GROUP_BODY 343
#define START_TEXTURE_BODY 344
#define START_PRIMITIVE_BODY 345
#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
typedef int YYSTYPE;
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
# define YYSTYPE_IS_DECLARED 1
# define YYSTYPE_IS_TRIVIAL 1
#endif
extern YYSTYPE eggyylval;

View File

@ -32,6 +32,7 @@
#include "eggCoordinateSystem.h"
#include "eggExternalReference.h"
#include "eggData.h"
#include "eggAnimPreload.h"
#include "pt_EggTexture.h"
#include "pt_EggMaterial.h"
@ -146,6 +147,7 @@ egg_cleanup_parser() {
%token <_ulong> EGG_ULONG
%token <_string> EGG_STRING
%token ANIMPRELOAD
%token BEZIERCURVE BFACE BILLBOARD BILLBOARDCENTER BINORMAL BUNDLE CLOSED
%token COLLIDE COMMENT COMPONENT
%token COORDSYSTEM CV DART
@ -190,6 +192,7 @@ egg_cleanup_parser() {
%type <_egg> nurbs_curve
%type <_egg> table
%type <_egg> bundle
%type <_egg> anim_preload
%type <_egg> sanim
%type <_egg> xfmanim
%type <_egg> xfm_s_anim
@ -261,6 +264,7 @@ node:
| nurbs_surface
| nurbs_curve
| table
| anim_preload
;
/*
@ -2484,7 +2488,6 @@ bundle:
}
;
/*
* table_body
*
@ -2670,6 +2673,52 @@ xfm_s_anim_body:
;
/*
* anim_preload
*
* enter:
* exit: returns a new EggAnimPreload object.
*
*/
anim_preload:
ANIMPRELOAD optional_name
{
EggAnimPreload *anim_preload = new EggAnimPreload($2);
egg_stack.push_back(anim_preload);
}
'{' anim_preload_body '}'
{
$$ = egg_stack.back();
egg_stack.pop_back();
}
;
/*
* anim_preload_body
*
* enter: TOS is EggAnimPreload.
* exit: anim_preload contents have been filled.
*
*/
anim_preload_body:
empty
| anim_preload_body SCALAR required_name '{' real_or_string '}'
{
EggAnimPreload *anim_preload = DCAST(EggAnimPreload, egg_stack.back());
string name = $3;
double value = $<_number>5;
if (cmp_nocase_uh(name, "fps") == 0) {
anim_preload->set_fps(value);
} else if (cmp_nocase_uh(name, "frames") == 0) {
anim_preload->set_num_frames((int)value);
} else {
eggyywarning("Unsupported AnimPreload scalar: " + name);
}
}
;
/*
* integer_list
*

View File

@ -32,6 +32,8 @@
#include "characterVertexSlider.h"
#include "jointVertexTransform.h"
#include "userVertexTransform.h"
#include "eggAnimPreload.h"
#include "animPreloadTable.h"
////////////////////////////////////////////////////////////////////
// Function: CharacterMaker::Construtor
@ -238,6 +240,28 @@ make_bundle() {
////////////////////////////////////////////////////////////////////
void CharacterMaker::
build_joint_hierarchy(EggNode *egg_node, PartGroup *part, int index) {
if (egg_node->is_of_type(EggAnimPreload::get_class_type())) {
EggAnimPreload *egg_anim_preload = DCAST(EggAnimPreload, egg_node);
double fps = 24.0;
if (egg_anim_preload->has_fps()) {
fps = egg_anim_preload->get_fps();
}
int num_frames = 1;
if (egg_anim_preload->has_num_frames()) {
num_frames = egg_anim_preload->get_num_frames();
}
PT(AnimPreloadTable) anim_preload = _bundle->modify_anim_preload();
if (anim_preload == (AnimPreloadTable *)NULL) {
anim_preload = new AnimPreloadTable;
_bundle->set_anim_preload(anim_preload);
}
anim_preload->add_anim(egg_node->get_name(), fps, num_frames);
return;
}
if (egg_node->is_of_type(EggGroup::get_class_type())) {
EggGroup *egg_group = DCAST(EggGroup, egg_node);

View File

@ -45,6 +45,11 @@ EventQueue::
void EventQueue::
queue_event(CPT_Event event) {
nassertv(!event.is_null());
if (event->get_name().empty()) {
// Never mind.
return;
}
MutexHolder holder(_lock);
_queue.push_back(event);

View File

@ -53,6 +53,20 @@ throw_event(const string &event_name,
EventQueue::get_global_event_queue()->queue_event(event);
}
INLINE void
throw_event(const string &event_name,
const EventParameter &p1,
const EventParameter &p2,
const EventParameter &p3,
const EventParameter &p4) {
Event *event = new Event(event_name);
event->add_parameter(p1);
event->add_parameter(p2);
event->add_parameter(p3);
event->add_parameter(p4);
EventQueue::get_global_event_queue()->queue_event(event);
}
////////////////////////////////////////////////////////////////////////////
INLINE void

View File

@ -33,6 +33,11 @@ INLINE void throw_event(const string &event_name,
const EventParameter &p1,
const EventParameter &p2,
const EventParameter &p3);
INLINE void throw_event(const string &event_name,
const EventParameter &p1,
const EventParameter &p2,
const EventParameter &p3,
const EventParameter &p4);
#include "eventHandler.h"

View File

@ -278,6 +278,11 @@ compute_billboard(CPT(TransformState) &node_transform,
CPT(TransformState) rel_transform =
net_transform->compose(translate)->invert_compose(camera_transform);
if (!rel_transform->has_mat()) {
// Never mind.
return;
}
const LMatrix4f &rel_mat = rel_transform->get_mat();
// Determine the look_at point in the camera space.

View File

@ -49,6 +49,7 @@ static const unsigned short _bam_minor_ver = 16;
// Bumped to minor version 14 on 12/19/07 to change default ColorAttrib.
// Bumped to minor version 15 on 4/9/08 to add TextureAttrib::_implicit_sort.
// Bumped to minor version 16 on 5/13/08 to add Texture::_quality_level.
// Bumped to minor version 17 on 8/6/08 to add PartBundle::_anim_preload.
#endif

View File

@ -540,6 +540,8 @@ read_handle(DatagramIterator &scan) {
////////////////////////////////////////////////////////////////////
void BamReader::
read_pointer(DatagramIterator &scan) {
Thread::consider_yield();
nassertv(_now_creating != _created_objs.end());
int requestor_id = (*_now_creating).first;