392 lines
13 KiB
C++
392 lines
13 KiB
C++
// Filename: internalName.cxx
|
|
// Created by: masad (15Jul04)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
|
|
//
|
|
// All use of this software is subject to the terms of the Panda 3d
|
|
// Software license. You should have received a copy of this license
|
|
// along with this source code; you will also find a current copy of
|
|
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
|
|
//
|
|
// To contact the maintainers of this program write to
|
|
// panda3d-general@lists.sourceforge.net .
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pandabase.h"
|
|
#include "internalName.h"
|
|
#include "datagram.h"
|
|
#include "datagramIterator.h"
|
|
#include "bamReader.h"
|
|
#include "preparedGraphicsObjects.h"
|
|
|
|
PT(InternalName) InternalName::_root;
|
|
PT(InternalName) InternalName::_error;
|
|
PT(InternalName) InternalName::_default;
|
|
PT(InternalName) InternalName::_vertex;
|
|
PT(InternalName) InternalName::_normal;
|
|
PT(InternalName) InternalName::_tangent;
|
|
PT(InternalName) InternalName::_binormal;
|
|
PT(InternalName) InternalName::_texcoord;
|
|
PT(InternalName) InternalName::_color;
|
|
PT(InternalName) InternalName::_rotate;
|
|
PT(InternalName) InternalName::_size;
|
|
PT(InternalName) InternalName::_aspect_ratio;
|
|
PT(InternalName) InternalName::_transform_blend;
|
|
PT(InternalName) InternalName::_transform_weight;
|
|
PT(InternalName) InternalName::_transform_index;
|
|
PT(InternalName) InternalName::_index;
|
|
PT(InternalName) InternalName::_world;
|
|
PT(InternalName) InternalName::_camera;
|
|
PT(InternalName) InternalName::_model;
|
|
PT(InternalName) InternalName::_view;
|
|
|
|
TypeHandle InternalName::_type_handle;
|
|
TypeHandle InternalName::_texcoord_type_handle;
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::Constructor
|
|
// Access: Private
|
|
// Description: Use make() to make a new InternalName instance.
|
|
////////////////////////////////////////////////////////////////////
|
|
InternalName::
|
|
InternalName(InternalName *parent, const string &basename) :
|
|
_parent(parent),
|
|
_basename(basename)
|
|
{
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::Destructor
|
|
// Access: Published, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
InternalName::
|
|
~InternalName() {
|
|
#ifndef NDEBUG
|
|
if (_parent != (const InternalName *)NULL) {
|
|
// unref() should have removed us from our parent's table already.
|
|
MutexHolder holder(_parent->_name_table_lock);
|
|
NameTable::iterator ni = _parent->_name_table.find(_basename);
|
|
nassertv(ni == _parent->_name_table.end());
|
|
}
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::unref
|
|
// Access: Published
|
|
// Description: This method overrides ReferenceCount::unref() to
|
|
// clear the pointer from its parent's table when
|
|
// its reference count goes to zero.
|
|
////////////////////////////////////////////////////////////////////
|
|
bool InternalName::
|
|
unref() const {
|
|
if (_parent == (const InternalName *)NULL) {
|
|
// No parent; no problem. This is the root InternalName.
|
|
// Actually, this probably shouldn't be destructing, but I guess
|
|
// it might at application shutdown.
|
|
return TypedWritableReferenceCount::unref();
|
|
}
|
|
|
|
MutexHolder holder(_parent->_name_table_lock);
|
|
|
|
if (ReferenceCount::unref()) {
|
|
return true;
|
|
}
|
|
|
|
// The reference count has just reached zero.
|
|
NameTable::iterator ni = _parent->_name_table.find(_basename);
|
|
nassertr(ni != _parent->_name_table.end(), false);
|
|
_parent->_name_table.erase(ni);
|
|
|
|
return false;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::append
|
|
// Access: Published
|
|
// Description: Constructs a new InternalName based on this name,
|
|
// with the indicated string following it. This is a
|
|
// cheaper way to construct a hierarchical name than
|
|
// InternalName::make(parent->get_name() + ".basename").
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(InternalName) InternalName::
|
|
append(const string &name) {
|
|
test_ref_count_integrity();
|
|
|
|
if (name.empty()) {
|
|
return this;
|
|
}
|
|
|
|
size_t dot = name.rfind('.');
|
|
if (dot != string::npos) {
|
|
return append(name.substr(0, dot))->append(name.substr(dot + 1));
|
|
}
|
|
|
|
MutexHolder holder(_name_table_lock);
|
|
|
|
NameTable::iterator ni = _name_table.find(name);
|
|
if (ni != _name_table.end()) {
|
|
return (*ni).second;
|
|
}
|
|
|
|
InternalName *internal_name = new InternalName(this, name);
|
|
_name_table[name] = internal_name;
|
|
return internal_name;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::get_name
|
|
// Access: Published
|
|
// Description: Returns the complete name represented by the
|
|
// InternalName and all of its parents.
|
|
////////////////////////////////////////////////////////////////////
|
|
string InternalName::
|
|
get_name() const {
|
|
if (_parent == get_root()) {
|
|
return _basename;
|
|
|
|
} else if (_parent == (InternalName *)NULL) {
|
|
return string();
|
|
|
|
} else {
|
|
return _parent->get_name() + "." + _basename;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::find_ancestor
|
|
// Access: Published
|
|
// Description: Returns the index of the ancestor with the indicated
|
|
// basename, or -1 if no ancestor has that basename.
|
|
// Returns 0 if this name has the basename.
|
|
//
|
|
// This index value may be passed to get_ancestor() or
|
|
// get_net_basename() to retrieve more information about
|
|
// the indicated name.
|
|
////////////////////////////////////////////////////////////////////
|
|
int InternalName::
|
|
find_ancestor(const string &basename) const {
|
|
test_ref_count_integrity();
|
|
|
|
if (_basename == basename) {
|
|
return 0;
|
|
|
|
} else if (_parent != (InternalName *)NULL) {
|
|
int index = _parent->find_ancestor(basename);
|
|
if (index >= 0) {
|
|
return index + 1;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::get_ancestor
|
|
// Access: Published
|
|
// Description: Returns the ancestor with the indicated index number.
|
|
// 0 is this name itself, 1 is the name's parent, 2 is
|
|
// the parent's parent, and so on. If there are not
|
|
// enough ancestors, returns the root InternalName.
|
|
////////////////////////////////////////////////////////////////////
|
|
const InternalName *InternalName::
|
|
get_ancestor(int n) const {
|
|
test_ref_count_integrity();
|
|
|
|
if (n == 0) {
|
|
return this;
|
|
|
|
} else if (_parent != (InternalName *)NULL) {
|
|
return _parent->get_ancestor(n - 1);
|
|
|
|
} else {
|
|
return get_root();
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::get_top
|
|
// Access: Published
|
|
// Description: Returns the oldest ancestor in the InternalName's
|
|
// chain, not counting the root. This will be the first
|
|
// name in the string, e.g. "texcoord.foo.bar" will
|
|
// return the InternalName "texcoord".
|
|
////////////////////////////////////////////////////////////////////
|
|
const InternalName *InternalName::
|
|
get_top() const {
|
|
test_ref_count_integrity();
|
|
|
|
if (_parent != (InternalName *)NULL && _parent != get_root()) {
|
|
return _parent->get_top();
|
|
}
|
|
return this;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::get_net_basename
|
|
// Access: Published
|
|
// Description: Returns the basename of this name prefixed by the
|
|
// indicated number of ancestors. 0 is this name's
|
|
// basename, 1 is parent.basename, 2 is
|
|
// grandparent.parent.basename, and so on.
|
|
////////////////////////////////////////////////////////////////////
|
|
string InternalName::
|
|
get_net_basename(int n) const {
|
|
if (n < 0) {
|
|
return "";
|
|
|
|
} else if (n == 0) {
|
|
return _basename;
|
|
|
|
} else if (_parent != (InternalName *)NULL && _parent != get_root()) {
|
|
return _parent->get_net_basename(n - 1) + "." + _basename;
|
|
|
|
} else {
|
|
return _basename;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::output
|
|
// Access: Published
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
void InternalName::
|
|
output(ostream &out) const {
|
|
if (_parent == get_root()) {
|
|
out << _basename;
|
|
|
|
} else if (_parent == (InternalName *)NULL) {
|
|
out << "(root)";
|
|
|
|
} else {
|
|
_parent->output(out);
|
|
out << '.' << _basename;
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::register_with_read_factory
|
|
// Access: Public, Static
|
|
// Description: Factory method to generate a InternalName object
|
|
////////////////////////////////////////////////////////////////////
|
|
void InternalName::
|
|
register_with_read_factory() {
|
|
BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
|
|
BamReader::get_factory()->register_factory(_texcoord_type_handle, make_texcoord_from_bam);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::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 InternalName::
|
|
finalize(BamReader *) {
|
|
// Unref the pointer that we explicitly reffed in make_from_bam().
|
|
unref();
|
|
|
|
// We should never get back to zero after unreffing our own count,
|
|
// because we expect to have been stored in a pointer somewhere. If
|
|
// we do get to zero, it's a memory leak; the way to avoid this is
|
|
// to call unref_delete() above instead of unref(), but this is
|
|
// dangerous to do from within a virtual function.
|
|
nassertv(get_ref_count() != 0);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::make
|
|
// Access: Published, Static
|
|
// Description: Make using a string and an integer. Concatenates
|
|
// the two.
|
|
////////////////////////////////////////////////////////////////////
|
|
PT(InternalName) InternalName::
|
|
make(const string &name, int index) {
|
|
std::ostringstream full;
|
|
full << name << index;
|
|
return make(full.str());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::make_from_bam
|
|
// Access: Protected, Static
|
|
// Description: This function is called by the BamReader's factory
|
|
// when a new object of type InternalName is encountered
|
|
// in the Bam file. It should create the InternalName
|
|
// and extract its information from the file.
|
|
////////////////////////////////////////////////////////////////////
|
|
TypedWritable *InternalName::
|
|
make_from_bam(const FactoryParams ¶ms) {
|
|
// The process of making a InternalName is slightly
|
|
// different than making other Writable objects.
|
|
// That is because all creation of InternalNames should
|
|
// be done through the make() constructor.
|
|
DatagramIterator scan;
|
|
BamReader *manager;
|
|
|
|
parse_params(params, scan, manager);
|
|
|
|
// The name is the only thing written to the data stream.
|
|
string name = scan.get_string();
|
|
|
|
// Make a new InternalName with that name (or get the previous one
|
|
// if there is one already).
|
|
PT(InternalName) me = make(name);
|
|
|
|
// 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.
|
|
me->ref();
|
|
manager->register_finalize(me);
|
|
|
|
return me.p();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::make_texcoord_from_bam
|
|
// Access: Protected, Static
|
|
// Description: This is a temporary method; it exists only to support
|
|
// old bam files (4.11 through 4.17) generated before we
|
|
// renamed this class from TexCoordName to InternalName.
|
|
////////////////////////////////////////////////////////////////////
|
|
TypedWritable *InternalName::
|
|
make_texcoord_from_bam(const FactoryParams ¶ms) {
|
|
DatagramIterator scan;
|
|
BamReader *manager;
|
|
parse_params(params, scan, manager);
|
|
|
|
string name = scan.get_string();
|
|
PT(InternalName) me;
|
|
if (name == "default") {
|
|
me = get_texcoord();
|
|
} else {
|
|
me = get_texcoord_name(name);
|
|
}
|
|
|
|
me->ref();
|
|
manager->register_finalize(me);
|
|
|
|
return me.p();
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: InternalName::write_datagram
|
|
// Access: Public
|
|
// Description: Function to write the important information in
|
|
// the particular object to a Datagram
|
|
////////////////////////////////////////////////////////////////////
|
|
void InternalName::
|
|
write_datagram(BamWriter *manager, Datagram &me) {
|
|
me.add_string(get_name());
|
|
}
|
|
|