diff --git a/panda/src/chan/animBundleNode.cxx b/panda/src/chan/animBundleNode.cxx index 706bd5b3b4..302f3e8a0f 100644 --- a/panda/src/chan/animBundleNode.cxx +++ b/panda/src/chan/animBundleNode.cxx @@ -75,7 +75,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int AnimBundleNode:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) +complete_pointers(TypedWritable **p_list, BamReader* manager) { int start = NamedNode::complete_pointers(p_list, manager); _bundle = DCAST(AnimBundle, p_list[start]); diff --git a/panda/src/chan/animBundleNode.h b/panda/src/chan/animBundleNode.h index 736ae72c0d..a816244ecc 100644 --- a/panda/src/chan/animBundleNode.h +++ b/panda/src/chan/animBundleNode.h @@ -48,7 +48,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); static TypedWritable *make_AnimBundleNode(const FactoryParams ¶ms); diff --git a/panda/src/chan/animGroup.cxx b/panda/src/chan/animGroup.cxx index a21a729e47..8558e81a64 100644 --- a/panda/src/chan/animGroup.cxx +++ b/panda/src/chan/animGroup.cxx @@ -221,7 +221,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int AnimGroup:: -complete_pointers(vector_typedWritable &p_list, BamReader*) +complete_pointers(TypedWritable **p_list, BamReader*) { nassertr(p_list[0] != TypedWritable::Null, 0); _root = DCAST(AnimBundle, p_list[0]); diff --git a/panda/src/chan/animGroup.h b/panda/src/chan/animGroup.h index 14b21d2b05..3bdc786f7f 100644 --- a/panda/src/chan/animGroup.h +++ b/panda/src/chan/animGroup.h @@ -72,7 +72,7 @@ protected: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); static TypedWritable *make_AnimGroup(const FactoryParams ¶ms); diff --git a/panda/src/chan/partBundleNode.cxx b/panda/src/chan/partBundleNode.cxx index 74c20ba94d..86401c5cb5 100644 --- a/panda/src/chan/partBundleNode.cxx +++ b/panda/src/chan/partBundleNode.cxx @@ -76,7 +76,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int PartBundleNode:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) +complete_pointers(TypedWritable **p_list, BamReader* manager) { int start = NamedNode::complete_pointers(p_list, manager); _bundle = DCAST(PartBundle, p_list[start]); diff --git a/panda/src/chan/partBundleNode.h b/panda/src/chan/partBundleNode.h index f8277cd36e..0d274b8b30 100644 --- a/panda/src/chan/partBundleNode.h +++ b/panda/src/chan/partBundleNode.h @@ -50,7 +50,7 @@ private: public: virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); protected: diff --git a/panda/src/chan/partGroup.cxx b/panda/src/chan/partGroup.cxx index dde6f335a4..74679504de 100644 --- a/panda/src/chan/partGroup.cxx +++ b/panda/src/chan/partGroup.cxx @@ -509,7 +509,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int PartGroup:: -complete_pointers(vector_typedWritable &p_list, BamReader*) +complete_pointers(TypedWritable **p_list, BamReader*) { int i; for(i = 0; i < _num_children; i++) diff --git a/panda/src/chan/partGroup.h b/panda/src/chan/partGroup.h index 0dd40b49dc..a4a24a6cac 100644 --- a/panda/src/chan/partGroup.h +++ b/panda/src/chan/partGroup.h @@ -98,7 +98,7 @@ protected: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); static TypedWritable *make_PartGroup(const FactoryParams ¶ms); diff --git a/panda/src/char/character.cxx b/panda/src/char/character.cxx index 387436ac61..37b1aaad79 100644 --- a/panda/src/char/character.cxx +++ b/panda/src/char/character.cxx @@ -456,7 +456,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int Character:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) +complete_pointers(TypedWritable **p_list, BamReader* manager) { int start = PartBundleNode::complete_pointers(p_list, manager); _computed_vertices = DCAST(ComputedVertices, p_list[start]); diff --git a/panda/src/char/character.h b/panda/src/char/character.h index 373e470096..bbc1e86c1c 100644 --- a/panda/src/char/character.h +++ b/panda/src/char/character.h @@ -99,7 +99,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); static TypedWritable *make_Character(const FactoryParams ¶ms); diff --git a/panda/src/char/characterJoint.cxx b/panda/src/char/characterJoint.cxx index fbe246c003..d85ea8c026 100644 --- a/panda/src/char/characterJoint.cxx +++ b/panda/src/char/characterJoint.cxx @@ -359,7 +359,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int CharacterJoint:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) +complete_pointers(TypedWritable **p_list, BamReader* manager) { int i; int start = MovingPartMatrix::complete_pointers(p_list, manager); diff --git a/panda/src/char/characterJoint.h b/panda/src/char/characterJoint.h index c4d9cf3e9d..1925f4ae73 100644 --- a/panda/src/char/characterJoint.h +++ b/panda/src/char/characterJoint.h @@ -65,7 +65,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); static TypedWritable *make_CharacterJoint(const FactoryParams ¶ms); diff --git a/panda/src/collide/collisionNode.cxx b/panda/src/collide/collisionNode.cxx index 7ee30e02ac..847351df32 100644 --- a/panda/src/collide/collisionNode.cxx +++ b/panda/src/collide/collisionNode.cxx @@ -303,7 +303,7 @@ fillin(DatagramIterator& scan, BamReader* manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int CollisionNode:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) { +complete_pointers(TypedWritable **p_list, BamReader* manager) { int num_solids = _solids.size(); int start = NamedNode::complete_pointers(p_list, manager); diff --git a/panda/src/collide/collisionNode.h b/panda/src/collide/collisionNode.h index 09c38411a9..9b58033faf 100644 --- a/panda/src/collide/collisionNode.h +++ b/panda/src/collide/collisionNode.h @@ -80,7 +80,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_CollisionNode(const FactoryParams ¶ms); diff --git a/panda/src/display/graphicsStateGuardian.h b/panda/src/display/graphicsStateGuardian.h index f9811b5c29..117c631d4f 100644 --- a/panda/src/display/graphicsStateGuardian.h +++ b/panda/src/display/graphicsStateGuardian.h @@ -170,13 +170,6 @@ public: INLINE CoordinateSystem get_coordinate_system() const; virtual CoordinateSystem get_internal_coordinate_system() const; - // This function may only be called during a render traversal; it - // will compute the distance to the indicated point, assumed to be - // in modelview coordinates, from the camera plane. This is a - // virtual function because different GSG's may define the modelview - // coordinate space differently. - virtual float compute_distance_to(const LPoint3f &point) const=0; - INLINE void clear_cached_state(void) { _state.clear(); }; virtual void issue_transform(const TransformState *transform); diff --git a/panda/src/effects/lensFlareNode.cxx b/panda/src/effects/lensFlareNode.cxx index 6a00bb95f7..87d5d07207 100644 --- a/panda/src/effects/lensFlareNode.cxx +++ b/panda/src/effects/lensFlareNode.cxx @@ -507,7 +507,7 @@ fillin(DatagramIterator &scan, BamReader *manager) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int LensFlareNode:: -complete_pointers(vector_typedWritable &p_list, BamReader *manager) +complete_pointers(TypedWritable **p_list, BamReader *manager) { int i; int start = Node::complete_pointers(p_list, manager); diff --git a/panda/src/effects/lensFlareNode.h b/panda/src/effects/lensFlareNode.h index ae566e186f..a17f2da8cf 100644 --- a/panda/src/effects/lensFlareNode.h +++ b/panda/src/effects/lensFlareNode.h @@ -106,7 +106,7 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_LensFlareNode(const FactoryParams ¶ms); diff --git a/panda/src/egg2sg/loaderFileTypeEgg.cxx b/panda/src/egg2sg/loaderFileTypeEgg.cxx index b15031a714..3d2dbe67f7 100644 --- a/panda/src/egg2sg/loaderFileTypeEgg.cxx +++ b/panda/src/egg2sg/loaderFileTypeEgg.cxx @@ -18,8 +18,9 @@ #include "loaderFileTypeEgg.h" #include "load_egg_file.h" +#include "qpload_egg_file.h" -#include +#include "eggData.h" TypeHandle LoaderFileTypeEgg::_type_handle; @@ -74,3 +75,14 @@ load_file(const Filename &path, bool) const { PT_NamedNode result = load_egg_file(path); return result.p(); } + +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileTypeEgg::load_file +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PT(PandaNode) LoaderFileTypeEgg:: +qpload_file(const Filename &path, bool) const { + PT(PandaNode) result = qpload_egg_file(path); + return result; +} diff --git a/panda/src/egg2sg/loaderFileTypeEgg.h b/panda/src/egg2sg/loaderFileTypeEgg.h index 2fc62c3a56..19296545b7 100644 --- a/panda/src/egg2sg/loaderFileTypeEgg.h +++ b/panda/src/egg2sg/loaderFileTypeEgg.h @@ -19,9 +19,9 @@ #ifndef LOADERFILETYPEEGG_H #define LOADERFILETYPEEGG_H -#include +#include "pandabase.h" -#include +#include "loaderFileType.h" //////////////////////////////////////////////////////////////////// // Class : LoaderFileTypeEgg @@ -36,6 +36,7 @@ public: virtual void resolve_filename(Filename &path) const; virtual PT_Node load_file(const Filename &path, bool report_errors) const; + virtual PT(PandaNode) qpload_file(const Filename &path, bool report_errors) const; public: static TypeHandle get_class_type() { diff --git a/panda/src/gobj/geomSprite.cxx b/panda/src/gobj/geomSprite.cxx index 416d3dab29..950bf097c5 100644 --- a/panda/src/gobj/geomSprite.cxx +++ b/panda/src/gobj/geomSprite.cxx @@ -152,7 +152,7 @@ register_with_read_factory(void) { // Description: //////////////////////////////////////////////////////////////////// int GeomSprite:: -complete_pointers(vector_typedWritable &p_list, BamReader *manager) { +complete_pointers(TypedWritable **p_list, BamReader *manager) { int index = Geom::complete_pointers(p_list, manager); _texture = DCAST(Texture, p_list[index]); diff --git a/panda/src/gobj/geomSprite.h b/panda/src/gobj/geomSprite.h index 488b2630af..06a7af3a65 100644 --- a/panda/src/gobj/geomSprite.h +++ b/panda/src/gobj/geomSprite.h @@ -88,7 +88,7 @@ public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); - int complete_pointers(vector_typedWritable &plist, BamReader *manager); + int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_GeomSprite(const FactoryParams ¶ms); protected: diff --git a/panda/src/graph/node.cxx b/panda/src/graph/node.cxx index eb67000c5c..011c26c605 100644 --- a/panda/src/graph/node.cxx +++ b/panda/src/graph/node.cxx @@ -562,7 +562,7 @@ write_datagram(BamWriter *manager, Datagram &me) { // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int Node:: -complete_pointers(vector_typedWritable &p_list, BamReader *manager) { +complete_pointers(TypedWritable **p_list, BamReader *manager) { if (manager->get_file_minor_ver() < 3) { // In bam versions before 3.3, this function does nothing (since // the arcs are completely responsible for adding themselves to diff --git a/panda/src/graph/node.h b/panda/src/graph/node.h index c29f2624fc..de4fc030ea 100644 --- a/panda/src/graph/node.h +++ b/panda/src/graph/node.h @@ -125,7 +125,7 @@ protected: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_Node(const FactoryParams ¶ms); diff --git a/panda/src/graph/nodeRelation.cxx b/panda/src/graph/nodeRelation.cxx index b90ab4539a..c32a533a28 100644 --- a/panda/src/graph/nodeRelation.cxx +++ b/panda/src/graph/nodeRelation.cxx @@ -902,7 +902,7 @@ write_datagram(BamWriter *manager, Datagram &me) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int NodeRelation:: -complete_pointers(vector_typedWritable &p_list, BamReader *manager) { +complete_pointers(TypedWritable **p_list, BamReader *manager) { nassertr(p_list[0] != TypedWritable::Null && p_list[1] != TypedWritable::Null, 0); _parent = DCAST(Node, p_list[0]); diff --git a/panda/src/graph/nodeRelation.h b/panda/src/graph/nodeRelation.h index 07dc94fc6f..b6a7fdd3c9 100644 --- a/panda/src/graph/nodeRelation.h +++ b/panda/src/graph/nodeRelation.h @@ -192,7 +192,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_NodeRelation(const FactoryParams ¶ms); diff --git a/panda/src/gsgbase/Sources.pp b/panda/src/gsgbase/Sources.pp index c7ae41cf67..465295302f 100644 --- a/panda/src/gsgbase/Sources.pp +++ b/panda/src/gsgbase/Sources.pp @@ -4,7 +4,7 @@ #begin lib_target #define TARGET gsgbase #define LOCAL_LIBS \ - putil graph + putil graph linmath #define COMBINED_SOURCES $[TARGET]_composite1.cxx diff --git a/panda/src/gsgbase/graphicsStateGuardianBase.h b/panda/src/gsgbase/graphicsStateGuardianBase.h index e048758c71..cc75cf8a2c 100644 --- a/panda/src/gsgbase/graphicsStateGuardianBase.h +++ b/panda/src/gsgbase/graphicsStateGuardianBase.h @@ -23,6 +23,7 @@ #include "typedReferenceCount.h" #include "nodeTransitions.h" +#include "luse.h" // A handful of forward references. @@ -148,6 +149,13 @@ public: virtual void set_state_and_transform(const RenderState *state, const TransformState *transform)=0; + // This function may only be called during a render traversal; it + // will compute the distance to the indicated point, assumed to be + // in modelview coordinates, from the camera plane. This is a + // virtual function because different GSG's may define the modelview + // coordinate space differently. + virtual float compute_distance_to(const LPoint3f &point) const=0; + // Defined here are some internal interface functions for the // GraphicsStateGuardian. These are here to support // double-dispatching from Geoms and NodeTransitions, and are diff --git a/panda/src/loader/Sources.pp b/panda/src/loader/Sources.pp index 9fcd19d1cc..d5e75d52c3 100644 --- a/panda/src/loader/Sources.pp +++ b/panda/src/loader/Sources.pp @@ -4,7 +4,7 @@ #begin lib_target #define TARGET loader #define LOCAL_LIBS \ - event graph ipc putil express downloader + event pgraph graph ipc putil express downloader #define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx diff --git a/panda/src/loader/bamFile.cxx b/panda/src/loader/bamFile.cxx index 708cc51c32..e3ccf25093 100644 --- a/panda/src/loader/bamFile.cxx +++ b/panda/src/loader/bamFile.cxx @@ -192,13 +192,7 @@ write_object(const TypedWritable *object) { return false; } - // We'll go ahead and cast the const TypedWritable pointer to a - // non-const for issuing the actual write. This allows - // write_datagram to be defined in such a way that it can modify - // itself in some minor way if it must; we assume that no class will - // abuse this privilege and modify its contents significantly during - // write_datagram(). - if (!_writer->write_object((TypedWritable *)object)) { + if (!_writer->write_object(object)) { close(); return false; } diff --git a/panda/src/loader/loader.I b/panda/src/loader/loader.I index 25848a97b1..39ec5e0fb1 100644 --- a/panda/src/loader/loader.I +++ b/panda/src/loader/loader.I @@ -28,3 +28,16 @@ load_sync(const Filename &filename) const { } return load_file(filename); } + +//////////////////////////////////////////////////////////////////// +// Function: Loader::load_sync +// Access: Public +// Description: Loads the file immediately, waiting for it to complete. +//////////////////////////////////////////////////////////////////// +INLINE PT(PandaNode) Loader:: +qpload_sync(const Filename &filename) const { + if (!_file_types_loaded) { + load_file_types(); + } + return qpload_file(filename); +} diff --git a/panda/src/loader/loader.cxx b/panda/src/loader/loader.cxx index ca8fce44da..2ad5d39bd4 100644 --- a/panda/src/loader/loader.cxx +++ b/panda/src/loader/loader.cxx @@ -20,22 +20,19 @@ #include "loaderFileTypeRegistry.h" #include "config_loader.h" -#include -#include -#include -#include -#include -#include -#include +#include "event.h" +#include "pt_Event.h" +#include "throw_event.h" +#include "eventParameter.h" +#include "circBuffer.h" +#include "filename.h" +#include "load_dso.h" #include "plist.h" #include "pvector.h" #include -//////////////////////////////////////////////////////////////////// -// Defines -//////////////////////////////////////////////////////////////////// bool Loader::_file_types_loaded = false; //////////////////////////////////////////////////////////////////// @@ -337,6 +334,51 @@ load_file(const Filename &filename) const { return result; } +//////////////////////////////////////////////////////////////////// +// Function: Loader::load_file +// Access: Private +// Description: Loads a single scene graph file, if possible. +// Returns the Node that is the root of the file, or +// NULL if the file cannot be loaded. +//////////////////////////////////////////////////////////////////// +PT(PandaNode) Loader:: +qpload_file(const Filename &filename) const { + string extension = filename.get_extension(); + + if (extension.empty()) { + return qpload_unknown_file_type(filename); + } + + LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr(); + LoaderFileType *requested_type = + reg->get_type_from_extension(extension); + + if (requested_type == (LoaderFileType *)NULL) { + loader_cat.error() + << "Extension of file " << filename + << " is unrecognized; cannot load.\n"; + loader_cat.error(false) + << "Currently known scene file types are:\n"; + reg->write_types(loader_cat.error(false), 2); + return NULL; + } + + Filename requested_filename = filename; + if (!requested_filename.is_fully_qualified()) { + // Ask the loader type to look for the file along its paths. + requested_type->resolve_filename(requested_filename); + } + + if (loader_cat.is_debug()) { + loader_cat.debug() + << "Loading " << requested_type->get_name() << " file: " + << requested_filename << "\n"; + } + + PT(PandaNode) result = requested_type->qpload_file(requested_filename, true); + return result; +} + class LoaderConsiderFile { public: Filename _path; @@ -436,6 +478,94 @@ load_unknown_file_type(const Filename &filename) const { return (Node *)NULL; } +//////////////////////////////////////////////////////////////////// +// Function: Loader::load_unknown_file_type +// Access: Private +// Description: Attempts to guess which file is meant when a file +// with no extension is given. Looks around for a file +// with a suitable extension for each of our known file +// types, and loads the most recent file available of +// any file type. +//////////////////////////////////////////////////////////////////// +PT(PandaNode) Loader:: +qpload_unknown_file_type(const Filename &filename) const { + typedef pvector Files; + Files files; + + // First, build up a list of all of the possible files it could be. + LoaderFileTypeRegistry *reg = LoaderFileTypeRegistry::get_ptr(); + int num_types = reg->get_num_types(); + + if (num_types == 0) { + loader_cat.error() + << "Can't load file " << filename + << "; no scene file types are known.\n"; + return (PandaNode *)NULL; + } + + for (int i = 0; i < num_types; i++) { + LoaderConsiderFile consider; + consider._type = reg->get_type(i); + consider._path = filename; + consider._path.set_extension(consider._type->get_extension()); + + if (!consider._path.is_fully_qualified()) { + // Ask the loader type to look for the file along its paths. + consider._type->resolve_filename(consider._path); + } + + if (consider._path.exists()) { + files.push_back(consider); + } + } + + if (files.empty()) { + loader_cat.error() + << "Couldn't find file " << filename << " as:\n"; + for (int i = 0; i < num_types; i++) { + Filename p = filename; + p.set_extension(reg->get_type(i)->get_extension()); + loader_cat.error(false) + << " " << p << "\n"; + } + return (PandaNode *)NULL; + } + + // Now sort the list into order by timestamp, from newest to oldest. + sort(files.begin(), files.end()); + + // And try to load each file one at a time. + Files::const_iterator fi; + + if (loader_cat.is_debug()) { + loader_cat.debug() + << "Loading " << filename << ", one of " << files.size() + << " possible types:\n"; + for (fi = files.begin(); fi != files.end(); ++fi) { + loader_cat.debug(false) + << " " << (*fi)._path << "\n"; + } + } + + for (fi = files.begin(); fi != files.end(); ++fi) { + const LoaderConsiderFile &consider = (*fi); + PT(PandaNode) result = consider._type->qpload_file(consider._path, false); + if (result != (PandaNode *)NULL) { + return result; + } + if (loader_cat.is_debug()) { + loader_cat.debug() + << "Couldn't read " << consider._type->get_name() + << " file " << consider._path << "\n"; + } + } + + loader_cat.error() + << "Cannot read " << files.front()._path << "\n"; + + return (PandaNode *)NULL; +} + //////////////////////////////////////////////////////////////////// // Function: Loader::resolve_unknown_file_type // Access: Private diff --git a/panda/src/loader/loader.h b/panda/src/loader/loader.h index a47026ae15..f5af97c5fa 100644 --- a/panda/src/loader/loader.h +++ b/panda/src/loader/loader.h @@ -17,18 +17,16 @@ //////////////////////////////////////////////////////////////////// #ifndef LOADER_H #define LOADER_H -// -//////////////////////////////////////////////////////////////////// -// Includes -//////////////////////////////////////////////////////////////////// -#include -#include -#include -#include -#include -#include -#include +#include "pandabase.h" + +#include "notify.h" +#include "node.h" +#include "pt_Node.h" +#include "pandaNode.h" +#include "filename.h" +#include "tokenBoard.h" +#include "asyncUtility.h" class LoaderToken; @@ -45,6 +43,7 @@ PUBLISHED: void resolve_filename(Filename &filename) const; INLINE PT_Node load_sync(const Filename &filename) const; + INLINE PT(PandaNode) qpload_sync(const Filename &filename) const; uint request_load(const Filename &filename, const string &event_name); bool check_load(uint id); @@ -57,6 +56,8 @@ private: virtual bool process_request(void); PT_Node load_file(const Filename &filename) const; PT_Node load_unknown_file_type(const Filename &filename) const; + PT(PandaNode) qpload_file(const Filename &filename) const; + PT(PandaNode) qpload_unknown_file_type(const Filename &filename) const; void resolve_unknown_file_type(Filename &filename) const; typedef TokenBoard LoaderTokenBoard; diff --git a/panda/src/loader/loaderFileType.cxx b/panda/src/loader/loaderFileType.cxx index 6406ffa6e7..6ed0a7bf57 100644 --- a/panda/src/loader/loaderFileType.cxx +++ b/panda/src/loader/loaderFileType.cxx @@ -51,3 +51,16 @@ LoaderFileType:: void LoaderFileType:: resolve_filename(Filename &) const { } + +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileType::load_file +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PT(PandaNode) LoaderFileType:: +qpload_file(const Filename &path, bool report_errors) const +{ + loader_cat.error() + << get_type() << " cannot read PandaNode objects.\n"; + return NULL; +} diff --git a/panda/src/loader/loaderFileType.h b/panda/src/loader/loaderFileType.h index 2833684ed1..5e3a56a333 100644 --- a/panda/src/loader/loaderFileType.h +++ b/panda/src/loader/loaderFileType.h @@ -19,12 +19,14 @@ #ifndef LOADERFILETYPE_H #define LOADERFILETYPE_H -#include +#include "pandabase.h" -#include -#include -#include -#include +#include "typedObject.h" +#include "node.h" +#include "pt_Node.h" +#include "filename.h" +#include "pandaNode.h" +#include "pointerTo.h" //////////////////////////////////////////////////////////////////// // Class : LoaderFileType @@ -45,6 +47,7 @@ public: virtual void resolve_filename(Filename &path) const; virtual PT_Node load_file(const Filename &path, bool report_errors) const=0; + virtual PT(PandaNode) qpload_file(const Filename &path, bool report_errors) const; public: static TypeHandle get_class_type() { diff --git a/panda/src/loader/loaderFileTypeBam.cxx b/panda/src/loader/loaderFileTypeBam.cxx index 2c29746d6f..3276a10b44 100644 --- a/panda/src/loader/loaderFileTypeBam.cxx +++ b/panda/src/loader/loaderFileTypeBam.cxx @@ -121,3 +121,53 @@ load_file(const Filename &path, bool report_errors) const return result; } +//////////////////////////////////////////////////////////////////// +// Function: LoaderFileTypeBam::load_file +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +PT(PandaNode) LoaderFileTypeBam:: +qpload_file(const Filename &path, bool report_errors) const { + BamFile bam_file; + if (!bam_file.open_read(path, report_errors)) { + return NULL; + } + + PT(PandaNode) result; + + TypedWritable *object = bam_file.read_object(); + if (object == TypedWritable::Null) { + if (report_errors) { + loader_cat.error() << "Bam file " << path << " is empty.\n"; + } + + } else if (!object->is_of_type(PandaNode::get_class_type())) { + if (report_errors) { + loader_cat.error() + << "Bam file " << path + << " contains a " << object->get_type() << ", not a PandaNode.\n"; + } + + } else { + result = DCAST(PandaNode, object); + + if (report_errors) { + bam_file.read_object(); + if (!bam_file.is_eof()) { + loader_cat.warning() + << "Ignoring extra objects in " << path << "\n"; + } + } + } + + if (!bam_file.resolve()) { + if (report_errors) { + loader_cat.error() + << "Unable to resolve Bam file.\n"; + result = (PandaNode *)NULL; + } + } + + return result; +} + diff --git a/panda/src/loader/loaderFileTypeBam.h b/panda/src/loader/loaderFileTypeBam.h index 4e5084f7c1..f53f6677ea 100644 --- a/panda/src/loader/loaderFileTypeBam.h +++ b/panda/src/loader/loaderFileTypeBam.h @@ -19,13 +19,13 @@ #ifndef LOADERFILETYPEBAM_H #define LOADERFILETYPEBAM_H -#include +#include "pandabase.h" #include "loaderFileType.h" //////////////////////////////////////////////////////////////////// -// Class : LoaderFileTypeEgg -// Description : This defines the Loader interface to read Egg files. +// Class : LoaderFileTypeBam +// Description : This defines the Loader interface to read Bam files. //////////////////////////////////////////////////////////////////// class EXPCL_PANDA LoaderFileTypeBam : public LoaderFileType { public: @@ -36,6 +36,7 @@ public: virtual void resolve_filename(Filename &path) const; virtual PT_Node load_file(const Filename &path, bool report_errors) const; + virtual PT(PandaNode) qpload_file(const Filename &path, bool report_errors) const; public: static TypeHandle get_class_type() { diff --git a/panda/src/parametrics/piecewiseCurve.cxx b/panda/src/parametrics/piecewiseCurve.cxx index 4959732504..56e5cf5d28 100644 --- a/panda/src/parametrics/piecewiseCurve.cxx +++ b/panda/src/parametrics/piecewiseCurve.cxx @@ -625,11 +625,9 @@ fillin(DatagramIterator &scan, BamReader *manager) { // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int PiecewiseCurve:: -complete_pointers(vector_typedWritable &p_list, BamReader *manager) { +complete_pointers(TypedWritable **p_list, BamReader *manager) { int used = ParametricCurve::complete_pointers(p_list, manager); - nassertr(used + _segs.size() <= p_list.size(), used); - size_t i; for (i = 0; i < _segs.size(); i++) { _segs[i]._curve = DCAST(ParametricCurve, p_list[used + i]); diff --git a/panda/src/parametrics/piecewiseCurve.h b/panda/src/parametrics/piecewiseCurve.h index 735b9feb60..18b746e1f7 100644 --- a/panda/src/parametrics/piecewiseCurve.h +++ b/panda/src/parametrics/piecewiseCurve.h @@ -99,7 +99,7 @@ protected: protected: virtual void write_datagram(BamWriter *manager, Datagram &me); void fillin(DatagramIterator &scan, BamReader *manager); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); public: diff --git a/panda/src/pgraph/billboardAttrib.cxx b/panda/src/pgraph/billboardAttrib.cxx index 3f5d8eb72e..2f21893bb2 100644 --- a/panda/src/pgraph/billboardAttrib.cxx +++ b/panda/src/pgraph/billboardAttrib.cxx @@ -220,6 +220,16 @@ register_with_read_factory() { void BillboardAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + dg.add_bool(_off); + _up_vector.write_datagram(dg); + dg.add_bool(_eye_relative); + dg.add_bool(_axial_rotate); + dg.add_float32(_offset); + _look_at_point.write_datagram(dg); + + // *** We don't write out the _look_at NodeChain right now. Maybe + // we should. } //////////////////////////////////////////////////////////////////// @@ -239,7 +249,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -252,4 +262,11 @@ make_from_bam(const FactoryParams ¶ms) { void BillboardAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + _off = scan.get_bool(); + _up_vector.read_datagram(scan); + _eye_relative = scan.get_bool(); + _axial_rotate = scan.get_bool(); + _offset = scan.get_float32(); + _look_at_point.read_datagram(scan); } diff --git a/panda/src/pgraph/colorAttrib.cxx b/panda/src/pgraph/colorAttrib.cxx index d9e21fca4e..ed935ac4dc 100644 --- a/panda/src/pgraph/colorAttrib.cxx +++ b/panda/src/pgraph/colorAttrib.cxx @@ -165,6 +165,9 @@ register_with_read_factory() { void ColorAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + dg.add_int8(_type); + _color.write_datagram(dg); } //////////////////////////////////////////////////////////////////// @@ -184,7 +187,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -197,4 +200,7 @@ make_from_bam(const FactoryParams ¶ms) { void ColorAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + _type = (Type)scan.get_int8(); + _color.read_datagram(scan); } diff --git a/panda/src/pgraph/config_pgraph.cxx b/panda/src/pgraph/config_pgraph.cxx index ae3408bf59..b21786097c 100644 --- a/panda/src/pgraph/config_pgraph.cxx +++ b/panda/src/pgraph/config_pgraph.cxx @@ -91,6 +91,7 @@ init_libpgraph() { BillboardAttrib::register_with_read_factory(); ColorAttrib::register_with_read_factory(); + CullBinAttrib::register_with_read_factory(); CullFaceAttrib::register_with_read_factory(); qpGeomNode::register_with_read_factory(); PandaNode::register_with_read_factory(); diff --git a/panda/src/pgraph/cullBinAttrib.cxx b/panda/src/pgraph/cullBinAttrib.cxx index cf7d04be5c..2049998eee 100644 --- a/panda/src/pgraph/cullBinAttrib.cxx +++ b/panda/src/pgraph/cullBinAttrib.cxx @@ -116,6 +116,9 @@ register_with_read_factory() { void CullBinAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + dg.add_string(_bin_name); + dg.add_int32(_draw_order); } //////////////////////////////////////////////////////////////////// @@ -135,7 +138,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -148,4 +151,7 @@ make_from_bam(const FactoryParams ¶ms) { void CullBinAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + _bin_name = scan.get_string(); + _draw_order = scan.get_int32(); } diff --git a/panda/src/pgraph/cullFaceAttrib.cxx b/panda/src/pgraph/cullFaceAttrib.cxx index f1d63bb404..de7c82f24f 100644 --- a/panda/src/pgraph/cullFaceAttrib.cxx +++ b/panda/src/pgraph/cullFaceAttrib.cxx @@ -137,6 +137,8 @@ register_with_read_factory() { void CullFaceAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + dg.add_int8(_mode); } //////////////////////////////////////////////////////////////////// @@ -156,7 +158,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -169,4 +171,6 @@ make_from_bam(const FactoryParams ¶ms) { void CullFaceAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + _mode = (Mode)scan.get_int8(); } diff --git a/panda/src/pgraph/pandaNode.cxx b/panda/src/pgraph/pandaNode.cxx index 381ff5a875..513e74c2c2 100644 --- a/panda/src/pgraph/pandaNode.cxx +++ b/panda/src/pgraph/pandaNode.cxx @@ -141,7 +141,7 @@ make_copy() const { //////////////////////////////////////////////////////////////////// PandaNode *PandaNode:: copy_subgraph() const { - //*** Do something here. + // *** Do something here. nassertr(false, (PandaNode *)NULL); return (PandaNode *)NULL; } @@ -903,6 +903,57 @@ register_with_read_factory() { //////////////////////////////////////////////////////////////////// void PandaNode:: write_datagram(BamWriter *manager, Datagram &dg) { + CDReader cdata(_cycler); + + dg.add_string(get_name()); + manager->write_pointer(dg, cdata->_state); + manager->write_pointer(dg, cdata->_transform); + + // When we write a PandaNode, we write out its list of child nodes, + // but not its parent nodes--so that writing out a node implicitly + // writes out all of the nodes in the subgraph below, but not the + // nodes above as well. + + int num_children = cdata->_down.size(); + nassertv(num_children == (int)(PN_uint16)num_children); + dg.add_uint16(num_children); + + // **** We should smarten up the writing of the sort number--most of + // the time these will all be zero. + Down::const_iterator ci; + for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) { + PandaNode *child = (*ci).get_child(); + int sort = (*ci).get_sort(); + manager->write_pointer(dg, child); + dg.add_int32(sort); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: PandaNode::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int PandaNode:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + CDWriter cdata(_cycler); + int pi = TypedWritable::complete_pointers(p_list, manager); + + // Get the state and transform pointers. + cdata->_state = DCAST(RenderState, p_list[pi++]); + cdata->_transform = DCAST(TransformState, p_list[pi++]); + + // Get the child pointers. + Down::iterator ci; + for (ci = cdata->_down.begin(); ci != cdata->_down.end(); ++ci) { + int sort = (*ci).get_sort(); + PT(PandaNode) node = DCAST(PandaNode, p_list[pi++]); + (*ci) = DownConnection(node, sort); + } + + return pi; } //////////////////////////////////////////////////////////////////// @@ -934,4 +985,23 @@ make_from_bam(const FactoryParams ¶ms) { //////////////////////////////////////////////////////////////////// void PandaNode:: fillin(DatagramIterator &scan, BamReader *manager) { + CDWriter cdata(_cycler); + + TypedWritable::fillin(scan, manager); + + string name = scan.get_string(); + set_name(name); + + // Read the state and transform pointers. + manager->read_pointer(scan, this); + manager->read_pointer(scan, this); + + int num_children = scan.get_uint16(); + // Read the list of child nodes. Push back a NULL for each one. + cdata->_down.reserve(num_children); + for (int i = 0; i < num_children; i++) { + manager->read_pointer(scan, this); + int sort = scan.get_int32(); + cdata->_down.push_back(DownConnection(NULL, sort)); + } } diff --git a/panda/src/pgraph/pandaNode.h b/panda/src/pgraph/pandaNode.h index 41faeebb02..3ec5503b1a 100644 --- a/panda/src/pgraph/pandaNode.h +++ b/panda/src/pgraph/pandaNode.h @@ -235,6 +235,8 @@ public: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); diff --git a/panda/src/pgraph/qpcullTraverser.cxx b/panda/src/pgraph/qpcullTraverser.cxx index 6b4b237363..195daaaa78 100644 --- a/panda/src/pgraph/qpcullTraverser.cxx +++ b/panda/src/pgraph/qpcullTraverser.cxx @@ -182,7 +182,7 @@ r_traverse(PandaNode *node, if (node->is_final()) { // The bounding volume is partially, but not completely, // within the viewing frustum. Normally we'd keep testing - // child bounded volumes as we continue down. But this node + // child bounding volumes as we continue down. But this node // has the "final" flag, so the user is claiming that there is // some important reason we should consider everything visible // at this point. So be it. diff --git a/panda/src/pgraph/qpgeomNode.cxx b/panda/src/pgraph/qpgeomNode.cxx index 23134be45c..11557084d3 100644 --- a/panda/src/pgraph/qpgeomNode.cxx +++ b/panda/src/pgraph/qpgeomNode.cxx @@ -212,6 +212,42 @@ register_with_read_factory() { void qpGeomNode:: write_datagram(BamWriter *manager, Datagram &dg) { PandaNode::write_datagram(manager, dg); + + CDReader cdata(_cycler); + + int num_geoms = cdata->_geoms.size(); + nassertv(num_geoms == (int)(PN_uint16)num_geoms); + dg.add_uint16(num_geoms); + + Geoms::const_iterator gi; + for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { + const GeomEntry &entry = (*gi); + manager->write_pointer(dg, entry._geom); + manager->write_pointer(dg, entry._state); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: qpGeomNode::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int qpGeomNode:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + CDWriter cdata(_cycler); + int pi = PandaNode::complete_pointers(p_list, manager); + + // Get the geom and state pointers. + Geoms::iterator gi; + for (gi = cdata->_geoms.begin(); gi != cdata->_geoms.end(); ++gi) { + GeomEntry &entry = (*gi); + entry._geom = DCAST(Geom, p_list[pi++]); + entry._state = DCAST(RenderState, p_list[pi++]); + } + + return pi; } //////////////////////////////////////////////////////////////////// @@ -243,5 +279,16 @@ make_from_bam(const FactoryParams ¶ms) { //////////////////////////////////////////////////////////////////// void qpGeomNode:: fillin(DatagramIterator &scan, BamReader *manager) { + CDWriter cdata(_cycler); + PandaNode::fillin(scan, manager); + + int num_geoms = scan.get_uint16(); + // Read the list of geoms and states. Push back a NULL for each one. + cdata->_geoms.reserve(num_geoms); + for (int i = 0; i < num_geoms; i++) { + manager->read_pointer(scan, this); + manager->read_pointer(scan, this); + cdata->_geoms.push_back(GeomEntry(NULL, NULL)); + } } diff --git a/panda/src/pgraph/qpgeomNode.h b/panda/src/pgraph/qpgeomNode.h index aa3bf39c6f..b5efbf77a8 100644 --- a/panda/src/pgraph/qpgeomNode.h +++ b/panda/src/pgraph/qpgeomNode.h @@ -91,6 +91,8 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, + BamReader *manager); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); diff --git a/panda/src/pgraph/renderAttrib.cxx b/panda/src/pgraph/renderAttrib.cxx index 1f635d355e..20782a9fa3 100644 --- a/panda/src/pgraph/renderAttrib.cxx +++ b/panda/src/pgraph/renderAttrib.cxx @@ -218,7 +218,40 @@ make_default_impl() const { // for shipping out to a Bam file. //////////////////////////////////////////////////////////////////// void RenderAttrib:: -write_datagram(BamWriter *, Datagram &) { +write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderAttrib::change_this +// Access: Public, Static +// Description: Called immediately after complete_pointers(), this +// gives the object a chance to adjust its own pointer +// if desired. Most objects don't change pointers after +// completion, but some need to. +// +// Once this function has been called, the old pointer +// will no longer be accessed. +//////////////////////////////////////////////////////////////////// +TypedWritable *RenderAttrib:: +change_this(TypedWritable *old_ptr, BamReader *manager) { + // First, uniquify the pointer. + RenderAttrib *attrib = DCAST(RenderAttrib, old_ptr); + CPT(RenderAttrib) pointer = return_new(attrib); + + // But now we have a problem, since we have to hold the reference + // count and there's no way to return a TypedWritable while still + // holding the reference count! We work around this by explicitly + // upping the count, and also setting a finalize() callback to down + // it later. + if (pointer == attrib) { + pointer->ref(); + manager->register_finalize(attrib); + } + + // We have to cast the pointer back to non-const, because the bam + // reader expects that. + return (RenderAttrib *)pointer.p(); } //////////////////////////////////////////////////////////////////// @@ -240,33 +273,6 @@ finalize() { nassertv(get_ref_count() != 0); } -//////////////////////////////////////////////////////////////////// -// Function: RenderAttrib::new_from_bam -// Access: Protected, Static -// Description: Uniquifies the pointer for a RenderAttrib object just -// created from a bam file, and preserves its reference -// count correctly. -//////////////////////////////////////////////////////////////////// -TypedWritable *RenderAttrib:: -new_from_bam(RenderAttrib *attrib, BamReader *manager) { - // First, uniquify the pointer. - CPT(RenderAttrib) pointer = return_new(attrib); - - // But now we have a problem, since we have to hold the reference - // count and there's no way to return a TypedWritable while still - // holding the reference count! We work around this by explicitly - // upping the count, and also setting a finalize() callback to down - // it later. - if (pointer == attrib) { - pointer->ref(); - manager->register_finalize(attrib); - } - - // We have to cast the pointer back to non-const, because the bam - // reader expects that. - return (RenderAttrib *)pointer.p(); -} - //////////////////////////////////////////////////////////////////// // Function: RenderAttrib::fillin // Access: Protected @@ -276,4 +282,5 @@ new_from_bam(RenderAttrib *attrib, BamReader *manager) { //////////////////////////////////////////////////////////////////// void RenderAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); } diff --git a/panda/src/pgraph/renderAttrib.h b/panda/src/pgraph/renderAttrib.h index afebd6c86e..c0ccc0651e 100644 --- a/panda/src/pgraph/renderAttrib.h +++ b/panda/src/pgraph/renderAttrib.h @@ -81,6 +81,7 @@ private: public: virtual void write_datagram(BamWriter *manager, Datagram &dg); + static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(); protected: diff --git a/panda/src/pgraph/renderState.I b/panda/src/pgraph/renderState.I index 8d8ca8bcf8..1aaf50186d 100644 --- a/panda/src/pgraph/renderState.I +++ b/panda/src/pgraph/renderState.I @@ -30,6 +30,19 @@ Attribute(const RenderAttrib *attrib, int override) : { } +//////////////////////////////////////////////////////////////////// +// Function: RenderState::Attribute::Constructor +// Access: Public +// Description: This constructor is only used when reading the +// RenderState from a bam file. At this point, the +// attribute pointer is unknown. +//////////////////////////////////////////////////////////////////// +INLINE RenderState::Attribute:: +Attribute(int override) : + _override(override) +{ +} + //////////////////////////////////////////////////////////////////// // Function: RenderState::Attribute::Constructor // Access: Public diff --git a/panda/src/pgraph/renderState.cxx b/panda/src/pgraph/renderState.cxx index 41ccb5a51e..a76ba406e5 100644 --- a/panda/src/pgraph/renderState.cxx +++ b/panda/src/pgraph/renderState.cxx @@ -929,13 +929,91 @@ register_with_read_factory() { //////////////////////////////////////////////////////////////////// void RenderState:: write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + + int num_attribs = _attributes.size(); + nassertv(num_attribs == (int)(PN_uint16)num_attribs); + dg.add_uint16(num_attribs); + + // **** We should smarten up the writing of the override + // number--most of the time these will all be zero. + Attributes::const_iterator ai; + for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) { + const Attribute &attribute = (*ai); + + manager->write_pointer(dg, attribute._attrib); + dg.add_int32(attribute._override); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int RenderState:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = TypedWritable::complete_pointers(p_list, manager); + + // Get the attribute pointers. + Attributes::iterator ai; + for (ai = _attributes.begin(); ai != _attributes.end(); ++ai) { + Attribute &attribute = (*ai); + + attribute._attrib = DCAST(RenderAttrib, p_list[pi++]); + nassertr(attribute._attrib != (RenderAttrib *)NULL, pi); + attribute._type = attribute._attrib->get_type(); + } + + // Now make sure the array is properly sorted. (It won't + // necessarily preserve its correct sort after being read from bam, + // because the sort is based on TypeHandle indices, which can change + // from session to session.) + _attributes.sort(); + + return pi; +} + +//////////////////////////////////////////////////////////////////// +// Function: RenderState::change_this +// Access: Public, Static +// Description: Called immediately after complete_pointers(), this +// gives the object a chance to adjust its own pointer +// if desired. Most objects don't change pointers after +// completion, but some need to. +// +// Once this function has been called, the old pointer +// will no longer be accessed. +//////////////////////////////////////////////////////////////////// +TypedWritable *RenderState:: +change_this(TypedWritable *old_ptr, BamReader *manager) { + // First, uniquify the pointer. + RenderState *state = DCAST(RenderState, old_ptr); + CPT(RenderState) pointer = return_new(state); + + // But now we have a problem, since we have to hold the reference + // count and there's no way to return a TypedWritable while still + // holding the reference count! We work around this by explicitly + // upping the count, and also setting a finalize() callback to down + // it later. + if (pointer == state) { + pointer->ref(); + manager->register_finalize(state); + } + + // We have to cast the pointer back to non-const, because the bam + // reader expects that. + return (RenderState *)pointer.p(); } //////////////////////////////////////////////////////////////////// // Function: RenderState::finalize // Access: Public, Virtual -// Description: Method to ensure that any necessary clean up tasks -// that have to be performed by this object are performed +// Description: Called by the BamReader to perform any final actions +// needed for setting up the object after all objects +// have been read and all pointers have been completed. //////////////////////////////////////////////////////////////////// void RenderState:: finalize() { @@ -966,35 +1044,9 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); state->fillin(scan, manager); + manager->register_change_this(change_this, state); - return new_from_bam(state, manager); -} - -//////////////////////////////////////////////////////////////////// -// Function: RenderState::new_from_bam -// Access: Protected, Static -// Description: Uniquifies the pointer for a RenderState object just -// created from a bam file, and preserves its reference -// count correctly. -//////////////////////////////////////////////////////////////////// -TypedWritable *RenderState:: -new_from_bam(RenderState *state, BamReader *manager) { - // First, uniquify the pointer. - CPT(RenderState) pointer = return_new(state); - - // But now we have a problem, since we have to hold the reference - // count and there's no way to return a TypedWritable while still - // holding the reference count! We work around this by explicitly - // upping the count, and also setting a finalize() callback to down - // it later. - if (pointer == state) { - pointer->ref(); - manager->register_finalize(state); - } - - // We have to cast the pointer back to non-const, because the bam - // reader expects that. - return (RenderState *)pointer.p(); + return state; } //////////////////////////////////////////////////////////////////// @@ -1006,4 +1058,16 @@ new_from_bam(RenderState *state, BamReader *manager) { //////////////////////////////////////////////////////////////////// void RenderState:: fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + int num_attribs = scan.get_uint16(); + + // Push back a NULL pointer for each attribute for now, until we get + // the actual list of pointers later in complete_pointers(). + _attributes.reserve(num_attribs); + for (int i = 0; i < num_attribs; i++) { + manager->read_pointer(scan, this); + int override = scan.get_int32(); + _attributes.push_back(Attribute(override)); + } } diff --git a/panda/src/pgraph/renderState.h b/panda/src/pgraph/renderState.h index 486b14f91a..334f285527 100644 --- a/panda/src/pgraph/renderState.h +++ b/panda/src/pgraph/renderState.h @@ -143,6 +143,7 @@ private: class Attribute { public: INLINE Attribute(const RenderAttrib *attrib, int override); + INLINE Attribute(int override); INLINE Attribute(TypeHandle type); INLINE Attribute(const Attribute ©); INLINE void operator = (const Attribute ©); @@ -173,11 +174,12 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); + static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); - static TypedWritable *new_from_bam(RenderState *state, BamReader *manager); void fillin(DatagramIterator &scan, BamReader *manager); public: diff --git a/panda/src/pgraph/textureAttrib.cxx b/panda/src/pgraph/textureAttrib.cxx index 9c5381fd26..c44dfe8670 100644 --- a/panda/src/pgraph/textureAttrib.cxx +++ b/panda/src/pgraph/textureAttrib.cxx @@ -137,6 +137,27 @@ register_with_read_factory() { void TextureAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + manager->write_pointer(dg, _texture); +} + +//////////////////////////////////////////////////////////////////// +// Function: TextureAttrib::complete_pointers +// Access: Public, Virtual +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +//////////////////////////////////////////////////////////////////// +int TextureAttrib:: +complete_pointers(TypedWritable **p_list, BamReader *manager) { + int pi = RenderAttrib::complete_pointers(p_list, manager); + + TypedWritable *texture = p_list[pi++]; + if (texture != (TypedWritable *)NULL) { + _texture = DCAST(Texture, texture); + } + + return pi; } //////////////////////////////////////////////////////////////////// @@ -156,7 +177,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -169,4 +190,7 @@ make_from_bam(const FactoryParams ¶ms) { void TextureAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + // Read the _texture pointer. + manager->read_pointer(scan, this); } diff --git a/panda/src/pgraph/textureAttrib.h b/panda/src/pgraph/textureAttrib.h index 302323c2ba..af467aa66b 100644 --- a/panda/src/pgraph/textureAttrib.h +++ b/panda/src/pgraph/textureAttrib.h @@ -55,6 +55,7 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); diff --git a/panda/src/pgraph/transformState.cxx b/panda/src/pgraph/transformState.cxx index 2c58c27e93..87a92bdf88 100644 --- a/panda/src/pgraph/transformState.cxx +++ b/panda/src/pgraph/transformState.cxx @@ -577,13 +577,69 @@ register_with_read_factory() { //////////////////////////////////////////////////////////////////// void TransformState:: write_datagram(BamWriter *manager, Datagram &dg) { + TypedWritable::write_datagram(manager, dg); + + if ((_flags & F_is_identity) != 0) { + // Identity, nothing much to that. + int flags = F_is_identity | F_singular_known; + dg.add_uint16(flags); + + } else if ((_flags & F_components_given) != 0) { + // A component-based transform. + int flags = F_components_given | F_components_known | F_has_components; + dg.add_uint16(flags); + + _pos.write_datagram(dg); + _hpr.write_datagram(dg); + _scale.write_datagram(dg); + + } else { + // A general matrix. + nassertv((_flags & F_mat_known) != 0); + int flags = F_mat_known; + dg.add_uint16(flags); + _mat.write_datagram(dg); + } +} + +//////////////////////////////////////////////////////////////////// +// Function: TransformState::change_this +// Access: Public, Static +// Description: Called immediately after complete_pointers(), this +// gives the object a chance to adjust its own pointer +// if desired. Most objects don't change pointers after +// completion, but some need to. +// +// Once this function has been called, the old pointer +// will no longer be accessed. +//////////////////////////////////////////////////////////////////// +TypedWritable *TransformState:: +change_this(TypedWritable *old_ptr, BamReader *manager) { + // First, uniquify the pointer. + TransformState *state = DCAST(TransformState, old_ptr); + CPT(TransformState) pointer = return_new(state); + + // But now we have a problem, since we have to hold the reference + // count and there's no way to return a TypedWritable while still + // holding the reference count! We work around this by explicitly + // upping the count, and also setting a finalize() callback to down + // it later. + if (pointer == state) { + pointer->ref(); + manager->register_finalize(state); + } + + // We have to cast the pointer back to non-const, because the bam + // reader expects that. + return (TransformState *)pointer.p(); } //////////////////////////////////////////////////////////////////// // Function: TransformState::finalize // Access: Public, Virtual -// Description: Method to ensure that any necessary clean up tasks -// that have to be performed by this object are performed +// Description: Called by the BamReader to perform any final actions +// needed for setting up the object after all objects +// have been read and all pointers have been completed. //////////////////////////////////////////////////////////////////// void TransformState:: finalize() { @@ -614,35 +670,9 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); state->fillin(scan, manager); + manager->register_change_this(change_this, state); - return new_from_bam(state, manager); -} - -//////////////////////////////////////////////////////////////////// -// Function: TransformState::new_from_bam -// Access: Protected, Static -// Description: Uniquifies the pointer for a TransformState object just -// created from a bam file, and preserves its reference -// count correctly. -//////////////////////////////////////////////////////////////////// -TypedWritable *TransformState:: -new_from_bam(TransformState *state, BamReader *manager) { - // First, uniquify the pointer. - CPT(TransformState) pointer = return_new(state); - - // But now we have a problem, since we have to hold the reference - // count and there's no way to return a TypedWritable while still - // holding the reference count! We work around this by explicitly - // upping the count, and also setting a finalize() callback to down - // it later. - if (pointer == state) { - pointer->ref(); - manager->register_finalize(state); - } - - // We have to cast the pointer back to non-const, because the bam - // reader expects that. - return (TransformState *)pointer.p(); + return state; } //////////////////////////////////////////////////////////////////// @@ -654,4 +684,19 @@ new_from_bam(TransformState *state, BamReader *manager) { //////////////////////////////////////////////////////////////////// void TransformState:: fillin(DatagramIterator &scan, BamReader *manager) { + TypedWritable::fillin(scan, manager); + + _flags = scan.get_uint16(); + + if ((_flags & F_components_known) != 0) { + // Componentwise transform. + _pos.read_datagram(scan); + _hpr.read_datagram(scan); + _scale.read_datagram(scan); + } + + if ((_flags & F_mat_known) != 0) { + // General matrix. + _mat.read_datagram(scan); + } } diff --git a/panda/src/pgraph/transformState.h b/panda/src/pgraph/transformState.h index 6b7c1a1a79..ad1dda51fb 100644 --- a/panda/src/pgraph/transformState.h +++ b/panda/src/pgraph/transformState.h @@ -151,11 +151,11 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &dg); + static TypedWritable *change_this(TypedWritable *old_ptr, BamReader *manager); virtual void finalize(); protected: static TypedWritable *make_from_bam(const FactoryParams ¶ms); - static TypedWritable *new_from_bam(TransformState *state, BamReader *manager); void fillin(DatagramIterator &scan, BamReader *manager); public: diff --git a/panda/src/pgraph/transparencyAttrib.cxx b/panda/src/pgraph/transparencyAttrib.cxx index 661817bcc6..350f47d77d 100644 --- a/panda/src/pgraph/transparencyAttrib.cxx +++ b/panda/src/pgraph/transparencyAttrib.cxx @@ -142,6 +142,8 @@ register_with_read_factory() { void TransparencyAttrib:: write_datagram(BamWriter *manager, Datagram &dg) { RenderAttrib::write_datagram(manager, dg); + + dg.add_int8(_mode); } //////////////////////////////////////////////////////////////////// @@ -161,7 +163,7 @@ make_from_bam(const FactoryParams ¶ms) { parse_params(params, scan, manager); attrib->fillin(scan, manager); - return new_from_bam(attrib, manager); + return attrib; } //////////////////////////////////////////////////////////////////// @@ -174,4 +176,6 @@ make_from_bam(const FactoryParams ¶ms) { void TransparencyAttrib:: fillin(DatagramIterator &scan, BamReader *manager) { RenderAttrib::fillin(scan, manager); + + _mode = (Mode)scan.get_int8(); } diff --git a/panda/src/putil/bamReader.cxx b/panda/src/putil/bamReader.cxx index 217eb56614..05cd114cde 100644 --- a/panda/src/putil/bamReader.cxx +++ b/panda/src/putil/bamReader.cxx @@ -42,6 +42,7 @@ BamReader(DatagramGenerator *generator) : _source(generator) { _num_extra_objects = 0; + _now_creating = _created_objs.end(); _pta_id = -1; } @@ -177,7 +178,8 @@ read_object() { return (TypedWritable *)NULL; } else { - TypedWritable *object = (*oi).second; + CreatedObj &created_obj = (*oi).second; + TypedWritable *object = created_obj._ptr; if (bam_cat.is_spam()) { if (object != (TypedWritable *)NULL) { @@ -185,6 +187,11 @@ read_object() { << "Returning object of type " << object->get_type() << "\n"; } } + if (created_obj._change_this != NULL) { + bam_cat.warning() + << "Returning pointer to " << object->get_type() + << " that might change.\n"; + } return object; } @@ -210,68 +217,116 @@ read_object() { //////////////////////////////////////////////////////////////////// bool BamReader:: resolve() { - bool all_completed = true; + bool all_completed; + bool any_completed_this_pass; - // Walk through all the objects that still have outstanding pointers. - Requests::iterator ri; - ri = _deferred_pointers.begin(); - while (ri != _deferred_pointers.end()) { - TypedWritable *whom = (*ri).first; - const vector_ushort &pointers = (*ri).second; + do { + all_completed = true; + any_completed_this_pass = false; - // Now make sure we have all of the pointers this object is - // waiting for. If any of the pointers has not yet been read in, - // we can't resolve this object--we can't do anything for a given - // object until we have *all* outstanding pointers for that - // object. - - bool is_complete = true; - vector_typedWritable references; - - vector_ushort::const_iterator pi; - for (pi = pointers.begin(); pi != pointers.end() && is_complete; ++pi) { - int object_id = (*pi); - - if (object_id == 0) { - // A NULL pointer is a NULL pointer. - references.push_back((TypedWritable *)NULL); - - } else { - // See if we have the pointer available now. - CreatedObjs::const_iterator oi = _created_objs.find(object_id); - if (oi == _created_objs.end()) { - // No, too bad. - is_complete = false; + // Walk through all the objects that still have outstanding pointers. + Requests::iterator ri; + ri = _deferred_pointers.begin(); + while (ri != _deferred_pointers.end()) { + int object_id = (*ri).first; + const vector_int &children = (*ri).second; + + CreatedObjs::iterator ci = _created_objs.find(object_id); + nassertr(ci != _created_objs.end(), false); + CreatedObj &created_obj = (*ci).second; + + TypedWritable *object_ptr = created_obj._ptr; + + // Now make sure we have all of the pointers this object is + // waiting for. If any of the pointers has not yet been read + // in, we can't resolve this object--we can't do anything for a + // given object until we have *all* outstanding pointers for + // that object. + bool is_complete = true; + vector_typedWritable references; + + vector_int::const_iterator pi; + for (pi = children.begin(); pi != children.end() && is_complete; ++pi) { + int child_id = (*pi); + + if (child_id == 0) { + // A NULL pointer is a NULL pointer. + references.push_back((TypedWritable *)NULL); + } else { - // Yes, it's ready. - references.push_back((*oi).second); + // See if we have the pointer available now. + CreatedObjs::const_iterator oi = _created_objs.find(child_id); + if (oi == _created_objs.end()) { + // No, too bad. + is_complete = false; + + } else { + const CreatedObj &child_obj = (*oi).second; + if (child_obj._change_this != NULL) { + // It's been created, but the pointer might still change. + is_complete = false; + + } else { + // Yes, it's ready. + references.push_back(child_obj._ptr); + } + } } } + + if (is_complete) { + // Okay, here's the complete list of pointers for you! + int num_completed = object_ptr->complete_pointers(&references[0], this); + if (num_completed != (int)references.size()) { + bam_cat.warning() + << object_ptr->get_type() << " completed " << num_completed + << " of " << references.size() << " pointers.\n"; + } + + // Now remove this object from the list of things that need + // completion. We have to be a bit careful when deleting things + // from the STL container while we are traversing it. + Requests::iterator old = ri; + ++ri; + _deferred_pointers.erase(old); + + // Does the pointer need to change? + if (created_obj._change_this != NULL) { + created_obj._ptr = created_obj._change_this(object_ptr, this); + created_obj._change_this = NULL; + } + any_completed_this_pass = true; + + } else { + // Couldn't complete this object yet; it'll wait for next time. + ++ri; + all_completed = false; + } } - - if (is_complete) { - // Okay, here's the complete list of pointers for you! - whom->complete_pointers(references, this); - - // Now remove this object from the list of things that need - // completion. We have to be a bit careful when deleting things - // from the STL container while we are traversing it. - Requests::iterator old = ri; - ++ri; - _deferred_pointers.erase(old); - - } else { - // Couldn't complete this object yet; it'll wait for next time. - bam_cat.warning() - << "Unable to complete " << whom->get_type() << "\n"; - ++ri; - all_completed = false; - } - } + } while (!all_completed && any_completed_this_pass); if (all_completed) { finalize(); + } else { + // Report all the uncompleted objects for no good reason. This + // will probably have to come out later when we have cases in + // which some objects might legitimately be uncompleted after + // calling resolve(), but for now we expect resolve() to always + // succeed. + Requests::const_iterator ri; + for (ri = _deferred_pointers.begin(); + ri != _deferred_pointers.end(); + ++ri) { + int object_id = (*ri).first; + CreatedObjs::iterator ci = _created_objs.find(object_id); + nassertr(ci != _created_objs.end(), false); + CreatedObj &created_obj = (*ci).second; + TypedWritable *object_ptr = created_obj._ptr; + + bam_cat.warning() + << "Unable to complete " << object_ptr->get_type() << "\n"; + } } return all_completed; @@ -381,9 +436,26 @@ read_handle(DatagramIterator &scan) { //////////////////////////////////////////////////////////////////// void BamReader:: read_pointer(DatagramIterator &scan, TypedWritable *for_whom) { + nassertv(_now_creating != _created_objs.end()); + int requestor_id = (*_now_creating).first; + +#ifndef NDEBUG + // A bit of sanity checking here: we look up the object ID, and + // assign the "this" pointer into the record if it's not there + // already. Then we can verify the "this" pointer later. + CreatedObj &created_obj = (*_now_creating).second; + if (created_obj._ptr == (TypedWritable *)NULL) { + created_obj._ptr = for_whom; + } else { + // We've previously assigned this pointer, and we should have + // assigned it to the same this pointer we have now. + nassertv(created_obj._ptr == for_whom); + } +#endif // NDEBUG + // Read the object ID, and associate it with the requesting object. int object_id = scan.get_uint16(); - _deferred_pointers[for_whom].push_back(object_id); + _deferred_pointers[requestor_id].push_back(object_id); // If the object ID is zero (which indicates a NULL pointer), we // don't have to do anything else. @@ -447,6 +519,44 @@ register_finalize(TypedWritable *whom) { _finalize_list.insert(whom); } +//////////////////////////////////////////////////////////////////// +// Function: BamReader::register_change_this +// Access: Public +// Description: Called by an object reading itself from the bam file +// to indicate that the object pointer that will be +// returned is temporary, and will eventually need to be +// replaced with another pointer. +// +// The supplied function pointer will later be called on +// the object, immediately after complete_pointers() is +// called; it should return the new and final pointer. +// +// We use a static function pointer instead of a virtual +// function (as in finalize()), to allow the function to +// destruct the old pointer if necessary. (It is +// invalid to destruct the this pointer within a virtual +// function.) +//////////////////////////////////////////////////////////////////// +void BamReader:: +register_change_this(ChangeThisFunc func, TypedWritable *object) { + nassertv(_now_creating != _created_objs.end()); + CreatedObj &created_obj = (*_now_creating).second; + +#ifndef NDEBUG + // Sanity check the pointer--it should always be the same pointer + // after we set it the first time. + if (created_obj._ptr == (TypedWritable *)NULL) { + created_obj._ptr = object; + } else { + // We've previously assigned this pointer, and we should have + // assigned it to the same this pointer we have now. + nassertv(created_obj._ptr == object); + } +#endif // NDEBUG + + created_obj._change_this = func; +} + //////////////////////////////////////////////////////////////////// // Function: BamReader::finalize_now // Access: Public @@ -597,16 +707,43 @@ p_read_object() { // First, we must add an entry into the map for this object ID, so // that in case this function is called recursively during the // object's factory constructor, we will have some definition for - // the object. It doesn't matter yet what the pointer is. + // the object. For now, we give it a NULL pointer. + CreatedObj new_created_obj; + new_created_obj._ptr = NULL; + new_created_obj._change_this = NULL; CreatedObjs::iterator oi = - _created_objs.insert(CreatedObjs::value_type(object_id, NULL)).first; + _created_objs.insert(CreatedObjs::value_type(object_id, new_created_obj)).first; + CreatedObj &created_obj = (*oi).second; - // Now we can call the factory to create the object. + // Now we can call the factory to create the object. Update + // _now_creating during this call so if this function calls + // read_pointer() or register_change_this() we'll match it up + // properly. This might recursively call back into this + // p_read_object(), so be sure to save and restore the original + // value of _now_creating. + CreatedObjs::iterator was_creating = _now_creating; + _now_creating = oi; TypedWritable *object = _factory->make_instance_more_general(type, fparams); + _now_creating = was_creating; // And now we can store the new object pointer in the map. - (*oi).second = object; + nassertr(created_obj._ptr == object || created_obj._ptr == NULL, object_id); + created_obj._ptr = object; + + if (created_obj._change_this != NULL) { + // If the pointer is scheduled to change after + // complete_pointers(), but we have no entry in + // _deferred_pointers for this object (and hence no plan to call + // complete_pointers()), then just change the pointer + // immediately. + Requests::const_iterator ri = _deferred_pointers.find(object_id); + if (ri == _deferred_pointers.end()) { + object = created_obj._change_this(object, this); + created_obj._ptr = object; + created_obj._change_this = NULL; + } + } //Just some sanity checks if (object == (TypedWritable *)NULL) { diff --git a/panda/src/putil/bamReader.h b/panda/src/putil/bamReader.h index cb1241fbca..2db1bf292d 100644 --- a/panda/src/putil/bamReader.h +++ b/panda/src/putil/bamReader.h @@ -27,7 +27,7 @@ #include "datagramIterator.h" #include "bamReaderParam.h" #include "factory.h" -#include "vector_ushort.h" +#include "vector_int.h" #include "pset.h" #include "dcast.h" @@ -114,6 +114,9 @@ public: void register_finalize(TypedWritable *whom); + typedef TypedWritable *(*ChangeThisFunc)(TypedWritable *object, BamReader *manager); + void register_change_this(ChangeThisFunc func, TypedWritable *whom); + void finalize_now(TypedWritable *whom); void *get_pta(DatagramIterator &scan); @@ -143,13 +146,23 @@ private: // This maps the object ID numbers encountered within the Bam file // to the actual pointers of the corresponding generated objects. - typedef pmap CreatedObjs; + class CreatedObj { + public: + TypedWritable *_ptr; + ChangeThisFunc _change_this; + }; + typedef pmap CreatedObjs; CreatedObjs _created_objs; + // This is the iterator into the above map for the object we are + // currently reading in p_read_object(). It is carefully maintained + // during recursion. We need this so we can associate + // read_pointer() calls with the proper objects. + CreatedObjs::iterator _now_creating; // This records all the objects that still need their pointers // completed, along with the object ID's of the pointers they need, // in the order in which read_pointer() was called. - typedef pmap Requests; + typedef pmap Requests; Requests _deferred_pointers; // This is the number of extra objects that must still be read (and diff --git a/panda/src/putil/bamWriter.cxx b/panda/src/putil/bamWriter.cxx index dfad48bd86..29235ee69f 100644 --- a/panda/src/putil/bamWriter.cxx +++ b/panda/src/putil/bamWriter.cxx @@ -97,7 +97,7 @@ init() { // false otherwise. //////////////////////////////////////////////////////////////////// bool BamWriter:: -write_object(TypedWritable *object) { +write_object(const TypedWritable *object) { nassertr(_object_queue.empty(), false); int object_id = enqueue_object(object); @@ -132,7 +132,14 @@ write_object(TypedWritable *object) { write_handle(dg, type); dg.add_uint16(object_id); - object->write_datagram(this, dg); + // We cast the const pointer to non-const so that we may call + // write_datagram() on it. Really, write_datagram() should be a + // const method anyway, but there may be times when a class + // object wants to update some transparent cache value during + // writing or something like that, so it's more convenient to + // cheat and define it as a non-const method. + ((TypedWritable *)object)->write_datagram(this, dg); + (*si).second._written = true; } else { @@ -170,10 +177,10 @@ write_object(TypedWritable *object) { // automatically be written. //////////////////////////////////////////////////////////////////// void BamWriter:: -write_pointer(Datagram &packet, TypedWritable *object) { +write_pointer(Datagram &packet, const TypedWritable *object) { // If the pointer is NULL, we always simply write a zero for an // object ID and leave it at that. - if (object == (TypedWritable *)NULL) { + if (object == (const TypedWritable *)NULL) { packet.add_uint16(0); } else { @@ -211,8 +218,8 @@ write_pointer(Datagram &packet, TypedWritable *object) { // the work that must be done to write a PTA. //////////////////////////////////////////////////////////////////// bool BamWriter:: -register_pta(Datagram &packet, void *ptr) { - if (ptr == (void *)NULL) { +register_pta(Datagram &packet, const void *ptr) { + if (ptr == (const void *)NULL) { // A zero for the PTA ID indicates a NULL pointer. This is a // special case. packet.add_uint16(0); @@ -313,7 +320,7 @@ write_handle(Datagram &packet, TypeHandle type) { // an error. //////////////////////////////////////////////////////////////////// int BamWriter:: -enqueue_object(TypedWritable *object) { +enqueue_object(const TypedWritable *object) { Datagram dg; nassertr(object != TypedWritable::Null, 0); diff --git a/panda/src/putil/bamWriter.h b/panda/src/putil/bamWriter.h index a00ac8e988..b5e0bcbb32 100644 --- a/panda/src/putil/bamWriter.h +++ b/panda/src/putil/bamWriter.h @@ -77,17 +77,17 @@ public: // The primary interface for a caller. bool init(); - bool write_object(TypedWritable *obj); + bool write_object(const TypedWritable *obj); public: // Functions to support classes that write themselves to the Bam. - void write_pointer(Datagram &packet, TypedWritable *dest); - bool register_pta(Datagram &packet, void *ptr); + void write_pointer(Datagram &packet, const TypedWritable *dest); + bool register_pta(Datagram &packet, const void *ptr); void write_handle(Datagram &packet, TypeHandle type); private: - int enqueue_object(TypedWritable *object); + int enqueue_object(const TypedWritable *object); // This is the set of all TypeHandles already written. @@ -103,7 +103,7 @@ private: StoreState(int object_id) : _object_id(object_id), _written(false) {} }; - typedef pmap StateMap; + typedef pmap StateMap; StateMap _state_map; // This is the next object ID that will be assigned to a new object. @@ -111,12 +111,12 @@ private: // This is the queue of objects that need to be written when the // current object is finished. - typedef pdeque ObjectQueue; + typedef pdeque ObjectQueue; ObjectQueue _object_queue; // These are used by register_pta() to unify multiple references to // the same PointerToArray. - typedef pmap PTAMap; + typedef pmap PTAMap; PTAMap _pta_map; int _next_pta_id; diff --git a/panda/src/putil/test_bam.cxx b/panda/src/putil/test_bam.cxx index a2d7c5543c..c76cc4cc79 100644 --- a/panda/src/putil/test_bam.cxx +++ b/panda/src/putil/test_bam.cxx @@ -82,7 +82,7 @@ fillin(Person* me, DatagramIterator& scan, BamReader* manager) } int Person:: -complete_pointers(vector_typedWritable& p_list, BamReader *) +complete_pointers(TypedWritable **p_list, BamReader *) { _bro = (p_list[0] == TypedWritable::Null) ? (Person*)NULL : DCAST(Person, p_list[0]); _sis = (p_list[1] == TypedWritable::Null) ? (Person*)NULL : DCAST(Person, p_list[1]); @@ -127,7 +127,7 @@ fillin(Parent* me, DatagramIterator& scan, BamReader* manager) } int Parent:: -complete_pointers(vector_typedWritable& p_list, BamReader *manager) +complete_pointers(TypedWritable *p_list, BamReader *manager) { int start = Person::complete_pointers(p_list, manager); _son = (p_list[start] == TypedWritable::Null) ? (Child*)NULL : DCAST(Child, p_list[2]); @@ -187,7 +187,7 @@ fillin(Child* me, DatagramIterator& scan, BamReader* manager) } int Child:: -complete_pointers(vector_typedWritable& p_list, BamReader *manager) +complete_pointers(TypedWritable ** p_list, BamReader *manager) { int start = Person::complete_pointers(p_list, manager); _dad = (p_list[start] == TypedWritable::Null) ? (Parent*)NULL : DCAST(Parent, p_list[2]); diff --git a/panda/src/putil/test_bam.h b/panda/src/putil/test_bam.h index 422a143a6d..8cae28f1c1 100644 --- a/panda/src/putil/test_bam.h +++ b/panda/src/putil/test_bam.h @@ -38,7 +38,7 @@ public: void write_datagram(BamWriter*, Datagram&); static TypedWritable *make_person(const FactoryParams ¶ms); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); protected: void fillin(Person*,DatagramIterator&,BamReader*); @@ -93,7 +93,7 @@ public: void write_datagram(BamWriter*, Datagram&); static TypedWritable *make_parent(const FactoryParams ¶ms); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable *p_list, BamReader *manager); protected: void fillin(Parent*,DatagramIterator&,BamReader*); @@ -139,7 +139,7 @@ public: void write_datagram(BamWriter*, Datagram&); static TypedWritable *make_child(const FactoryParams ¶ms); - virtual int complete_pointers(vector_typedWritable &p_list, + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); protected: void fillin(Child*,DatagramIterator&,BamReader*); diff --git a/panda/src/putil/typedWritable.cxx b/panda/src/putil/typedWritable.cxx index eb4c96824c..c0ca3c2471 100644 --- a/panda/src/putil/typedWritable.cxx +++ b/panda/src/putil/typedWritable.cxx @@ -26,20 +26,72 @@ TypedWritable* const TypedWritable::Null = (TypedWritable*)0L; // Access: Public, Virtual // Description: //////////////////////////////////////////////////////////////////// -TypedWritable::~TypedWritable() -{ +TypedWritable::~TypedWritable() { } +//////////////////////////////////////////////////////////////////// +// Function: TypedWritable::write_datagram +// Access: Public, Virtual +// Description: Writes the contents of this object to the datagram +// for shipping out to a Bam file. +//////////////////////////////////////////////////////////////////// +void TypedWritable:: +write_datagram(BamWriter *, Datagram &) { +} //////////////////////////////////////////////////////////////////// // Function: TypedWritable::complete_pointers // Access: Public, Virtual -// Description: Takes in a vector of pointers to TypedWritable -// objects that correspond to all the requests for -// pointers that this object made to BamReader. +// Description: Receives an array of pointers, one for each time +// manager->read_pointer() was called in fillin(). +// Returns the number of pointers processed. +// +// This is the callback function that is made by the +// BamReader at some later point, after all of the +// required pointers have been filled in. It is +// necessary because there might be forward references +// in a bam file; when we call read_pointer() in +// fillin(), the object may not have been read from the +// file yet, so we do not have a pointer available at +// that time. Thus, instead of returning a pointer, +// read_pointer() simply reserves a later callback. +// This function provides that callback. The calling +// object is responsible for keeping track of the number +// of times it called read_pointer() and extracting the +// same number of pointers out of the supplied vector, +// and storing them appropriately within the object. //////////////////////////////////////////////////////////////////// int TypedWritable:: -complete_pointers(vector_typedWritable &, BamReader*) -{ +complete_pointers(TypedWritable **, BamReader *) { return 0; } + + +//////////////////////////////////////////////////////////////////// +// Function: TypedWritable::finalize +// Access: Public, Virtual +// Description: Called by the BamReader to perform any final actions +// needed for setting up the object after all objects +// have been read and all pointers have been completed. +//////////////////////////////////////////////////////////////////// +void TypedWritable:: +finalize() { +} + + +//////////////////////////////////////////////////////////////////// +// Function: TypedWritable::fillin +// Access: Protected +// Description: This internal function is intended to be called by +// each class's make_from_bam() method to read in all of +// the relevant data from the BamFile for the new +// object. +// +// It is defined at the TypedWritable level so that +// derived classes may call up the inheritance chain +// from their own fillin() method. +//////////////////////////////////////////////////////////////////// +void TypedWritable:: +fillin(DatagramIterator &, BamReader *) { +} + diff --git a/panda/src/putil/typedWritable.h b/panda/src/putil/typedWritable.h index 2718c9398d..00e9d93b72 100644 --- a/panda/src/putil/typedWritable.h +++ b/panda/src/putil/typedWritable.h @@ -27,20 +27,11 @@ class BamReader; //////////////////////////////////////////////////////////////////// // Class : TypedWritable -// Description : Convience class to not have to derive from TypedObject -// and writable all the time -// -// Important : Every class derived from TypedWritable that is -// not an abstract class, MUST define a factory method -// for creating and object of that type. This method -// must be static. This method must be of the form -// static make_(const FactoryParams &) -// Also, in the config file for each package, make sure -// to add in code to the ConfigureFN to register the -// creation function with BamReader's factory. +// Description : Base class for objects that can be written to and +// read from Bam files. //////////////////////////////////////////////////////////////////// -class EXPCL_PANDA TypedWritable : public TypedObject, public Writable { +class EXPCL_PANDA TypedWritable : public TypedObject { public: static TypedWritable* const Null; @@ -50,30 +41,14 @@ public: virtual ~TypedWritable(); - //The essential virtual function interface to define - //how any writable object, writes itself to a datagram - virtual void write_datagram(BamWriter *, Datagram &) = 0; + virtual void write_datagram(BamWriter *, Datagram &); - //This function is the interface through which BamReader is - //able to pass the completed object references into each - //object that requested them. - //In other words, if an object (when it is creating itself - //from a datagram) requests BamReader to generate an object - //that this object points to, this is the function that is - //eventually called by BamReader to complete those references. - //Return the number of pointers read. This is useful for when - //a parent reads in a variable number of pointers, so the child - //knows where to start reading from. - virtual int complete_pointers(vector_typedWritable &p_list, - BamReader *manager); + virtual int complete_pointers(TypedWritable **p_list, BamReader *manager); + virtual void finalize(); protected: - //This interface function is written here, as a suggestion - //for a function to write in any class that will have children - //that are also TypedWritable. To encourage code re-use - - //virtual void fillin(TypedWritable*, DatagramIterator&, BamReader *); + void fillin(DatagramIterator &scan, BamReader *manager); PUBLISHED: static TypeHandle get_class_type() { @@ -82,6 +57,9 @@ PUBLISHED: public: static void init_type() { + // We no longer derive from Writable, but we continue to record + // that derivation for now, just to keep bam files consistent + // until we move to bam version 4.0. TypedObject::init_type(); Writable::init_type(); register_type(_type_handle, "TypedWritable", diff --git a/panda/src/putil/writable.h b/panda/src/putil/writable.h index 75d57aa2fb..4575526924 100644 --- a/panda/src/putil/writable.h +++ b/panda/src/putil/writable.h @@ -58,7 +58,7 @@ public: //Return the number of pointers read. This is useful for when //a parent reads in a variable number of pointers, so the child //knows where to start reading from. - //virtual int complete_pointers(vector_typedWritable &p_list, + //virtual int complete_pointers(TypedWritable **p_list, // BamReader *manager) {} diff --git a/panda/src/sgattrib/materialTransition.cxx b/panda/src/sgattrib/materialTransition.cxx index d8e2bc48d3..8a098c65be 100644 --- a/panda/src/sgattrib/materialTransition.cxx +++ b/panda/src/sgattrib/materialTransition.cxx @@ -145,7 +145,7 @@ write_datagram(BamWriter *manager, Datagram &me) { // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int MaterialTransition:: -complete_pointers(vector_typedWritable &p_list, BamReader *) { +complete_pointers(TypedWritable **p_list, BamReader *) { if (p_list[0] == TypedWritable::Null) { if (sgattrib_cat.is_debug()) { sgattrib_cat->debug() diff --git a/panda/src/sgattrib/materialTransition.h b/panda/src/sgattrib/materialTransition.h index 381c4fb4e6..cc74e8f82a 100644 --- a/panda/src/sgattrib/materialTransition.h +++ b/panda/src/sgattrib/materialTransition.h @@ -58,7 +58,7 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); protected: diff --git a/panda/src/sgattrib/textureTransition.cxx b/panda/src/sgattrib/textureTransition.cxx index b8d3caaab2..7f92f3b5bc 100644 --- a/panda/src/sgattrib/textureTransition.cxx +++ b/panda/src/sgattrib/textureTransition.cxx @@ -146,7 +146,7 @@ write_datagram(BamWriter *manager, Datagram &me) { // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int TextureTransition:: -complete_pointers(vector_typedWritable &p_list, BamReader *) { +complete_pointers(TypedWritable **p_list, BamReader *) { if (p_list[0] == TypedWritable::Null) { if (sgattrib_cat.is_debug()) { sgattrib_cat->debug() diff --git a/panda/src/sgattrib/textureTransition.h b/panda/src/sgattrib/textureTransition.h index 9e23a4cfb2..26a53c163e 100644 --- a/panda/src/sgattrib/textureTransition.h +++ b/panda/src/sgattrib/textureTransition.h @@ -70,7 +70,7 @@ private: public: static void register_with_read_factory(); virtual void write_datagram(BamWriter *manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); protected: diff --git a/panda/src/sgraph/geomNode.cxx b/panda/src/sgraph/geomNode.cxx index e1a3f3730d..2519f81a85 100644 --- a/panda/src/sgraph/geomNode.cxx +++ b/panda/src/sgraph/geomNode.cxx @@ -464,7 +464,7 @@ write_datagram(BamWriter *manager, Datagram &me) // pointers that this object made to BamReader. //////////////////////////////////////////////////////////////////// int GeomNode:: -complete_pointers(vector_typedWritable &p_list, BamReader* manager) +complete_pointers(TypedWritable **p_list, BamReader* manager) { int start = NamedNode::complete_pointers(p_list, manager); for(int i = start; i < _num_geoms+start; i++) diff --git a/panda/src/sgraph/geomNode.h b/panda/src/sgraph/geomNode.h index 4eb7f19ad3..90ae9b0956 100644 --- a/panda/src/sgraph/geomNode.h +++ b/panda/src/sgraph/geomNode.h @@ -88,7 +88,7 @@ private: public: static void register_with_read_factory(void); virtual void write_datagram(BamWriter* manager, Datagram &me); - virtual int complete_pointers(vector_typedWritable &plist, + virtual int complete_pointers(TypedWritable **plist, BamReader *manager); static TypedWritable *make_GeomNode(const FactoryParams ¶ms); diff --git a/panda/src/testbed/Sources.pp b/panda/src/testbed/Sources.pp index f2bb058a75..b558e9f235 100644 --- a/panda/src/testbed/Sources.pp +++ b/panda/src/testbed/Sources.pp @@ -26,14 +26,12 @@ #end bin_target -#begin test_bin_target +#begin bin_target #define TARGET pview #define SOURCES \ pview.cxx - - #define LOCAL_LIBS egg2pg pgraph $[LOCAL_LIBS] -#end test_bin_target +#end bin_target #begin test_bin_target #define TARGET open_window diff --git a/panda/src/testbed/pview.cxx b/panda/src/testbed/pview.cxx index 59192e54c3..eeea89e9d9 100644 --- a/panda/src/testbed/pview.cxx +++ b/panda/src/testbed/pview.cxx @@ -32,10 +32,8 @@ #include "geomTri.h" #include "texture.h" #include "texturePool.h" - -// To load egg files directly. -#include "qpload_egg_file.h" -#include "eggData.h" +#include "dSearchPath.h" +#include "loader.h" // These are in support of legacy data graph operations. #include "namedNode.h" @@ -199,13 +197,20 @@ get_models(PandaNode *parent, int argc, char *argv[]) { make_default_geometry(parent); } else { + Loader loader; + DSearchPath local_path("."); for (int i = 1; i < argc; i++) { Filename filename = argv[i]; cerr << "Loading " << filename << "\n"; - EggData::resolve_egg_filename(filename); - PT(PandaNode) node = qpload_egg_file(filename); + + // First, we always try to resolve a filename from the current + // directory. This means a local filename will always be found + // before the model path is searched. + filename.resolve_filename(local_path); + + PT(PandaNode) node = loader.qpload_sync(filename); if (node == (PandaNode *)NULL) { cerr << "Unable to load " << filename << "\n";