mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 10:22:45 -04:00
low-level support for python copy and pickle modules
This commit is contained in:
parent
3e82b3d163
commit
816ddc0387
@ -302,6 +302,30 @@ Filename(const Filename &dirname, const Filename &basename) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Filename::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *Filename::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(s))", this_class, c_str());
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Filename::from_os_specific
|
||||
// Access: Published, Static
|
||||
|
@ -66,6 +66,10 @@ PUBLISHED:
|
||||
Filename(const Filename &dirname, const Filename &basename);
|
||||
INLINE ~Filename();
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
// Static constructors to explicitly create a filename that refers
|
||||
// to a text or binary file. This is in lieu of calling set_text()
|
||||
// or set_binary() or set_type().
|
||||
|
@ -297,6 +297,16 @@ make_wrapper_entry(FunctionIndex function_index) {
|
||||
assert(!iwrapper._parameters.empty());
|
||||
iwrapper._parameters.front()._parameter_flags |=
|
||||
InterrogateFunctionWrapper::PF_is_this;
|
||||
|
||||
if (_parameters.size() >= 2 && _parameters[1]._name == "self" &&
|
||||
TypeManager::is_pointer_to_PyObject(_parameters[1]._remap->get_orig_type())) {
|
||||
// Here's a special case. If the first parameter of a nonstatic
|
||||
// method is a PyObject * called "self", then we will
|
||||
// automatically fill it in from the this pointer, and remove it
|
||||
// from the generated parameter list.
|
||||
_parameters.erase(_parameters.begin() + 1);
|
||||
_flags |= F_explicit_self;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_void_return) {
|
||||
@ -382,6 +392,14 @@ get_call_str(const string &container, const vector_string &pexprs) const {
|
||||
}
|
||||
|
||||
call << "(";
|
||||
if (_flags & F_explicit_self) {
|
||||
// Pass on the PyObject * that we stripped off above.
|
||||
call << "self";
|
||||
if (_first_true_parameter < (int)_parameters.size()) {
|
||||
call << ", ";
|
||||
}
|
||||
}
|
||||
|
||||
int pn = _first_true_parameter;
|
||||
if (pn < (int)_parameters.size()) {
|
||||
_parameters[pn]._remap->pass_parameter(call, get_parameter_expr(pn, pexprs));
|
||||
@ -630,6 +648,23 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
|
||||
// It receives no parameters, and returns an integer.
|
||||
_flags |= F_size;
|
||||
}
|
||||
|
||||
} else if (fname == "make_copy" ) {
|
||||
if (_has_this && _parameters.size() == 1 &&
|
||||
TypeManager::is_pointer(_return_type->get_new_type())) {
|
||||
// It receives no parameters, and returns a pointer.
|
||||
_flags |= F_make_copy;
|
||||
}
|
||||
}
|
||||
|
||||
} else if (_type == T_constructor) {
|
||||
if (!_has_this && _parameters.size() == 1) {
|
||||
if (TypeManager::unwrap(_parameters[0]._remap->get_orig_type()) ==
|
||||
TypeManager::unwrap(_return_type->get_orig_type())) {
|
||||
// If this is the only parameter, and it's the same as the
|
||||
// "this" type, this is a copy constructor.
|
||||
_flags |= F_copy_constructor;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -79,11 +79,14 @@ public:
|
||||
};
|
||||
|
||||
enum Flags {
|
||||
F_getitem = 0x0001,
|
||||
F_getitem_int = 0x0002,
|
||||
F_size = 0x0004,
|
||||
F_setitem = 0x0008,
|
||||
F_setitem_int = 0x0010,
|
||||
F_getitem = 0x0001,
|
||||
F_getitem_int = 0x0002,
|
||||
F_size = 0x0004,
|
||||
F_setitem = 0x0008,
|
||||
F_setitem_int = 0x0010,
|
||||
F_make_copy = 0x0020,
|
||||
F_copy_constructor = 0x0040,
|
||||
F_explicit_self = 0x0080,
|
||||
};
|
||||
|
||||
typedef vector<Parameter> Parameters;
|
||||
|
@ -123,6 +123,10 @@ check_protocols() {
|
||||
int flags = 0;
|
||||
|
||||
Functions::const_iterator fi;
|
||||
for (fi = _constructors.begin(); fi != _constructors.end(); ++fi) {
|
||||
Function *func = (*fi);
|
||||
flags |= func->_flags;
|
||||
}
|
||||
for (fi = _methods.begin(); fi != _methods.end(); ++fi) {
|
||||
Function *func = (*fi);
|
||||
flags |= func->_flags;
|
||||
@ -140,6 +144,16 @@ check_protocols() {
|
||||
_protocol_types |= PT_mapping;
|
||||
}
|
||||
|
||||
if (flags & FunctionRemap::F_make_copy) {
|
||||
// It's not exactly a protocol, but if we have a make_copy()
|
||||
// method, we can use it to synthesize a __copy__ and __deepcopy__
|
||||
// Python method to support the copy module.
|
||||
_protocol_types |= PT_make_copy;
|
||||
} else if (flags & FunctionRemap::F_copy_constructor) {
|
||||
// Ditto for the copy constructor.
|
||||
_protocol_types |= PT_copy_constructor;
|
||||
}
|
||||
|
||||
// Now are there any make_seq requests within this class?
|
||||
CPPStructType *stype = _itype._cpptype->as_struct_type();
|
||||
if (stype != (CPPStructType *)NULL) {
|
||||
|
@ -110,8 +110,10 @@ public:
|
||||
MakeSeqs _make_seqs;
|
||||
|
||||
enum ProtocolTypes {
|
||||
PT_sequence = 0x0001,
|
||||
PT_mapping = 0x0002,
|
||||
PT_sequence = 0x0001,
|
||||
PT_mapping = 0x0002,
|
||||
PT_make_copy = 0x0004,
|
||||
PT_copy_constructor = 0x0008,
|
||||
};
|
||||
int _protocol_types;
|
||||
};
|
||||
|
@ -97,7 +97,10 @@ RenameSet methodRenameDictionary[] = {
|
||||
{ "operator <<=" , "__ilshift__", 1 },
|
||||
{ "operator >>=" , "__irshift__", 1 },
|
||||
{ "operator typecast bool", "__nonzero__", 0 },
|
||||
{ "__nonzero__" , "__nonzero__", 0 },
|
||||
{ "__nonzero__" , "__nonzero__", 0 },
|
||||
{ "__reduce__" , "__reduce__", 0 },
|
||||
{ "__copy__" , "__copy__", 0 },
|
||||
{ "__deepcopy__" , "__deepcopy__", 0 },
|
||||
{ "print" , "Cprint", 0 },
|
||||
{ "CInterval.set_t", "_priv__cSetT", 0 },
|
||||
{ NULL, NULL, -1 }
|
||||
@ -159,34 +162,36 @@ RenameSet classRenameDictionary[] = {
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
const char * pythonKeywords[] = {
|
||||
"and",
|
||||
"del",
|
||||
"for",
|
||||
"is",
|
||||
"raise",
|
||||
"assert",
|
||||
"elif",
|
||||
"from",
|
||||
"lambda",
|
||||
"return",
|
||||
"break",
|
||||
"else",
|
||||
"global",
|
||||
"not",
|
||||
"try",
|
||||
"class",
|
||||
"except",
|
||||
"if",
|
||||
"or",
|
||||
"while",
|
||||
"continue",
|
||||
"exec",
|
||||
"import",
|
||||
"pass",
|
||||
"def",
|
||||
"finally",
|
||||
"in",
|
||||
"print",
|
||||
NULL};
|
||||
"del",
|
||||
"for",
|
||||
"is",
|
||||
"raise",
|
||||
"assert",
|
||||
"elif",
|
||||
"from",
|
||||
"lambda",
|
||||
"return",
|
||||
"break",
|
||||
"else",
|
||||
"global",
|
||||
"not",
|
||||
"try",
|
||||
"class",
|
||||
"except",
|
||||
"if",
|
||||
"or",
|
||||
"while",
|
||||
"continue",
|
||||
"exec",
|
||||
"import",
|
||||
"pass",
|
||||
"def",
|
||||
"finally",
|
||||
"in",
|
||||
"print",
|
||||
NULL
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////
|
||||
std::string checkKeyword(std::string & cppName)
|
||||
{
|
||||
@ -813,69 +818,69 @@ void InterfaceMakerPythonNative::write_prototypes_class(ostream &out_code,ostrea
|
||||
void InterfaceMakerPythonNative::write_functions(ostream &out)
|
||||
{
|
||||
inside_python_native = true;
|
||||
|
||||
out << "//********************************************************************\n";
|
||||
out << "//*** Functions for .. Global \n" ;
|
||||
out << "//********************************************************************\n";
|
||||
Functions::iterator fi;
|
||||
for (fi = _functions.begin(); fi != _functions.end(); ++fi)
|
||||
{
|
||||
Function *func = (*fi);
|
||||
if(!func->_itype.is_global() && isFunctionLegal(func))
|
||||
write_function_for_top(out, NULL, func,"");
|
||||
}
|
||||
|
||||
Objects::iterator oi;
|
||||
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
|
||||
{
|
||||
Object *object = (*oi).second;
|
||||
if(object->_itype.is_class() ||object->_itype.is_struct())
|
||||
{
|
||||
if(isCppTypeLegal(object->_itype._cpptype))
|
||||
if(isExportThisRun(object->_itype._cpptype))
|
||||
write_ClasseDetails(out,object);
|
||||
}
|
||||
}
|
||||
|
||||
// Objects::iterator oi;
|
||||
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
|
||||
|
||||
out << "//********************************************************************\n";
|
||||
out << "//*** Functions for .. Global \n" ;
|
||||
out << "//********************************************************************\n";
|
||||
Functions::iterator fi;
|
||||
for (fi = _functions.begin(); fi != _functions.end(); ++fi)
|
||||
{
|
||||
Object *object = (*oi).second;
|
||||
if(!object->_itype.get_outer_class())
|
||||
Function *func = (*fi);
|
||||
if(!func->_itype.is_global() && isFunctionLegal(func))
|
||||
write_function_for_top(out, NULL, func,"");
|
||||
}
|
||||
|
||||
Objects::iterator oi;
|
||||
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
|
||||
{
|
||||
Object *object = (*oi).second;
|
||||
if(object->_itype.is_class() ||object->_itype.is_struct())
|
||||
{
|
||||
if(object->_itype.is_class() ||object->_itype.is_struct())
|
||||
if(isCppTypeLegal(object->_itype._cpptype))
|
||||
if(isExportThisRun(object->_itype._cpptype))
|
||||
write_module_class(out,object);
|
||||
if(isCppTypeLegal(object->_itype._cpptype))
|
||||
if(isExportThisRun(object->_itype._cpptype))
|
||||
write_ClasseDetails(out,object);
|
||||
}
|
||||
}
|
||||
|
||||
// Objects::iterator oi;
|
||||
for (oi = _objects.begin(); oi != _objects.end(); ++oi)
|
||||
{
|
||||
Object *object = (*oi).second;
|
||||
if(!object->_itype.get_outer_class())
|
||||
{
|
||||
if(object->_itype.is_class() ||object->_itype.is_struct())
|
||||
if(isCppTypeLegal(object->_itype._cpptype))
|
||||
if(isExportThisRun(object->_itype._cpptype))
|
||||
write_module_class(out,object);
|
||||
}
|
||||
}
|
||||
inside_python_native = true;
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
// Function : write_ClasseDetails
|
||||
////////////////////////////////////////////////////////////
|
||||
void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
|
||||
{
|
||||
Functions::iterator fi;
|
||||
|
||||
//std::string cClassName = obj->_itype.get_scoped_name();
|
||||
std::string ClassName = make_safe_name(obj->_itype.get_scoped_name());
|
||||
std::string cClassName = obj->_itype.get_true_name();
|
||||
std::string export_class_name = classNameFromCppName(obj->_itype.get_name());
|
||||
|
||||
out << "//********************************************************************\n";
|
||||
out << "//*** Functions for .. "<< cClassName <<" \n" ;
|
||||
out << "//********************************************************************\n";
|
||||
|
||||
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi)
|
||||
Functions::iterator fi;
|
||||
|
||||
//std::string cClassName = obj->_itype.get_scoped_name();
|
||||
std::string ClassName = make_safe_name(obj->_itype.get_scoped_name());
|
||||
std::string cClassName = obj->_itype.get_true_name();
|
||||
std::string export_class_name = classNameFromCppName(obj->_itype.get_name());
|
||||
|
||||
out << "//********************************************************************\n";
|
||||
out << "//*** Functions for .. "<< cClassName <<" \n" ;
|
||||
out << "//********************************************************************\n";
|
||||
|
||||
for (fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi)
|
||||
{
|
||||
Function *func = (*fi);
|
||||
if( (func))
|
||||
Function *func = (*fi);
|
||||
if( (func))
|
||||
{
|
||||
SlottedFunctionDef def;
|
||||
get_slotted_function_def(obj, func, def);
|
||||
|
||||
|
||||
ostringstream GetThis;
|
||||
GetThis << " "<<cClassName << " * local_this = NULL;\n";
|
||||
GetThis << " DTOOL_Call_ExtractThisPointerForType(self,&Dtool_"<< ClassName<<",(void **)&local_this);\n";
|
||||
@ -887,7 +892,7 @@ void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
|
||||
// likes to call on the wrong-type objects.
|
||||
GetThis << " Py_INCREF(Py_NotImplemented);\n";
|
||||
GetThis << " return Py_NotImplemented;\n";
|
||||
|
||||
|
||||
} else {
|
||||
// Other functions should raise an exception if the this
|
||||
// pointer isn't set or is the wrong type.
|
||||
@ -898,100 +903,100 @@ void InterfaceMakerPythonNative::write_ClasseDetails(ostream &out, Object * obj)
|
||||
write_function_for_top(out, obj, func,GetThis.str());
|
||||
}
|
||||
}
|
||||
|
||||
// bool AnyLeganConstructors;
|
||||
|
||||
if(obj->_constructors.size() == 0)
|
||||
|
||||
// bool AnyLeganConstructors;
|
||||
|
||||
if(obj->_constructors.size() == 0)
|
||||
{
|
||||
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds)";
|
||||
out << fname << "\n";
|
||||
out << "{\n";
|
||||
out << " PyErr_SetString(PyExc_TypeError, \"Error Can Not Init Constant Class (" << cClassName << ")\");\n";
|
||||
out << " return -1;\n" ;
|
||||
out << "}\n";
|
||||
|
||||
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds)";
|
||||
out << fname << "\n";
|
||||
out << "{\n";
|
||||
out << " PyErr_SetString(PyExc_TypeError, \"Error Can Not Init Constant Class (" << cClassName << ")\");\n";
|
||||
out << " return -1;\n" ;
|
||||
out << "}\n";
|
||||
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
for (fi = obj->_constructors.begin(); fi != obj->_constructors.end(); ++fi)
|
||||
for (fi = obj->_constructors.begin(); fi != obj->_constructors.end(); ++fi)
|
||||
{
|
||||
Function *func = (*fi);
|
||||
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds) ";
|
||||
|
||||
write_function_for_name(out, obj, func,fname,"",ClassName);
|
||||
Function *func = (*fi);
|
||||
std::string fname = "int Dtool_Init_"+ClassName+"(PyObject *self, PyObject *args, PyObject *kwds) ";
|
||||
|
||||
write_function_for_name(out, obj, func,fname,"",ClassName);
|
||||
}
|
||||
}
|
||||
|
||||
MakeSeqs::iterator msi;
|
||||
for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
|
||||
write_make_seq(out, obj, ClassName, *msi);
|
||||
|
||||
MakeSeqs::iterator msi;
|
||||
for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
|
||||
write_make_seq(out, obj, ClassName, *msi);
|
||||
}
|
||||
|
||||
CPPType *cpptype = TypeManager::resolve_type(obj->_itype._cpptype);
|
||||
std::map< string ,CastDetails > details;
|
||||
std::map< string ,CastDetails >::iterator di;
|
||||
builder.get_type(TypeManager::unwrap(cpptype),false);
|
||||
GetValideChildClasses(details, cpptype->as_struct_type());
|
||||
for(di = details.begin(); di != details.end(); di++)
|
||||
{
|
||||
//InterrogateType ptype =idb->get_type(di->first);
|
||||
if(di->second._is_legal_py_class && !isExportThisRun(di->second._structType))
|
||||
_external_imports.insert(make_safe_name(di->second._to_class_name));
|
||||
//out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(di->second._to_class_name) <<";\n";
|
||||
}
|
||||
|
||||
|
||||
|
||||
{ // the Cast Converter
|
||||
|
||||
out << "inline void * Dtool_UpcastInterface_"<< ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type)\n";
|
||||
out << "{\n";
|
||||
out << " Dtool_PyTypedObject *SelfType = ((Dtool_PyInstDef *)self)->_My_Type;\n";
|
||||
out << " if(SelfType != &Dtool_" << ClassName <<")\n";
|
||||
out << " {\n";
|
||||
out << " printf(\""<<ClassName<<" ** Bad Source Type-- Requesting Conversion from %s to %s\\n\",((Dtool_PyInstDef *)self)->_My_Type->_name,requested_type->_name);fflush(NULL);\n";;
|
||||
out << " return NULL;\n";
|
||||
out << " }\n";
|
||||
out << " \n";
|
||||
out << " "<<cClassName<<" * local_this = (" << cClassName<<" *)((Dtool_PyInstDef *)self)->_ptr_to_object;\n";
|
||||
out << " if(requested_type == &Dtool_"<<ClassName<<")\n";
|
||||
out << " return local_this;\n";
|
||||
|
||||
CPPType *cpptype = TypeManager::resolve_type(obj->_itype._cpptype);
|
||||
std::map< string ,CastDetails > details;
|
||||
std::map< string ,CastDetails >::iterator di;
|
||||
builder.get_type(TypeManager::unwrap(cpptype),false);
|
||||
GetValideChildClasses(details, cpptype->as_struct_type());
|
||||
for(di = details.begin(); di != details.end(); di++)
|
||||
{
|
||||
//InterrogateType ptype =idb->get_type(di->first);
|
||||
if(di->second._is_legal_py_class && !isExportThisRun(di->second._structType))
|
||||
_external_imports.insert(make_safe_name(di->second._to_class_name));
|
||||
//out << "IMPORT_THIS struct Dtool_PyTypedObject Dtool_" << make_safe_name(di->second._to_class_name) <<";\n";
|
||||
if(di->second._is_legal_py_class)
|
||||
{
|
||||
out << " if(requested_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
|
||||
out << " return "<< di->second._up_cast_string << " local_this;\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
out << " return NULL;\n";
|
||||
out << "}\n";
|
||||
|
||||
{ // the Cast Converter
|
||||
|
||||
out << "inline void * Dtool_UpcastInterface_"<< ClassName << "(PyObject *self, Dtool_PyTypedObject *requested_type)\n";
|
||||
out << "{\n";
|
||||
out << " Dtool_PyTypedObject *SelfType = ((Dtool_PyInstDef *)self)->_My_Type;\n";
|
||||
out << " if(SelfType != &Dtool_" << ClassName <<")\n";
|
||||
out << " {\n";
|
||||
out << " printf(\""<<ClassName<<" ** Bad Source Type-- Requesting Conversion from %s to %s\\n\",((Dtool_PyInstDef *)self)->_My_Type->_name,requested_type->_name);fflush(NULL);\n";;
|
||||
out << " return NULL;\n";
|
||||
out << " }\n";
|
||||
out << " \n";
|
||||
out << " "<<cClassName<<" * local_this = (" << cClassName<<" *)((Dtool_PyInstDef *)self)->_ptr_to_object;\n";
|
||||
out << " if(requested_type == &Dtool_"<<ClassName<<")\n";
|
||||
out << " return local_this;\n";
|
||||
|
||||
for(di = details.begin(); di != details.end(); di++)
|
||||
{
|
||||
if(di->second._is_legal_py_class)
|
||||
{
|
||||
out << " if(requested_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
|
||||
out << " return "<< di->second._up_cast_string << " local_this;\n";
|
||||
}
|
||||
}
|
||||
|
||||
out << " return NULL;\n";
|
||||
out << "}\n";
|
||||
|
||||
out << "inline void * Dtool_DowncastInterface_"<< ClassName << "(void *from_this, Dtool_PyTypedObject *from_type)\n";
|
||||
out << "{\n";
|
||||
out << " if(from_this == NULL || from_type == NULL)\n";
|
||||
out << " return NULL;\n";
|
||||
out << " if(from_type == &Dtool_" << ClassName<<")\n";
|
||||
out << " return from_this;\n";
|
||||
for(di = details.begin(); di != details.end(); di++)
|
||||
{
|
||||
if(di->second._can_downcast && di->second._is_legal_py_class)
|
||||
{
|
||||
out << " if(from_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
|
||||
out << " {\n";
|
||||
out << " "<< di->second._to_class_name << "* other_this = ("<< di->second._to_class_name << "*)from_this;\n" ;
|
||||
out << " return ("<< cClassName << "*)other_this;\n";
|
||||
out << " }\n";
|
||||
}
|
||||
}
|
||||
out << " return (void *) NULL;\n";
|
||||
out << "}\n";
|
||||
|
||||
}
|
||||
out << "inline void * Dtool_DowncastInterface_"<< ClassName << "(void *from_this, Dtool_PyTypedObject *from_type)\n";
|
||||
out << "{\n";
|
||||
out << " if(from_this == NULL || from_type == NULL)\n";
|
||||
out << " return NULL;\n";
|
||||
out << " if(from_type == &Dtool_" << ClassName<<")\n";
|
||||
out << " return from_this;\n";
|
||||
for(di = details.begin(); di != details.end(); di++)
|
||||
{
|
||||
if(di->second._can_downcast && di->second._is_legal_py_class)
|
||||
{
|
||||
out << " if(from_type == &Dtool_"<<make_safe_name(di->second._to_class_name)<<")\n";
|
||||
out << " {\n";
|
||||
out << " "<< di->second._to_class_name << "* other_this = ("<< di->second._to_class_name << "*)from_this;\n" ;
|
||||
out << " return ("<< cClassName << "*)other_this;\n";
|
||||
out << " }\n";
|
||||
}
|
||||
}
|
||||
out << " return (void *) NULL;\n";
|
||||
out << "}\n";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////
|
||||
/// Function : write_ClasseDeclarations
|
||||
//
|
||||
@ -1215,9 +1220,18 @@ write_module_class(ostream &out, Object *obj) {
|
||||
std::map<Function *, std::string > normal_Operator_functions;
|
||||
std::map<Function *, SlottedFunctionDef> wraped_Operator_functions;
|
||||
// function Table
|
||||
bool got_copy = false;
|
||||
bool got_deepcopy = false;
|
||||
|
||||
int x;
|
||||
for (x = 0, fi = obj->_methods.begin(); fi != obj->_methods.end(); ++fi,x++) {
|
||||
Function *func = (*fi);
|
||||
if (func->_name == "__copy__") {
|
||||
got_copy = true;
|
||||
} else if (func->_name == "__deepcopy__") {
|
||||
got_deepcopy = true;
|
||||
}
|
||||
|
||||
SlottedFunctionDef slotted_def;
|
||||
if (!get_slotted_function_def(obj, func, slotted_def)) {
|
||||
out << " { \"" << methodNameFromCppName(func,export_calss_name) << "\",(PyCFunction ) &"
|
||||
@ -1248,6 +1262,22 @@ write_module_class(ostream &out, Object *obj) {
|
||||
}
|
||||
}
|
||||
|
||||
if (obj->_protocol_types & Object::PT_make_copy) {
|
||||
if (!got_copy) {
|
||||
out << " { \"__copy__\", (PyCFunction)©_from_make_copy, METH_NOARGS, NULL},\n";
|
||||
got_copy = true;
|
||||
}
|
||||
} else if (obj->_protocol_types & Object::PT_copy_constructor) {
|
||||
if (!got_copy) {
|
||||
out << " { \"__copy__\", (PyCFunction)©_from_copy_constructor, METH_NOARGS, NULL},\n";
|
||||
got_copy = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (got_copy && !got_deepcopy) {
|
||||
out << " { \"__deepcopy__\", (PyCFunction)&map_deepcopy_to_copy, METH_VARARGS, NULL},\n";
|
||||
}
|
||||
|
||||
MakeSeqs::iterator msi;
|
||||
for (msi = obj->_make_seqs.begin(); msi != obj->_make_seqs.end(); ++msi) {
|
||||
out << " { \""
|
||||
|
@ -708,6 +708,42 @@ PyObject *make_list_for_item(PyObject *self, const char *num_name,
|
||||
return list;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: copy_from_make_copy
|
||||
// Description: This is a support function for a synthesized
|
||||
// __copy__() method from a C++ make_copy() method.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *copy_from_make_copy(PyObject *self) {
|
||||
return PyObject_CallMethod(self, (char *)"makeCopy", (char *)"()");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: copy_from_make_copy
|
||||
// Description: This is a support function for a synthesized
|
||||
// __copy__() method from a C++ copy constructor.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *copy_from_copy_constructor(PyObject *self) {
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = PyObject_CallFunction(this_class, (char *)"(O)", self);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: copy_from_make_copy
|
||||
// Description: This is a support function for a synthesized
|
||||
// __deepcopy__() method for any class that has a
|
||||
// __copy__() method. The sythethic method simply
|
||||
// invokes __copy__().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *map_deepcopy_to_copy(PyObject *self, PyObject *args) {
|
||||
return PyObject_CallMethod(self, (char *)"__copy__", (char *)"()");
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PyLongOrInt_FromUnsignedLong
|
||||
// Description: Similar to PyLong_FromUnsignedLong(), but returns
|
||||
|
@ -174,114 +174,118 @@ struct Dtool_PyTypedObject {
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Macro's from Hell.. May want to Just Add this to the Code generator..
|
||||
// Macros from Hell.. May want to just add this to the code generator..
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
|
||||
static PyNumberMethods Dtool_PyNumberMethods_##CLASS_NAME ={\
|
||||
0,/*binaryfunc nb_add*/\
|
||||
0,/*binaryfunc nb_subtract*/\
|
||||
0,/*binaryfunc nb_multiply*/\
|
||||
0,/*binaryfunc nb_divide*/\
|
||||
0,/*binaryfunc nb_remainder*/\
|
||||
0,/*binaryfunc nb_divmod*/\
|
||||
0,/*ternaryfunc nb_power*/\
|
||||
0,/*unaryfunc nb_negative*/\
|
||||
0,/*unaryfunc nb_positive*/\
|
||||
0,/*unaryfunc nb_absolute*/\
|
||||
0,/*inquiry nb_nonzero*/\
|
||||
0,/*unaryfunc nb_invert*/\
|
||||
0,/*binaryfunc nb_lshift*/\
|
||||
0,/*binaryfunc nb_rshift*/\
|
||||
0,/*binaryfunc nb_and*/\
|
||||
0,/*binaryfunc nb_xor*/\
|
||||
0,/*binaryfunc nb_or*/\
|
||||
0,/*coercion nb_coerce*/\
|
||||
0,/*unaryfunc nb_int*/\
|
||||
0,/*unaryfunc nb_long*/\
|
||||
0,/*unaryfunc nb_float*/\
|
||||
0,/*unaryfunc nb_oct*/\
|
||||
0,/*unaryfunc nb_hex*/\
|
||||
0,/*binaryfunc nb_inplace_add*/\
|
||||
0,/*binaryfunc nb_inplace_subtract*/\
|
||||
0,/*binaryfunc nb_inplace_multiply*/\
|
||||
0,/*binaryfunc nb_inplace_divide*/\
|
||||
0,/*binaryfunc nb_inplace_remainder*/\
|
||||
0,/*ternaryfunc nb_inplace_power*/\
|
||||
0,/*binaryfunc nb_inplace_lshift*/\
|
||||
0,/*binaryfunc nb_inplace_rshift*/\
|
||||
0,/*binaryfunc nb_inplace_and*/\
|
||||
0,/*binaryfunc nb_inplace_xor*/\
|
||||
0,/*binaryfunc nb_inplace_or*/\
|
||||
0,/*binaryfunc nb_floor_divide*/\
|
||||
0,/*binaryfunc nb_true_divide*/\
|
||||
0,/*binaryfunc nb_inplace_floor_divide*/\
|
||||
0,/*binaryfunc nb_inplace_true_divide*/\
|
||||
};\
|
||||
static PySequenceMethods Dtool_PySequenceMethods_##CLASS_NAME ={\
|
||||
0,/*lenfunc sq_length */\
|
||||
0,/*binaryfunc sq_concat */\
|
||||
0,/*ssizeargfunc sq_repeat */\
|
||||
0,/*ssizeargfunc sq_item */\
|
||||
0,/*ssizeargfunc sq_ass_item */\
|
||||
0,/*objobjproc sq_contains */\
|
||||
0,/*binaryfunc sq_inplace_concat */\
|
||||
0,/*ssizeargfunc sq_inplace_repeat */\
|
||||
};\
|
||||
static PyMappingMethods Dtool_PyMappingMethods_##CLASS_NAME ={\
|
||||
0,/*inquiry mp_length */\
|
||||
0,/*binaryfunc mp_subscript */\
|
||||
0,/*objobjargproc mp_ass_subscript */\
|
||||
};\
|
||||
EXPORT_THIS Dtool_PyTypedObject Dtool_##CLASS_NAME = {\
|
||||
{\
|
||||
PyObject_HEAD_INIT(NULL)\
|
||||
0,\
|
||||
"lib" #MODULE_NAME "." #PUBLIC_NAME, /*type name with module */ \
|
||||
sizeof(Dtool_PyInstDef), /* tp_basicsize*/ \
|
||||
0, /*tp_itemsize*/ \
|
||||
&Dtool_Deallocate_General, /*Dtool_Deallocate_##CLASS_NAME,*/ /*tp_dealloc*/\
|
||||
0, /*tp_print*/\
|
||||
0, /*tp_getattr*/\
|
||||
0, /*tp_setattr*/\
|
||||
0, /*tp_compare*/\
|
||||
0, /*tp_repr*/\
|
||||
&Dtool_PyNumberMethods_##CLASS_NAME, /*tp_as_number*/\
|
||||
&Dtool_PySequenceMethods_##CLASS_NAME, /*tp_as_sequence*/\
|
||||
&Dtool_PyMappingMethods_##CLASS_NAME, /*tp_as_mapping*/\
|
||||
0, /*tp_hash */\
|
||||
0, /* tp_call */\
|
||||
0, /* tp_str */\
|
||||
PyObject_GenericGetAttr, /* tp_getattro */\
|
||||
PyObject_GenericSetAttr, /* tp_setattro */\
|
||||
0, /* tp_as_buffer */\
|
||||
(Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */\
|
||||
0, /* tp_doc */\
|
||||
0, /* tp_traverse */\
|
||||
0, /* tp_clear */\
|
||||
0, /* tp_richcompare */\
|
||||
0, /* tp_weaklistoffset */\
|
||||
0, /* tp_iter */\
|
||||
0, /* tp_iternext */\
|
||||
Dtool_Methods_##CLASS_NAME, /* tp_methods */\
|
||||
standard_type_members, /* tp_members */\
|
||||
0, /* tp_getset */\
|
||||
0, /* tp_base */\
|
||||
0, /* tp_dict */\
|
||||
0, /* tp_descr_get */\
|
||||
0, /* tp_descr_set */\
|
||||
0, /* tp_dictoffset */\
|
||||
Dtool_Init_##CLASS_NAME, /* tp_init */\
|
||||
PyType_GenericAlloc, /* tp_alloc */\
|
||||
Dtool_new_##CLASS_NAME, /* tp_new */\
|
||||
_PyObject_Del, /* tp_free */\
|
||||
},\
|
||||
#CLASS_NAME, \
|
||||
false,\
|
||||
Dtool_UpcastInterface_##CLASS_NAME, \
|
||||
Dtool_DowncastInterface_##CLASS_NAME, \
|
||||
Dtool_FreeInstance_##CLASS_NAME, \
|
||||
Dtool_PyModuleClassInit_##CLASS_NAME\
|
||||
};
|
||||
#define Define_Dtool_Class(MODULE_NAME, CLASS_NAME, PUBLIC_NAME) \
|
||||
static PyNumberMethods Dtool_PyNumberMethods_##CLASS_NAME = \
|
||||
{ \
|
||||
0,/*binaryfunc nb_add*/ \
|
||||
0,/*binaryfunc nb_subtract*/ \
|
||||
0,/*binaryfunc nb_multiply*/ \
|
||||
0,/*binaryfunc nb_divide*/ \
|
||||
0,/*binaryfunc nb_remainder*/ \
|
||||
0,/*binaryfunc nb_divmod*/ \
|
||||
0,/*ternaryfunc nb_power*/ \
|
||||
0,/*unaryfunc nb_negative*/ \
|
||||
0,/*unaryfunc nb_positive*/ \
|
||||
0,/*unaryfunc nb_absolute*/ \
|
||||
0,/*inquiry nb_nonzero*/ \
|
||||
0,/*unaryfunc nb_invert*/ \
|
||||
0,/*binaryfunc nb_lshift*/ \
|
||||
0,/*binaryfunc nb_rshift*/ \
|
||||
0,/*binaryfunc nb_and*/ \
|
||||
0,/*binaryfunc nb_xor*/ \
|
||||
0,/*binaryfunc nb_or*/ \
|
||||
0,/*coercion nb_coerce*/ \
|
||||
0,/*unaryfunc nb_int*/ \
|
||||
0,/*unaryfunc nb_long*/ \
|
||||
0,/*unaryfunc nb_float*/ \
|
||||
0,/*unaryfunc nb_oct*/ \
|
||||
0,/*unaryfunc nb_hex*/ \
|
||||
0,/*binaryfunc nb_inplace_add*/ \
|
||||
0,/*binaryfunc nb_inplace_subtract*/ \
|
||||
0,/*binaryfunc nb_inplace_multiply*/ \
|
||||
0,/*binaryfunc nb_inplace_divide*/ \
|
||||
0,/*binaryfunc nb_inplace_remainder*/ \
|
||||
0,/*ternaryfunc nb_inplace_power*/ \
|
||||
0,/*binaryfunc nb_inplace_lshift*/ \
|
||||
0,/*binaryfunc nb_inplace_rshift*/ \
|
||||
0,/*binaryfunc nb_inplace_and*/ \
|
||||
0,/*binaryfunc nb_inplace_xor*/ \
|
||||
0,/*binaryfunc nb_inplace_or*/ \
|
||||
0,/*binaryfunc nb_floor_divide*/ \
|
||||
0,/*binaryfunc nb_true_divide*/ \
|
||||
0,/*binaryfunc nb_inplace_floor_divide*/ \
|
||||
0,/*binaryfunc nb_inplace_true_divide*/ \
|
||||
}; \
|
||||
static PySequenceMethods Dtool_PySequenceMethods_##CLASS_NAME = \
|
||||
{ \
|
||||
0,/*lenfunc sq_length */ \
|
||||
0,/*binaryfunc sq_concat */ \
|
||||
0,/*ssizeargfunc sq_repeat */ \
|
||||
0,/*ssizeargfunc sq_item */ \
|
||||
0,/*ssizeargfunc sq_ass_item */ \
|
||||
0,/*objobjproc sq_contains */ \
|
||||
0,/*binaryfunc sq_inplace_concat */ \
|
||||
0,/*ssizeargfunc sq_inplace_repeat */ \
|
||||
}; \
|
||||
static PyMappingMethods Dtool_PyMappingMethods_##CLASS_NAME = \
|
||||
{ \
|
||||
0,/*inquiry mp_length */ \
|
||||
0,/*binaryfunc mp_subscript */ \
|
||||
0,/*objobjargproc mp_ass_subscript */ \
|
||||
}; \
|
||||
EXPORT_THIS Dtool_PyTypedObject Dtool_##CLASS_NAME = \
|
||||
{ \
|
||||
{ \
|
||||
PyObject_HEAD_INIT(NULL) \
|
||||
0, \
|
||||
"lib" #MODULE_NAME "." #PUBLIC_NAME, /*type name with module */ \
|
||||
sizeof(Dtool_PyInstDef), /* tp_basicsize */ \
|
||||
0, /* tp_itemsize */ \
|
||||
&Dtool_Deallocate_General, /* tp_dealloc */ \
|
||||
0, /* tp_print */ \
|
||||
0, /* tp_getattr */ \
|
||||
0, /* tp_setattr */ \
|
||||
0, /* tp_compare */ \
|
||||
0, /* tp_repr */ \
|
||||
&Dtool_PyNumberMethods_##CLASS_NAME, /* tp_as_number */ \
|
||||
&Dtool_PySequenceMethods_##CLASS_NAME, /* tp_as_sequence */ \
|
||||
&Dtool_PyMappingMethods_##CLASS_NAME, /* tp_as_mapping */ \
|
||||
0, /* tp_hash */ \
|
||||
0, /* tp_call */ \
|
||||
0, /* tp_str */ \
|
||||
PyObject_GenericGetAttr, /* tp_getattro */ \
|
||||
PyObject_GenericSetAttr, /* tp_setattro */ \
|
||||
0, /* tp_as_buffer */ \
|
||||
(Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES), /* tp_flags */ \
|
||||
0, /* tp_doc */ \
|
||||
0, /* tp_traverse */ \
|
||||
0, /* tp_clear */ \
|
||||
0, /* tp_richcompare */ \
|
||||
0, /* tp_weaklistoffset */ \
|
||||
0, /* tp_iter */ \
|
||||
0, /* tp_iternext */ \
|
||||
Dtool_Methods_##CLASS_NAME, /* tp_methods */ \
|
||||
standard_type_members, /* tp_members */ \
|
||||
0, /* tp_getset */ \
|
||||
0, /* tp_base */ \
|
||||
0, /* tp_dict */ \
|
||||
0, /* tp_descr_get */ \
|
||||
0, /* tp_descr_set */ \
|
||||
0, /* tp_dictoffset */ \
|
||||
Dtool_Init_##CLASS_NAME, /* tp_init */ \
|
||||
PyType_GenericAlloc, /* tp_alloc */ \
|
||||
Dtool_new_##CLASS_NAME, /* tp_new */ \
|
||||
_PyObject_Del, /* tp_free */ \
|
||||
}, \
|
||||
#CLASS_NAME, \
|
||||
false, \
|
||||
Dtool_UpcastInterface_##CLASS_NAME, \
|
||||
Dtool_DowncastInterface_##CLASS_NAME, \
|
||||
Dtool_FreeInstance_##CLASS_NAME, \
|
||||
Dtool_PyModuleClassInit_##CLASS_NAME \
|
||||
};
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
@ -538,6 +542,16 @@ EXPCL_DTOOLCONFIG int DTOOL_PyObject_Compare(PyObject *v1, PyObject *v2);
|
||||
EXPCL_DTOOLCONFIG PyObject *
|
||||
make_list_for_item(PyObject *self, const char *num_name,
|
||||
const char *element_name);
|
||||
|
||||
EXPCL_DTOOLCONFIG PyObject *
|
||||
copy_from_make_copy(PyObject *self);
|
||||
|
||||
EXPCL_DTOOLCONFIG PyObject *
|
||||
copy_from_copy_constructor(PyObject *self);
|
||||
|
||||
EXPCL_DTOOLCONFIG PyObject *
|
||||
map_deepcopy_to_copy(PyObject *self, PyObject *args);
|
||||
|
||||
EXPCL_DTOOLCONFIG PyObject *
|
||||
PyLongOrInt_FromUnsignedLong(unsigned long value);
|
||||
|
||||
|
@ -51,6 +51,7 @@ extern "C" {
|
||||
EXPCL_DTOOLCONFIG int PyGen_Type(...);
|
||||
EXPCL_DTOOLCONFIG int PyGILState_Ensure(...);
|
||||
EXPCL_DTOOLCONFIG int PyGILState_Release(...);
|
||||
EXPCL_DTOOLCONFIG int PyImport_GetModuleDict(...);
|
||||
EXPCL_DTOOLCONFIG int PyInt_AsLong(...);
|
||||
EXPCL_DTOOLCONFIG int PyInt_AsSsize_t(...);
|
||||
EXPCL_DTOOLCONFIG int PyInt_FromLong(...);
|
||||
@ -74,6 +75,7 @@ extern "C" {
|
||||
EXPCL_DTOOLCONFIG int PyModule_AddObject(...);
|
||||
EXPCL_DTOOLCONFIG int PyNumber_Long(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_Call(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_CallFunction(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_CallMethod(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_CallMethodObjArgs(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_CallObject(...);
|
||||
@ -88,6 +90,7 @@ extern "C" {
|
||||
EXPCL_DTOOLCONFIG int PyObject_Repr(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_SetAttrString(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_Str(...);
|
||||
EXPCL_DTOOLCONFIG int PyObject_Type(...);
|
||||
EXPCL_DTOOLCONFIG int PySequence_Check(...);
|
||||
EXPCL_DTOOLCONFIG int PySequence_GetItem(...);
|
||||
EXPCL_DTOOLCONFIG int PySequence_Size(...);
|
||||
@ -180,6 +183,7 @@ int PyGen_Check(...) { return 0; }
|
||||
int PyGen_Type(...) { return 0; }
|
||||
int PyGILState_Ensure(...) { return 0; }
|
||||
int PyGILState_Release(...) { return 0; }
|
||||
int PyImport_GetModuleDict(...) { return 0; }
|
||||
int PyInt_AsLong(...) { return 0; }
|
||||
int PyInt_AsSsize_t(...) { return 0; }
|
||||
int PyInt_FromLong(...) { return 0; }
|
||||
@ -203,6 +207,7 @@ int PyModule_AddIntConstant(...) { return 0; };
|
||||
int PyModule_AddObject(...) { return 0; };
|
||||
int PyNumber_Long(...) { return 0; }
|
||||
int PyObject_Call(...) { return 0; }
|
||||
int PyObject_CallFunction(...) { return 0; }
|
||||
int PyObject_CallMethod(...) { return 0; }
|
||||
int PyObject_CallMethodObjArgs(...) { return 0; }
|
||||
int PyObject_CallObject(...) { return 0; }
|
||||
@ -217,6 +222,7 @@ int PyObject_IsTrue(...) { return 0; }
|
||||
int PyObject_Repr(...) { return 0; }
|
||||
int PyObject_SetAttrString(...) { return 0; }
|
||||
int PyObject_Str(...) { return 0; }
|
||||
int PyObject_Type(...) { return 0; }
|
||||
int PySequence_Check(...) { return 0; }
|
||||
int PySequence_GetItem(...) { return 0; }
|
||||
int PySequence_Size(...) { return 0; }
|
||||
|
@ -46,6 +46,33 @@ const FLOATNAME(LMatrix3) FLOATNAME(LMatrix3)::_ly_to_rz_mat =
|
||||
FLOATNAME(LMatrix3)::_flip_z_mat * FLOATNAME(LMatrix3)::_y_to_z_up_mat;
|
||||
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LMatrix3::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *FLOATNAME(LMatrix3)::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(fffffffff))", this_class,
|
||||
_m.m._00, _m.m._01, _m.m._02,
|
||||
_m.m._10, _m.m._11, _m.m._12,
|
||||
_m.m._20, _m.m._21, _m.m._22);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LMatrix::set_scale_shear_mat
|
||||
// Access: Public
|
||||
|
@ -65,6 +65,10 @@ PUBLISHED:
|
||||
FLOATTYPE e20, FLOATTYPE e21, FLOATTYPE e22);
|
||||
ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix3));
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
void fill(FLOATTYPE fill_value);
|
||||
INLINE_LINMATH void set(
|
||||
FLOATTYPE e00, FLOATTYPE e01, FLOATTYPE e02,
|
||||
|
@ -62,6 +62,35 @@ const FLOATNAME(LMatrix4) FLOATNAME(LMatrix4)::_lz_to_ry_mat =
|
||||
const FLOATNAME(LMatrix4) FLOATNAME(LMatrix4)::_ly_to_rz_mat =
|
||||
FLOATNAME(LMatrix4)::_flip_z_mat * FLOATNAME(LMatrix4)::_y_to_z_up_mat;
|
||||
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LMatrix4::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *FLOATNAME(LMatrix4)::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(ffffffffffffffff))", this_class,
|
||||
_m.m._00, _m.m._01, _m.m._02, _m.m._03,
|
||||
_m.m._10, _m.m._11, _m.m._12, _m.m._13,
|
||||
_m.m._20, _m.m._21, _m.m._22, _m.m._23,
|
||||
_m.m._30, _m.m._31, _m.m._32, _m.m._33);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LMatrix::convert_mat
|
||||
// Access: Public, Static
|
||||
|
@ -60,6 +60,10 @@ PUBLISHED:
|
||||
FLOATTYPE e30, FLOATTYPE e31, FLOATTYPE e32, FLOATTYPE e33);
|
||||
ALLOC_DELETED_CHAIN(FLOATNAME(LMatrix4));
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
// Construct a 4x4 matrix given a 3x3 rotation matrix and an optional
|
||||
// translation component.
|
||||
INLINE_LINMATH FLOATNAME(LMatrix4)(const FLOATNAME(LMatrix3) &upper3);
|
||||
|
@ -21,6 +21,31 @@ const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_unit_x =
|
||||
const FLOATNAME(LVecBase2) FLOATNAME(LVecBase2)::_unit_y =
|
||||
FLOATNAME(LVecBase2)(0.0f, 1.0f);
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase2::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *FLOATNAME(LVecBase2)::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(ff))", this_class,
|
||||
(*this)[0], (*this)[1]);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase2::init_type
|
||||
// Access: Public, Static
|
||||
|
@ -39,6 +39,10 @@ PUBLISHED:
|
||||
|
||||
INLINE_LINMATH ~FLOATNAME(LVecBase2)();
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
INLINE_LINMATH FLOATTYPE operator [](int i) const;
|
||||
INLINE_LINMATH FLOATTYPE &operator [](int i);
|
||||
#ifdef HAVE_PYTHON
|
||||
|
@ -12,6 +12,7 @@
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
TypeHandle FLOATNAME(LVecBase3)::_type_handle;
|
||||
|
||||
const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_zero =
|
||||
@ -23,6 +24,32 @@ const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_unit_y =
|
||||
const FLOATNAME(LVecBase3) FLOATNAME(LVecBase3)::_unit_z =
|
||||
FLOATNAME(LVecBase3)(0.0f, 0.0f, 1.0f);
|
||||
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase3::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *FLOATNAME(LVecBase3)::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(fff))", this_class,
|
||||
(*this)[0], (*this)[1], (*this)[2]);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase3::init_type
|
||||
// Access: Public, Static
|
||||
|
@ -37,6 +37,10 @@ PUBLISHED:
|
||||
|
||||
INLINE_LINMATH ~FLOATNAME(LVecBase3)();
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
INLINE_LINMATH FLOATTYPE operator [](int i) const;
|
||||
INLINE_LINMATH FLOATTYPE &operator [](int i);
|
||||
#ifdef HAVE_PYTHON
|
||||
|
@ -25,6 +25,31 @@ const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_unit_z =
|
||||
const FLOATNAME(LVecBase4) FLOATNAME(LVecBase4)::_unit_w =
|
||||
FLOATNAME(LVecBase4)(0.0f, 0.0f, 0.0f, 1.0f);
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase4::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *FLOATNAME(LVecBase4)::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(ffff))", this_class,
|
||||
(*this)[0], (*this)[1], (*this)[2], (*this)[3]);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: LVecBase4::init_type
|
||||
// Access: Public, Static
|
||||
|
@ -38,6 +38,10 @@ PUBLISHED:
|
||||
|
||||
INLINE_LINMATH ~FLOATNAME(LVecBase4)();
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
INLINE_LINMATH FLOATTYPE operator [](int i) const;
|
||||
INLINE_LINMATH FLOATTYPE &operator [](int i);
|
||||
#ifdef HAVE_PYTHON
|
||||
|
@ -66,6 +66,7 @@
|
||||
#include "pStatCollector.h"
|
||||
#include "pStatTimer.h"
|
||||
#include "modelNode.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
// stack seems to overflow on Intel C++ at 7000. If we need more than
|
||||
// 7000, need to increase stack size.
|
||||
@ -127,6 +128,128 @@ static ConfigVariableEnum<EmptyNodePathType> empty_node_path
|
||||
// ***End temporary transition code for operator bool
|
||||
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodePath::__copy__
|
||||
// Access: Published
|
||||
// Description: A special Python method that is invoked by
|
||||
// copy.copy(node). Unlike the NodePath copy
|
||||
// constructor, this makes a duplicate copy of the
|
||||
// underlying PandaNode (but shares children, instead of
|
||||
// copying them or omitting them).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodePath NodePath::
|
||||
__copy__() const {
|
||||
if (is_empty()) {
|
||||
// Invoke the copy constructor if we have no node.
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If we do have a node, duplicate it, and wrap it in a new
|
||||
// NodePath.
|
||||
return NodePath(node()->__copy__());
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodePath::__deepcopy__
|
||||
// Access: Published
|
||||
// Description: A special Python method that is invoked by
|
||||
// copy.deepcopy(np). This calls copy_to() unless the
|
||||
// NodePath is already present in the provided
|
||||
// dictionary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *NodePath::
|
||||
__deepcopy__(PyObject *self, PyObject *memo) const {
|
||||
IMPORT_THIS struct Dtool_PyTypedObject Dtool_NodePath;
|
||||
|
||||
// Borrowed reference.
|
||||
PyObject *dupe = PyDict_GetItem(memo, self);
|
||||
if (dupe != NULL) {
|
||||
// Already in the memo dictionary.
|
||||
Py_INCREF(dupe);
|
||||
return dupe;
|
||||
}
|
||||
|
||||
NodePath *np_dupe;
|
||||
if (is_empty()) {
|
||||
np_dupe = new NodePath(*this);
|
||||
} else {
|
||||
np_dupe = new NodePath(copy_to(NodePath()));
|
||||
}
|
||||
|
||||
dupe = DTool_CreatePyInstance((void *)np_dupe, Dtool_NodePath,
|
||||
true, false);
|
||||
if (PyDict_SetItem(memo, self, dupe) != 0) {
|
||||
Py_DECREF(dupe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dupe;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodePath::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *NodePath::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
|
||||
if (is_empty()) {
|
||||
// Reconstruct an empty NodePath. Not a 100% reconstruction,
|
||||
// because we lose the specific error status, but I don't think
|
||||
// that matters much.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O())", this_class);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
// We have a non-empty NodePath. We need to streamify the
|
||||
// underlying node.
|
||||
|
||||
string bam_stream;
|
||||
if (!node()->encode_to_bam_stream(bam_stream)) {
|
||||
ostringstream stream;
|
||||
stream << "Could not bamify object of type " << node()->get_type() << "\n";
|
||||
string message = stream.str();
|
||||
PyErr_SetString(PyExc_TypeError, message.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Start by getting this class object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *func = TypedWritable::find_global_decode(this_class, "pyDecodeNodePathFromBamStream");
|
||||
if (func == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeNodePathFromBamStream()");
|
||||
Py_DECREF(this_class);
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(this_class);
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(s#))", func, bam_stream.data(), bam_stream.size());
|
||||
Py_DECREF(func);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NodePath::operator bool
|
||||
// Access: Published
|
||||
@ -7292,3 +7415,23 @@ r_find_all_materials(PandaNode *node, const RenderState *state,
|
||||
r_find_all_materials(child, next_state, materials);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: py_decode_NodePath_from_bam_stream
|
||||
// Access: Published
|
||||
// Description: This wrapper is defined as a global function to suit
|
||||
// pickle's needs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
NodePath
|
||||
py_decode_NodePath_from_bam_stream(const string &data) {
|
||||
PT(PandaNode) node = PandaNode::decode_from_bam_stream(data);
|
||||
if (node == (PandaNode *)NULL) {
|
||||
PyErr_SetString(PyExc_ValueError, "Could not unpack bam stream");
|
||||
return NodePath();
|
||||
}
|
||||
|
||||
return NodePath(node);
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
|
@ -168,6 +168,12 @@ PUBLISHED:
|
||||
INLINE NodePath(const NodePath ©);
|
||||
INLINE void operator = (const NodePath ©);
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
NodePath __copy__() const;
|
||||
PyObject *__deepcopy__(PyObject *self, PyObject *memo) const;
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
INLINE static NodePath not_found();
|
||||
INLINE static NodePath removed();
|
||||
INLINE static NodePath fail();
|
||||
@ -949,6 +955,12 @@ private:
|
||||
|
||||
INLINE ostream &operator << (ostream &out, const NodePath &node_path);
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
BEGIN_PUBLISH
|
||||
NodePath py_decode_NodePath_from_bam_stream(const string &data);
|
||||
END_PUBLISH
|
||||
#endif
|
||||
|
||||
#include "nodePath.I"
|
||||
|
||||
#endif
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "config_mathutil.h"
|
||||
#include "lightReMutexHolder.h"
|
||||
#include "graphicsStateGuardianBase.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
// This category is just temporary for debugging convenience.
|
||||
NotifyCategoryDecl(drawmask, EXPCL_PANDA_PGRAPH, EXPTP_PANDA_PGRAPH);
|
||||
@ -211,20 +212,6 @@ as_reference_count() {
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::make_copy
|
||||
// Access: Public, Virtual
|
||||
// Description: Returns a newly-allocated PandaNode that is a shallow
|
||||
// copy of this one. It will be a different pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original PandaNode. No children will be
|
||||
// copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PandaNode::
|
||||
make_copy() const {
|
||||
return new PandaNode(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::dupe_for_flatten
|
||||
// Access: Public, Virtual
|
||||
@ -608,6 +595,20 @@ void PandaNode::
|
||||
add_for_draw(CullTraverser *, CullTraverserData &) {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::make_copy
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns a newly-allocated PandaNode that is a shallow
|
||||
// copy of this one. It will be a different pointer,
|
||||
// but its internal data may or may not be shared with
|
||||
// that of the original PandaNode. No children will be
|
||||
// copied.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PandaNode *PandaNode::
|
||||
make_copy() const {
|
||||
return new PandaNode(*this);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::copy_subgraph
|
||||
// Access: Published
|
||||
@ -618,12 +619,79 @@ add_for_draw(CullTraverser *, CullTraverserData &) {
|
||||
// will impede normal use of the PandaNode.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(PandaNode) PandaNode::
|
||||
copy_subgraph(Thread *current_thread) const
|
||||
{
|
||||
copy_subgraph(Thread *current_thread) const {
|
||||
InstanceMap inst_map;
|
||||
return r_copy_subgraph(inst_map, current_thread);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::__copy__
|
||||
// Access: Published
|
||||
// Description: A special Python method that is invoked by
|
||||
// copy.copy(node). Unlike the PandaNode copy
|
||||
// constructor, which creates a new node without
|
||||
// children, this shares child pointers (essentially
|
||||
// making every child an instance). This is intended to
|
||||
// simulate the behavior of copy.copy() for other
|
||||
// objects.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(PandaNode) PandaNode::
|
||||
__copy__() const {
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
|
||||
PT(PandaNode) node_dupe = make_copy();
|
||||
|
||||
Children children = get_children(current_thread);
|
||||
int num_children = children.get_num_children();
|
||||
|
||||
for (int i = 0; i < num_children; ++i) {
|
||||
PandaNode *child = children.get_child(i);
|
||||
node_dupe->add_child(children.get_child(i), children.get_child_sort(i));
|
||||
}
|
||||
|
||||
return node_dupe;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::__deepcopy__
|
||||
// Access: Published
|
||||
// Description: A special Python method that is invoked by
|
||||
// copy.deepcopy(node). This calls copy_subgraph()
|
||||
// unless the node is already present in the provided
|
||||
// dictionary.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *PandaNode::
|
||||
__deepcopy__(PyObject *self, PyObject *memo) const {
|
||||
IMPORT_THIS struct Dtool_PyTypedObject Dtool_PandaNode;
|
||||
|
||||
// Borrowed reference.
|
||||
PyObject *dupe = PyDict_GetItem(memo, self);
|
||||
if (dupe != NULL) {
|
||||
// Already in the memo dictionary.
|
||||
Py_INCREF(dupe);
|
||||
return dupe;
|
||||
}
|
||||
|
||||
PT(PandaNode) node_dupe = copy_subgraph();
|
||||
|
||||
// DTool_CreatePyInstanceTyped() steals a C++ reference.
|
||||
node_dupe->ref();
|
||||
dupe = DTool_CreatePyInstanceTyped
|
||||
((void *)node_dupe.p(), Dtool_PandaNode, true, false,
|
||||
node_dupe->get_type_index());
|
||||
|
||||
if (PyDict_SetItem(memo, self, dupe) != 0) {
|
||||
Py_DECREF(dupe);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return dupe;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::count_num_descendants
|
||||
// Access: Published
|
||||
@ -2597,6 +2665,32 @@ is_ambient_light() const {
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::decode_from_bam_stream
|
||||
// Access: Published, Static
|
||||
// Description: Reads the string created by a previous call to
|
||||
// encode_to_bam_stream(), and extracts and returns the
|
||||
// single object on that string. Returns NULL on error.
|
||||
//
|
||||
// This method is intended to replace
|
||||
// decode_raw_from_bam_stream() when you know the stream
|
||||
// in question returns an object of type PandaNode,
|
||||
// allowing for easier reference count management. Note
|
||||
// that the caller is still responsible for maintaining
|
||||
// the reference count on the return value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(PandaNode) PandaNode::
|
||||
decode_from_bam_stream(const string &data) {
|
||||
TypedWritable *object;
|
||||
ReferenceCount *ref_ptr;
|
||||
|
||||
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return DCAST(PandaNode, object);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: PandaNode::get_internal_bounds
|
||||
// Access: Protected
|
||||
|
@ -84,7 +84,6 @@ private:
|
||||
|
||||
public:
|
||||
virtual ReferenceCount *as_reference_count();
|
||||
virtual PandaNode *make_copy() const;
|
||||
virtual PandaNode *dupe_for_flatten() const;
|
||||
|
||||
virtual bool safe_to_flatten() const;
|
||||
@ -116,8 +115,14 @@ public:
|
||||
virtual void add_for_draw(CullTraverser *trav, CullTraverserData &data);
|
||||
|
||||
PUBLISHED:
|
||||
virtual PandaNode *make_copy() const;
|
||||
PT(PandaNode) copy_subgraph(Thread *current_thread = Thread::get_current_thread()) const;
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PT(PandaNode) __copy__() const;
|
||||
PyObject *__deepcopy__(PyObject *self, PyObject *memo) const;
|
||||
#endif
|
||||
|
||||
INLINE int get_num_parents(Thread *current_thread = Thread::get_current_thread()) const;
|
||||
INLINE PandaNode *get_parent(int n, Thread *current_thread = Thread::get_current_thread()) const;
|
||||
INLINE int find_parent(PandaNode *node, Thread *current_thread = Thread::get_current_thread()) const;
|
||||
@ -300,6 +305,10 @@ PUBLISHED:
|
||||
};
|
||||
INLINE int get_fancy_bits(Thread *current_thread = Thread::get_current_thread()) const;
|
||||
|
||||
|
||||
PUBLISHED:
|
||||
static PT(PandaNode) decode_from_bam_stream(const string &data);
|
||||
|
||||
protected:
|
||||
class BoundsData;
|
||||
|
||||
|
@ -66,3 +66,28 @@ INLINE UpdateSeq TypedWritable::
|
||||
get_bam_modified() const {
|
||||
return _bam_modified;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritable::encode_to_bam_stream
|
||||
// Access: Published
|
||||
// Description: Converts the TypedWritable object into a single
|
||||
// stream of data using a BamWriter, and returns that
|
||||
// data as a string string. Returns empty string on
|
||||
// failure.
|
||||
//
|
||||
// This is a convenience method particularly useful for
|
||||
// cases when you are only serializing a single object.
|
||||
// If you have many objects to process, it is more
|
||||
// efficient to use the same BamWriter to serialize all
|
||||
// of them together.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
string TypedWritable::
|
||||
encode_to_bam_stream() const {
|
||||
string data;
|
||||
if (!encode_to_bam_stream(data)) {
|
||||
return string();
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -14,7 +14,11 @@
|
||||
|
||||
#include "typedWritable.h"
|
||||
#include "bamWriter.h"
|
||||
#include "bamReader.h"
|
||||
#include "datagramOutputFile.h"
|
||||
#include "datagramInputFile.h"
|
||||
#include "lightMutexHolder.h"
|
||||
#include "bam.h"
|
||||
|
||||
LightMutex TypedWritable::_bam_writers_lock;
|
||||
|
||||
@ -144,3 +148,276 @@ ReferenceCount *TypedWritable::
|
||||
as_reference_count() {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritable::__reduce__
|
||||
// Access: Published
|
||||
// Description: This special Python method is implement to provide
|
||||
// support for the pickle module.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *TypedWritable::
|
||||
__reduce__(PyObject *self) const {
|
||||
// We should return at least a 2-tuple, (Class, (args)): the
|
||||
// necessary class object whose constructor we should call
|
||||
// (e.g. this), and the arguments necessary to reconstruct this
|
||||
// object.
|
||||
|
||||
// Check that we have a decodeFromBamStream python method. If not,
|
||||
// we can't use this interface.
|
||||
PyObject *method = PyObject_GetAttrString(self, "decodeFromBamStream");
|
||||
if (method == NULL) {
|
||||
ostringstream stream;
|
||||
stream << "Cannot pickle objects of type " << get_type() << "\n";
|
||||
string message = stream.str();
|
||||
PyErr_SetString(PyExc_TypeError, message.c_str());
|
||||
return NULL;
|
||||
}
|
||||
Py_DECREF(method);
|
||||
|
||||
// First, streamify the object, if possible.
|
||||
string bam_stream;
|
||||
if (!encode_to_bam_stream(bam_stream)) {
|
||||
ostringstream stream;
|
||||
stream << "Could not bamify object of type " << get_type() << "\n";
|
||||
string message = stream.str();
|
||||
PyErr_SetString(PyExc_TypeError, message.c_str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Start by getting this class object.
|
||||
PyObject *this_class = PyObject_Type(self);
|
||||
if (this_class == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *func = find_global_decode(this_class, "pyDecodeTypedWritableFromBamStream");
|
||||
if (func == NULL) {
|
||||
PyErr_SetString(PyExc_TypeError, "Couldn't find pyDecodeTypedWritableFromBamStream()");
|
||||
Py_DECREF(this_class);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = Py_BuildValue("(O(Os#))", func, this_class, bam_stream.data(), bam_stream.size());
|
||||
Py_DECREF(func);
|
||||
Py_DECREF(this_class);
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritable::encode_to_bam_stream
|
||||
// Access: Published
|
||||
// Description: Converts the TypedWritable object into a single
|
||||
// stream of data using a BamWriter, and stores that
|
||||
// data in the indicated string. Returns true on
|
||||
// success, false on failure.
|
||||
//
|
||||
// This is a convenience method particularly useful for
|
||||
// cases when you are only serializing a single object.
|
||||
// If you have many objects to process, it is more
|
||||
// efficient to use the same BamWriter to serialize all
|
||||
// of them together.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TypedWritable::
|
||||
encode_to_bam_stream(string &data) const {
|
||||
data.clear();
|
||||
ostringstream stream;
|
||||
|
||||
// We use nested scoping to ensure the destructors get called in the
|
||||
// right order.
|
||||
{
|
||||
DatagramOutputFile dout;
|
||||
if (!dout.open(stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dout.write_header(_bam_header)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
{
|
||||
BamWriter writer(&dout, "bam_stream");
|
||||
if (!writer.init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!writer.write_object(this)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
data = stream.str();
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritable::decode_raw_from_bam_stream
|
||||
// Access: Published, Static
|
||||
// Description: Reads the string created by a previous call to
|
||||
// encode_to_bam_stream(), and extracts the single
|
||||
// object on that string. Returns true on success,
|
||||
// false on on error.
|
||||
//
|
||||
// This variant sets the TypedWritable and
|
||||
// ReferenceCount pointers separately; both are pointers
|
||||
// to the same object. The reference count is not
|
||||
// incremented; it is the caller's responsibility to
|
||||
// manage the reference count.
|
||||
//
|
||||
// Note that this method cannot be used to retrieve
|
||||
// objects that do not inherit from ReferenceCount,
|
||||
// because these objects cannot persist beyond the
|
||||
// lifetime of the BamReader that reads them. To
|
||||
// retrieve these objects from a bam stream, you must
|
||||
// construct a BamReader directly.
|
||||
//
|
||||
// If you happen to know that the particular object in
|
||||
// question inherits from TypedWritableReferenceCount or
|
||||
// PandaNode, consider calling the variant of
|
||||
// decode_from_bam_stream() defined for those methods,
|
||||
// which presents a simpler interface.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool TypedWritable::
|
||||
decode_raw_from_bam_stream(TypedWritable *&ptr, ReferenceCount *&ref_ptr,
|
||||
const string &data) {
|
||||
istringstream stream(data);
|
||||
|
||||
DatagramInputFile din;
|
||||
if (!din.open(stream)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
string head;
|
||||
if (!din.read_header(head, _bam_header.size())) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (head != _bam_header) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// We scope this so we can control when the BamReader destructs.
|
||||
{
|
||||
BamReader reader(&din, "bam_stream");
|
||||
if (!reader.init()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader.read_object(ptr, ref_ptr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reader.resolve()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ref_ptr == NULL) {
|
||||
// Can't support non-reference-counted objects.
|
||||
return false;
|
||||
}
|
||||
|
||||
// Protect the pointer from accidental deletion when the BamReader
|
||||
// goes away.
|
||||
ref_ptr->ref();
|
||||
}
|
||||
|
||||
// Now decrement the ref count, without deleting the object. This
|
||||
// may reduce the reference count to zero, but that's OK--we trust
|
||||
// the caller to manage the reference count from this point on.
|
||||
ref_ptr->unref();
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritable::find_global_decode
|
||||
// Access: Public, Static
|
||||
// Description: This is a support function for __reduce__(). It
|
||||
// searches for the global function
|
||||
// pyDecodeTypedWritableFromBamStream() in this class's
|
||||
// module, or in the module for any base class. (It's
|
||||
// really looking for the libpanda module, but we can't
|
||||
// be sure what name that module was loaded under, so we
|
||||
// search upwards this way.)
|
||||
//
|
||||
// Returns: new reference on success, or NULL on failure.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *TypedWritable::
|
||||
find_global_decode(PyObject *this_class, const char *func_name) {
|
||||
PyObject *module_name = PyObject_GetAttrString(this_class, "__module__");
|
||||
if (module_name != NULL) {
|
||||
// borrowed reference
|
||||
PyObject *sys_modules = PyImport_GetModuleDict();
|
||||
if (sys_modules != NULL) {
|
||||
// borrowed reference
|
||||
PyObject *module = PyDict_GetItem(sys_modules, module_name);
|
||||
if (module != NULL){
|
||||
PyObject *func = PyObject_GetAttrString(module, func_name);
|
||||
if (func != NULL) {
|
||||
Py_DECREF(module_name);
|
||||
return func;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_DECREF(module_name);
|
||||
|
||||
PyObject *bases = PyObject_GetAttrString(this_class, "__bases__");
|
||||
if (bases != NULL) {
|
||||
if (PySequence_Check(bases)) {
|
||||
Py_ssize_t size = PySequence_Size(bases);
|
||||
for (Py_ssize_t i = 0; i < size; ++i) {
|
||||
PyObject *base = PySequence_GetItem(bases, i);
|
||||
if (base != NULL) {
|
||||
PyObject *func = find_global_decode(base, func_name);
|
||||
Py_DECREF(base);
|
||||
if (func != NULL) {
|
||||
Py_DECREF(bases);
|
||||
return func;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_DECREF(bases);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: py_decode_TypedWritable_from_bam_stream
|
||||
// Access: Published
|
||||
// Description: This wrapper is defined as a global function to suit
|
||||
// pickle's needs.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PyObject *
|
||||
py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data) {
|
||||
// We need the function TypedWritable::decode_from_bam_stream, which
|
||||
// invokes the BamReader to reconstruct this object. Since we use
|
||||
// the specific object's class as the pointer, we get the particular
|
||||
// instance of decode_from_bam_stream appropriate to this class.
|
||||
|
||||
PyObject *func = PyObject_GetAttrString(this_class, "decodeFromBamStream");
|
||||
if (func == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PyObject *result = PyObject_CallFunction(func, (char *)"(s#)", data.data(), data.size());
|
||||
if (result == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (result == Py_None) {
|
||||
Py_DECREF(result);
|
||||
PyErr_SetString(PyExc_ValueError, "Could not unpack bam stream");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
|
@ -60,6 +60,21 @@ PUBLISHED:
|
||||
INLINE void mark_bam_modified();
|
||||
INLINE UpdateSeq get_bam_modified() const;
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
PyObject *__reduce__(PyObject *self) const;
|
||||
#endif
|
||||
|
||||
INLINE string encode_to_bam_stream() const;
|
||||
bool encode_to_bam_stream(string &data) const;
|
||||
static bool decode_raw_from_bam_stream(TypedWritable *&ptr,
|
||||
ReferenceCount *&ref_ptr,
|
||||
const string &data);
|
||||
|
||||
public:
|
||||
#ifdef HAVE_PYTHON
|
||||
static PyObject *find_global_decode(PyObject *this_class, const char *func_name);
|
||||
#endif
|
||||
|
||||
private:
|
||||
// We may need to store a list of the BamWriter(s) that have a
|
||||
// reference to this object, so that we can remove the object from
|
||||
@ -70,12 +85,10 @@ private:
|
||||
|
||||
UpdateSeq _bam_modified;
|
||||
|
||||
PUBLISHED:
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
|
||||
public:
|
||||
static void init_type() {
|
||||
TypedObject::init_type();
|
||||
register_type(_type_handle, "TypedWritable",
|
||||
@ -96,6 +109,12 @@ private:
|
||||
friend class BamWriter;
|
||||
};
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
BEGIN_PUBLISH
|
||||
PyObject *py_decode_TypedWritable_from_bam_stream(PyObject *this_class, const string &data);
|
||||
END_PUBLISH
|
||||
#endif
|
||||
|
||||
#include "typedWritable.I"
|
||||
|
||||
#endif
|
||||
|
@ -26,3 +26,30 @@ ReferenceCount *TypedWritableReferenceCount::
|
||||
as_reference_count() {
|
||||
return this;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TypedWritableReferenceCount::decode_from_bam_stream
|
||||
// Access: Published, Static
|
||||
// Description: Reads the string created by a previous call to
|
||||
// encode_to_bam_stream(), and extracts and returns the
|
||||
// single object on that string. Returns NULL on error.
|
||||
//
|
||||
// This method is intended to replace
|
||||
// decode_raw_from_bam_stream() when you know the stream
|
||||
// in question returns an object of type
|
||||
// TypedWritableReferenceCount, allowing for easier
|
||||
// reference count management. Note that the caller is
|
||||
// still responsible for maintaining the reference count
|
||||
// on the return value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(TypedWritableReferenceCount) TypedWritableReferenceCount::
|
||||
decode_from_bam_stream(const string &data) {
|
||||
TypedWritable *object;
|
||||
ReferenceCount *ref_ptr;
|
||||
|
||||
if (!TypedWritable::decode_raw_from_bam_stream(object, ref_ptr, data)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return DCAST(TypedWritableReferenceCount, object);
|
||||
}
|
||||
|
@ -40,18 +40,17 @@ public:
|
||||
|
||||
virtual ReferenceCount *as_reference_count();
|
||||
|
||||
PUBLISHED:
|
||||
static PT(TypedWritableReferenceCount) decode_from_bam_stream(const string &data);
|
||||
|
||||
public:
|
||||
virtual TypeHandle get_type() const {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
|
||||
|
||||
PUBLISHED:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
|
||||
public:
|
||||
static void init_type() {
|
||||
TypedWritable::init_type();
|
||||
ReferenceCount::init_type();
|
||||
|
Loading…
x
Reference in New Issue
Block a user