196 lines
6.9 KiB
C++
196 lines
6.9 KiB
C++
/**
|
|
* 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<int, int_hash> _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<const TypedWritable *, StoreState, pointer_hash> 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<const TypedWritable *> 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<const void *, int, pointer_hash> 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
|