/** * PANDA 3D SOFTWARE * Copyright (c) Carnegie Mellon University. All rights reserved. * * All use of this software is subject to the terms of the revised BSD * license. You should have received a copy of this license along * with this source code in a file named "LICENSE." * * @file bamWriter.h * @author jason * @date 2000-06-08 */ #ifndef __BAM_WRITER_ #define __BAM_WRITER_ #include "pandabase.h" #include "pnotify.h" #include "bamEnums.h" #include "typedWritable.h" #include "datagramSink.h" #include "pdeque.h" #include "pset.h" #include "pmap.h" #include "vector_int.h" #include "pipelineCyclerBase.h" // A handy macro for writing PointerToArrays. #define WRITE_PTA(Manager, dest, Write_func, array) \ if (!Manager->register_pta(dest, array.p())) \ { \ Write_func(Manager, dest, array); \ } \ /** * This is the fundamental interface for writing binary objects to a Bam file, * to be extracted later by a BamReader. * * A Bam file can be thought of as a linear collection of objects. Each * object is an instance of a class that inherits, directly or indirectly, * from TypedWritable. The objects may include pointers to other objects; the * BamWriter automatically manages these (with help from code within each * class) and writes all referenced objects to the file in such a way that the * pointers may be correctly restored later. * * This is the abstract interface and does not specifically deal with disk * files, but rather with a DatagramSink of some kind, which simply accepts a * linear stream of Datagrams. It is probably written to a disk file, but it * might conceivably be streamed directly to a network or some such nonsense. * * Bam files are most often used to store scene graphs or subgraphs, and by * convention they are given filenames ending in the extension ".bam" when * they are used for this purpose. However, a Bam file may store any * arbitrary list of TypedWritable objects; in this more general usage, they * are given filenames ending in ".boo" to differentiate them from the more * common scene graph files. * * See also BamFile, which defines a higher-level interface to read and write * Bam files on disk. */ class EXPCL_PANDA_PUTIL BamWriter : public BamEnums { PUBLISHED: explicit BamWriter(DatagramSink *target = nullptr); ~BamWriter(); void set_target(DatagramSink *target); INLINE DatagramSink *get_target(); bool init(); INLINE const Filename &get_filename() const; bool write_object(const TypedWritable *obj); bool has_object(const TypedWritable *obj) const; void flush(); INLINE int get_file_major_ver() const; INLINE int get_file_minor_ver() const; INLINE void set_file_minor_ver(int minor_ver); INLINE BamEndian get_file_endian() const; INLINE bool get_file_stdfloat_double() const; INLINE BamTextureMode get_file_texture_mode() const; INLINE void set_file_texture_mode(BamTextureMode file_texture_mode); INLINE TypedWritable *get_root_node() const; INLINE void set_root_node(TypedWritable *root_node); PUBLISHED: MAKE_PROPERTY(target, get_target, set_target); MAKE_PROPERTY(filename, get_filename); MAKE_PROPERTY(file_endian, get_file_endian); MAKE_PROPERTY(file_stdfloat_double, get_file_stdfloat_double); MAKE_PROPERTY(file_texture_mode, get_file_texture_mode); MAKE_PROPERTY(root_node, get_root_node, set_root_node); public: // Functions to support classes that write themselves to the Bam. void consider_update(const TypedWritable *obj); void write_pointer(Datagram &packet, const TypedWritable *dest); void write_file_data(SubfileInfo &result, const Filename &filename); void write_file_data(SubfileInfo &result, const SubfileInfo &source); void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler); void write_cdata(Datagram &packet, const PipelineCyclerBase &cycler, void *extra_data); bool register_pta(Datagram &packet, const void *ptr); void write_handle(Datagram &packet, TypeHandle type); static std::string get_obsolete_type_name(TypeHandle type, int major, int minor); static void record_obsolete_type_name(TypeHandle type, std::string name, int before_major, int before_minor); private: void object_destructs(TypedWritable *object); void write_object_id(Datagram &dg, int object_id); void write_pta_id(Datagram &dg, int pta_id); int enqueue_object(const TypedWritable *object); bool flush_queue(); int _file_major, _file_minor; BamEndian _file_endian; bool _file_stdfloat_double; BamTextureMode _file_texture_mode; // Stores the PandaNode representing the root of the node hierarchy we are // currently writing, if any, for the purpose of writing NodePaths. This is // a TypedWritable since PandaNode is defined in pgraph. TypedWritable *_root_node; // This is the set of all TypeHandles already written. pset _types_written; // This keeps track of all of the objects we have written out already (or // are about to write out), and associates a unique object ID number to each // one. class StoreState { public: int _object_id; UpdateSeq _written_seq; UpdateSeq _modified; const ReferenceCount *_refcount; StoreState(int object_id) : _object_id(object_id), _refcount(nullptr) {} }; typedef phash_map StateMap; StateMap _state_map; // This seq number is incremented each time we write a new object using the // top-level write_object() call. It indicates the current sequence number // we are writing, which is updated in the StoreState, above, and used to // keep track of which objects may need to be checked for internal updates. UpdateSeq _writing_seq; // This is initialized to BOC_push in write_object(), then cleared to // BOC_adjunct as each object is written, so that only the first object gets // written with BOC_push. BamObjectCode _next_boc; // This is the next object ID that will be assigned to a new object. int _next_object_id; bool _long_object_id; // This is the queue of objects that need to be written when the current // object is finished. typedef pdeque ObjectQueue; ObjectQueue _object_queue; // This is the set of object_id's that we won't be using any more; we'll // encode this set into the bam stream so the BamReader will be able to // clean up its internal structures. typedef vector_int FreedObjectIds; FreedObjectIds _freed_object_ids; // These are used by register_pta() to unify multiple references to the same // PointerToArray. typedef phash_map PTAMap; PTAMap _pta_map; int _next_pta_id; bool _long_pta_id; // The destination to write all the output to. DatagramSink *_target; bool _needs_init; friend class TypedWritable; }; #include "bamWriter.I" #endif