mirror of
https://github.com/panda3d/panda3d.git
synced 2025-09-30 16:58:40 -04:00
Support defining bam factory functions in Python
This commit is contained in:
parent
12af395012
commit
33ed30b178
@ -39,11 +39,25 @@ public:
|
||||
typedef vector<Type, allocator> base_class;
|
||||
typedef TYPENAME base_class::size_type size_type;
|
||||
|
||||
pvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator(type_handle)) { }
|
||||
explicit pvector(TypeHandle type_handle = pvector_type_handle) : base_class(allocator(type_handle)) { }
|
||||
pvector(const pvector<Type> ©) : base_class(copy) { }
|
||||
pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { }
|
||||
pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { }
|
||||
explicit pvector(size_type n, TypeHandle type_handle = pvector_type_handle) : base_class(n, Type(), allocator(type_handle)) { }
|
||||
explicit pvector(size_type n, const Type &value, TypeHandle type_handle = pvector_type_handle) : base_class(n, value, allocator(type_handle)) { }
|
||||
pvector(const Type *begin, const Type *end, TypeHandle type_handle = pvector_type_handle) : base_class(begin, end, allocator(type_handle)) { }
|
||||
|
||||
#ifdef USE_MOVE_SEMANTICS
|
||||
pvector(pvector<Type> &&from) NOEXCEPT : base_class(move(from)) {};
|
||||
|
||||
pvector<Type> &operator =(pvector<Type> &&from) NOEXCEPT {
|
||||
base_class::operator =(move(from));
|
||||
return *this;
|
||||
}
|
||||
#endif
|
||||
|
||||
pvector<Type> &operator =(const pvector<Type> ©) {
|
||||
base_class::operator =(copy);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // USE_STL_ALLOCATOR
|
||||
|
@ -37,14 +37,15 @@ class EXPCL_DTOOL TypeRegistry : public MemoryBase {
|
||||
public:
|
||||
// User code shouldn't generally need to call TypeRegistry::register_type()
|
||||
// or record_derivation() directly; instead, use the register_type
|
||||
// convenience function, defined below.
|
||||
// convenience function, defined in register_type.h.
|
||||
bool register_type(TypeHandle &type_handle, const string &name);
|
||||
|
||||
PUBLISHED:
|
||||
TypeHandle register_dynamic_type(const string &name);
|
||||
|
||||
void record_derivation(TypeHandle child, TypeHandle parent);
|
||||
void record_alternate_name(TypeHandle type, const string &name);
|
||||
|
||||
PUBLISHED:
|
||||
TypeHandle find_type(const string &name) const;
|
||||
TypeHandle find_type_by_id(int id) const;
|
||||
|
||||
|
@ -3407,8 +3407,7 @@ if (not RUNTIME):
|
||||
TargetAdd('libp3putil.in', opts=OPTS, input=IGATEFILES)
|
||||
TargetAdd('libp3putil.in', opts=['IMOD:panda3d.core', 'ILIB:libp3putil', 'SRCDIR:panda/src/putil'])
|
||||
TargetAdd('libp3putil_igate.obj', input='libp3putil.in', opts=["DEPENDENCYONLY"])
|
||||
TargetAdd('p3putil_typedWritable_ext.obj', opts=OPTS, input='typedWritable_ext.cxx')
|
||||
TargetAdd('p3putil_pythonCallbackObject.obj', opts=OPTS, input='pythonCallbackObject.cxx')
|
||||
TargetAdd('p3putil_ext_composite.obj', opts=OPTS, input='p3putil_ext_composite.cxx')
|
||||
|
||||
#
|
||||
# DIRECTORY: panda/src/audio/
|
||||
@ -4009,8 +4008,7 @@ if (not RUNTIME):
|
||||
if PkgSkip("FREETYPE")==0:
|
||||
TargetAdd('core.pyd', input="libp3pnmtext_igate.obj")
|
||||
|
||||
TargetAdd('core.pyd', input='p3putil_typedWritable_ext.obj')
|
||||
TargetAdd('core.pyd', input='p3putil_pythonCallbackObject.obj')
|
||||
TargetAdd('core.pyd', input='p3putil_ext_composite.obj')
|
||||
TargetAdd('core.pyd', input='p3pnmimage_pfmFile_ext.obj')
|
||||
TargetAdd('core.pyd', input='p3event_pythonTask.obj')
|
||||
TargetAdd('core.pyd', input='p3gobj_ext_composite.obj')
|
||||
|
@ -159,6 +159,17 @@ get_file_pos() {
|
||||
return _source->get_file_pos();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a factory function that is called when an object of the given
|
||||
* type is encountered within the .bam stream.
|
||||
*
|
||||
* @param user_data an optional pointer to be passed along to the function.
|
||||
*/
|
||||
void BamReader::
|
||||
register_factory(TypeHandle handle, WritableFactory::CreateFunc *func, void *user_data) {
|
||||
get_factory()->register_factory(handle, func, user_data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the global WritableFactory for generating TypedWritable objects
|
||||
*/
|
||||
|
@ -148,11 +148,14 @@ PUBLISHED:
|
||||
INLINE int get_current_major_ver() const;
|
||||
INLINE int get_current_minor_ver() const;
|
||||
|
||||
EXTENSION(PyObject *get_file_version() const);
|
||||
|
||||
PUBLISHED:
|
||||
MAKE_PROPERTY(source, get_source, set_source);
|
||||
MAKE_PROPERTY(filename, get_filename);
|
||||
MAKE_PROPERTY(loader_options, get_loader_options, set_loader_options);
|
||||
|
||||
MAKE_PROPERTY(file_version, get_file_version);
|
||||
MAKE_PROPERTY(file_endian, get_file_endian);
|
||||
MAKE_PROPERTY(file_stdfloat_double, get_file_stdfloat_double);
|
||||
|
||||
@ -194,7 +197,13 @@ public:
|
||||
INLINE streampos get_file_pos();
|
||||
|
||||
public:
|
||||
INLINE static void register_factory(TypeHandle type, WritableFactory::CreateFunc *func,
|
||||
void *user_data = NULL);
|
||||
INLINE static WritableFactory *get_factory();
|
||||
|
||||
PUBLISHED:
|
||||
EXTENSION(static void register_factory(TypeHandle handle, PyObject *func));
|
||||
|
||||
private:
|
||||
INLINE static void create_factory();
|
||||
|
||||
|
123
panda/src/putil/bamReader_ext.cxx
Normal file
123
panda/src/putil/bamReader_ext.cxx
Normal file
@ -0,0 +1,123 @@
|
||||
/**
|
||||
* 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 bamReader_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2016-04-09
|
||||
*/
|
||||
|
||||
#include "bamReader_ext.h"
|
||||
#include "config_util.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#ifndef CPPPARSER
|
||||
extern Dtool_PyTypedObject Dtool_BamReader;
|
||||
extern Dtool_PyTypedObject Dtool_DatagramIterator;
|
||||
extern Dtool_PyTypedObject Dtool_TypedWritable;
|
||||
#endif // CPPPARSER
|
||||
|
||||
/**
|
||||
* Factory function that calls the registered Python function.
|
||||
*/
|
||||
static TypedWritable *factory_callback(const FactoryParams ¶ms){
|
||||
PyObject *func = (PyObject *)params.get_user_data();
|
||||
nassertr(func != NULL, NULL);
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
// Use PyGILState to protect this asynchronous call.
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
#endif
|
||||
|
||||
// Extract the parameters we will pass to the Python function.
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
parse_params(params, scan, manager);
|
||||
|
||||
PyObject *py_scan = DTool_CreatePyInstance(&scan, Dtool_DatagramIterator, false, false);
|
||||
PyObject *py_manager = DTool_CreatePyInstance(manager, Dtool_BamReader, false, false);
|
||||
PyObject *args = PyTuple_Pack(2, py_scan, py_manager);
|
||||
|
||||
// Now call the Python function.
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
PyObject *result = current_thread->call_python_func(func, args);
|
||||
Py_DECREF(args);
|
||||
Py_DECREF(py_scan);
|
||||
Py_DECREF(py_manager);
|
||||
|
||||
if (result == (PyObject *)NULL) {
|
||||
util_cat.error()
|
||||
<< "Exception occurred in Python factory function\n";
|
||||
|
||||
} else if (result == Py_None) {
|
||||
util_cat.error()
|
||||
<< "Python factory function returned None\n";
|
||||
Py_DECREF(result);
|
||||
result = NULL;
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
|
||||
// Unwrap the returned TypedWritable object.
|
||||
if (result == (PyObject *)NULL) {
|
||||
return (TypedWritable *)NULL;
|
||||
} else {
|
||||
void *object = NULL;
|
||||
Dtool_Call_ExtractThisPointer(result, Dtool_TypedWritable, &object);
|
||||
|
||||
TypedWritable *ptr = (TypedWritable *)object;
|
||||
ReferenceCount *ref_count = ptr->as_reference_count();
|
||||
if (ref_count != NULL) {
|
||||
// If the Python pointer is the last reference to it, make sure that the
|
||||
// object isn't destroyed. We do this by calling unref(), which
|
||||
// decreases the reference count without destroying the object.
|
||||
if (result->ob_refcnt <= 1) {
|
||||
ref_count->unref();
|
||||
|
||||
// Tell the Python wrapper object that it shouldn't try to delete the
|
||||
// object when it is destroyed.
|
||||
((Dtool_PyInstDef *)result)->_memory_rules = false;
|
||||
}
|
||||
Py_DECREF(result);
|
||||
}
|
||||
|
||||
return (TypedWritable *)object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the version number of the Bam file currently being read.
|
||||
*/
|
||||
PyObject *Extension<BamReader>::
|
||||
get_file_version() const {
|
||||
return Py_BuildValue("(ii)", _this->get_file_major_ver(),
|
||||
_this->get_file_minor_ver());
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a Python function as factory function for the given type. This
|
||||
* should be a function (or class object) that takes a DatagramIterator and a
|
||||
* BamReader as arguments, and should return a TypedWritable object.
|
||||
*/
|
||||
void Extension<BamReader>::
|
||||
register_factory(TypeHandle handle, PyObject *func) {
|
||||
nassertv(func != NULL);
|
||||
|
||||
if (!PyCallable_Check(func)) {
|
||||
Dtool_Raise_TypeError("second argument to register_factory must be callable");
|
||||
return;
|
||||
}
|
||||
|
||||
Py_INCREF(func);
|
||||
BamReader::get_factory()->register_factory(handle, &factory_callback, (void *)func);
|
||||
}
|
||||
|
||||
#endif
|
39
panda/src/putil/bamReader_ext.h
Normal file
39
panda/src/putil/bamReader_ext.h
Normal file
@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 bamReader_ext.h
|
||||
* @author rdb
|
||||
* @date 2016-04-09
|
||||
*/
|
||||
|
||||
#ifndef BAMREADER_EXT_H
|
||||
#define BAMREADER_EXT_H
|
||||
|
||||
#include "dtoolbase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "bamReader.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for BamReader, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<BamReader> : public ExtensionBase<BamReader> {
|
||||
public:
|
||||
PyObject *get_file_version() const;
|
||||
|
||||
static void register_factory(TypeHandle handle, PyObject *func);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif // BAMREADER_EXT_H
|
@ -70,6 +70,6 @@ make_instance_more_general(const string &type_name,
|
||||
*/
|
||||
template<class Type>
|
||||
INLINE void Factory<Type>::
|
||||
register_factory(TypeHandle handle, CreateFunc *func) {
|
||||
FactoryBase::register_factory(handle, (BaseCreateFunc *)func);
|
||||
register_factory(TypeHandle handle, CreateFunc *func, void *user_data) {
|
||||
FactoryBase::register_factory(handle, (BaseCreateFunc *)func, user_data);
|
||||
}
|
||||
|
@ -49,7 +49,8 @@ public:
|
||||
make_instance_more_general(const string &type_name,
|
||||
const FactoryParams ¶ms = FactoryParams());
|
||||
|
||||
INLINE void register_factory(TypeHandle handle, CreateFunc *func);
|
||||
INLINE void register_factory(TypeHandle handle, CreateFunc *func,
|
||||
void *user_data = NULL);
|
||||
};
|
||||
|
||||
#include "factory.I"
|
||||
|
@ -128,12 +128,18 @@ find_registered_type(TypeHandle handle) {
|
||||
|
||||
/**
|
||||
* Registers a new kind of thing the Factory will be able to create.
|
||||
*
|
||||
* @param user_data an optional pointer to be passed along to the function.
|
||||
*/
|
||||
void FactoryBase::
|
||||
register_factory(TypeHandle handle, BaseCreateFunc *func) {
|
||||
register_factory(TypeHandle handle, BaseCreateFunc *func, void *user_data) {
|
||||
nassertv(handle != TypeHandle::none());
|
||||
nassertv(func != (BaseCreateFunc *)NULL);
|
||||
_creators[handle] = func;
|
||||
|
||||
Creator creator;
|
||||
creator._func = func;
|
||||
creator._user_data = user_data;
|
||||
_creators[handle] = creator;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -234,15 +240,16 @@ operator = (const FactoryBase &) {
|
||||
* not be created.
|
||||
*/
|
||||
TypedObject *FactoryBase::
|
||||
make_instance_exact(TypeHandle handle, const FactoryParams ¶ms) {
|
||||
make_instance_exact(TypeHandle handle, FactoryParams params) {
|
||||
Creators::const_iterator ci = _creators.find(handle);
|
||||
if (ci == _creators.end()) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BaseCreateFunc *func = (BaseCreateFunc *)((*ci).second);
|
||||
nassertr(func != (BaseCreateFunc *)NULL, NULL);
|
||||
return (*func)(params);
|
||||
Creator creator = (*ci).second;
|
||||
nassertr(creator._func != (BaseCreateFunc *)NULL, NULL);
|
||||
params._user_data = creator._user_data;
|
||||
return (*creator._func)(params);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -251,7 +258,7 @@ make_instance_exact(TypeHandle handle, const FactoryParams ¶ms) {
|
||||
* instance could not be created.
|
||||
*/
|
||||
TypedObject *FactoryBase::
|
||||
make_instance_more_specific(TypeHandle handle, const FactoryParams ¶ms) {
|
||||
make_instance_more_specific(TypeHandle handle, FactoryParams params) {
|
||||
// First, walk through the established preferred list. Maybe one of these
|
||||
// qualifies.
|
||||
|
||||
@ -272,9 +279,10 @@ make_instance_more_specific(TypeHandle handle, const FactoryParams ¶ms) {
|
||||
for (ci = _creators.begin(); ci != _creators.end(); ++ci) {
|
||||
TypeHandle ctype = (*ci).first;
|
||||
if (ctype.is_derived_from(handle)) {
|
||||
BaseCreateFunc *func = (BaseCreateFunc *)((*ci).second);
|
||||
nassertr(func != (BaseCreateFunc *)NULL, NULL);
|
||||
TypedObject *object = (*func)(params);
|
||||
Creator creator = (*ci).second;
|
||||
nassertr(creator._func != (BaseCreateFunc *)NULL, NULL);
|
||||
params._user_data = creator._user_data;
|
||||
TypedObject *object = (*creator._func)(params);
|
||||
if (object != (TypedObject *)NULL) {
|
||||
return object;
|
||||
}
|
||||
|
@ -56,7 +56,7 @@ public:
|
||||
|
||||
TypeHandle find_registered_type(TypeHandle handle);
|
||||
|
||||
void register_factory(TypeHandle handle, BaseCreateFunc *func);
|
||||
void register_factory(TypeHandle handle, BaseCreateFunc *func, void *user_data = NULL);
|
||||
|
||||
int get_num_types() const;
|
||||
TypeHandle get_type(int n) const;
|
||||
@ -74,22 +74,18 @@ private:
|
||||
void operator = (const FactoryBase ©);
|
||||
|
||||
// internal utility functions
|
||||
TypedObject *make_instance_exact(TypeHandle handle,
|
||||
const FactoryParams ¶ms);
|
||||
TypedObject *make_instance_exact(TypeHandle handle, FactoryParams params);
|
||||
TypedObject *make_instance_more_specific(TypeHandle handle,
|
||||
const FactoryParams ¶ms);
|
||||
FactoryParams params);
|
||||
|
||||
private:
|
||||
// internal mechanics and bookkeeping
|
||||
struct Creator {
|
||||
BaseCreateFunc *_func;
|
||||
void *_user_data;
|
||||
};
|
||||
|
||||
#if (defined(WIN32_VC) || defined(WIN64_VC)) && !defined(__ICL) //__ICL is Intel C++
|
||||
// Visual C++ seems to have a problem with building a map based on
|
||||
// BaseCreateFunc. We'll have to typecast it on the way out.
|
||||
typedef pmap<TypeHandle, void *> Creators;
|
||||
#else
|
||||
typedef pmap<TypeHandle, BaseCreateFunc *> Creators;
|
||||
#endif
|
||||
|
||||
typedef pmap<TypeHandle, Creator> Creators;
|
||||
Creators _creators;
|
||||
|
||||
typedef pvector<TypeHandle> Preferred;
|
||||
|
@ -13,6 +13,54 @@
|
||||
|
||||
#include "pnotify.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE FactoryParams::
|
||||
FactoryParams() : _user_data(NULL) {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE FactoryParams::
|
||||
FactoryParams(const FactoryParams ©) :
|
||||
_params(copy._params),
|
||||
_user_data(copy._user_data) {}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE FactoryParams::
|
||||
~FactoryParams() {
|
||||
}
|
||||
|
||||
#ifdef USE_MOVE_SEMANTICS
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE FactoryParams::
|
||||
FactoryParams(FactoryParams &&from) NOEXCEPT :
|
||||
_params(move(from._params)),
|
||||
_user_data(from._user_data) {}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
INLINE void FactoryParams::
|
||||
operator = (FactoryParams &&from) NOEXCEPT {
|
||||
_params = move(from._params);
|
||||
_user_data = from._user_data;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the custom pointer that was associated with the factory function.
|
||||
*/
|
||||
INLINE void *FactoryParams::
|
||||
get_user_data() const {
|
||||
return _user_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* A handy convenience template function that extracts a parameter of the
|
||||
|
@ -13,20 +13,6 @@
|
||||
|
||||
#include "factoryParams.h"
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FactoryParams::
|
||||
FactoryParams() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
FactoryParams::
|
||||
~FactoryParams() {
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
|
@ -35,8 +35,14 @@
|
||||
*/
|
||||
class EXPCL_PANDA_PUTIL FactoryParams {
|
||||
public:
|
||||
FactoryParams();
|
||||
~FactoryParams();
|
||||
INLINE FactoryParams();
|
||||
INLINE FactoryParams(const FactoryParams ©);
|
||||
INLINE ~FactoryParams();
|
||||
|
||||
#ifdef USE_MOVE_SEMANTICS
|
||||
INLINE FactoryParams(FactoryParams &&from) NOEXCEPT;
|
||||
INLINE void operator = (FactoryParams &&from) NOEXCEPT;
|
||||
#endif
|
||||
|
||||
void add_param(FactoryParam *param);
|
||||
void clear();
|
||||
@ -46,10 +52,15 @@ public:
|
||||
|
||||
FactoryParam *get_param_of_type(TypeHandle type) const;
|
||||
|
||||
INLINE void *get_user_data() const;
|
||||
|
||||
private:
|
||||
typedef pvector< PT(TypedReferenceCount) > Params;
|
||||
|
||||
Params _params;
|
||||
void *_user_data;
|
||||
|
||||
friend class FactoryBase;
|
||||
};
|
||||
|
||||
template<class ParamType>
|
||||
|
3
panda/src/putil/p3putil_ext_composite.cxx
Normal file
3
panda/src/putil/p3putil_ext_composite.cxx
Normal file
@ -0,0 +1,3 @@
|
||||
#include "bamReader_ext.cxx"
|
||||
#include "pythonCallbackObject.cxx"
|
||||
#include "typedWritable_ext.cxx"
|
@ -47,7 +47,10 @@ public:
|
||||
virtual int complete_pointers(TypedWritable **p_list, BamReader *manager);
|
||||
virtual bool require_fully_complete() const;
|
||||
|
||||
PUBLISHED:
|
||||
virtual void fillin(DatagramIterator &scan, BamReader *manager);
|
||||
|
||||
public:
|
||||
virtual void finalize(BamReader *manager);
|
||||
|
||||
virtual ReferenceCount *as_reference_count();
|
||||
|
Loading…
x
Reference in New Issue
Block a user