23 extern struct Dtool_PyTypedObject Dtool_BamCacheRecord;
24 extern struct Dtool_PyTypedObject Dtool_Filename;
25 extern struct Dtool_PyTypedObject Dtool_LoaderOptions;
26 extern struct Dtool_PyTypedObject Dtool_PandaNode;
27 extern struct Dtool_PyTypedObject Dtool_PythonLoaderFileType;
34 PythonLoaderFileType::
35 PythonLoaderFileType() {
43 PythonLoaderFileType::
44 PythonLoaderFileType(std::string extension, PyObject *entry_point) :
45 _extension(std::move(extension)),
46 _entry_point(entry_point) {
49 Py_INCREF(entry_point);
55 PythonLoaderFileType::
56 ~PythonLoaderFileType() {
57 if (_entry_point !=
nullptr || _load_func !=
nullptr || _save_func !=
nullptr) {
58 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
59 PyGILState_STATE gstate;
60 gstate = PyGILState_Ensure();
63 Py_CLEAR(_entry_point);
67 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
68 PyGILState_Release(gstate);
76 bool PythonLoaderFileType::
77 init(PyObject *loader) {
78 nassertr(loader !=
nullptr,
false);
79 nassertr(_load_func ==
nullptr,
false);
80 nassertr(_save_func ==
nullptr,
false);
84 PyObject *extensions = PyObject_GetAttrString(loader,
"extensions");
85 if (extensions !=
nullptr) {
86 if (PyUnicode_Check(extensions)
87 #
if PY_MAJOR_VERSION < 3
88 || PyString_Check(extensions)
91 Dtool_Raise_TypeError(
"extensions list should be a list or tuple");
92 Py_DECREF(extensions);
96 PyObject *sequence = PySequence_Fast(extensions,
"extensions must be a sequence");
97 PyObject **items = PySequence_Fast_ITEMS(sequence);
98 Py_ssize_t num_items = PySequence_Fast_GET_SIZE(sequence);
99 Py_DECREF(extensions);
101 if (num_items == 0) {
102 PyErr_SetString(PyExc_ValueError,
"extensions list may not be empty");
107 bool found_extension =
false;
109 for (Py_ssize_t i = 0; i < num_items; ++i) {
110 PyObject *extension = items[i];
111 const char *extension_str;
112 Py_ssize_t extension_len;
113 #if PY_MAJOR_VERSION >= 3
114 extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len);
116 if (PyString_AsStringAndSize(extension, (
char **)&extension_str, &extension_len) == -1) {
117 extension_str =
nullptr;
121 if (extension_str ==
nullptr) {
126 if (_extension.empty()) {
127 _extension.assign(extension_str, extension_len);
128 found_extension =
true;
130 std::string new_extension(extension_str, extension_len);
131 if (_extension == new_extension) {
132 found_extension =
true;
134 if (!_additional_extensions.empty()) {
135 _additional_extensions +=
' ';
137 _additional_extensions += new_extension;
143 if (!found_extension) {
144 PyObject *repr = PyObject_Repr(loader);
146 <<
"Registered extension '" << _extension
147 <<
"' does not occur in extensions list of "
148 #if PY_MAJOR_VERSION >= 3
149 << PyUnicode_AsUTF8(repr) <<
"\n";
151 << PyString_AsString(repr) <<
"\n";
160 PyObject *supports_compressed = PyObject_GetAttrString(loader,
"supports_compressed");
161 if (supports_compressed !=
nullptr) {
162 if (supports_compressed == Py_True) {
163 _supports_compressed =
true;
165 else if (supports_compressed == Py_False) {
166 _supports_compressed =
false;
169 Dtool_Raise_TypeError(
"supports_compressed must be a bool");
170 Py_DECREF(supports_compressed);
173 Py_DECREF(supports_compressed);
176 _load_func = PyObject_GetAttrString(loader,
"load_file");
177 _save_func = PyObject_GetAttrString(loader,
"save_file");
180 if (_load_func ==
nullptr && _save_func ==
nullptr) {
181 #if PY_MAJOR_VERSION >= 3
182 PyErr_Format(PyExc_TypeError,
183 "loader plug-in %R does not define load_file or save_file function",
186 PyObject *repr = PyObject_Repr(loader);
187 PyErr_Format(PyExc_TypeError,
188 "loader plug-in %s does not define load_file or save_file function",
189 PyString_AsString(repr));
196 Py_CLEAR(_entry_point);
204 bool PythonLoaderFileType::
205 ensure_loaded()
const {
206 if (_load_func !=
nullptr || _save_func !=
nullptr) {
209 nassertr_always(_entry_point !=
nullptr,
false);
211 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
212 PyGILState_STATE gstate;
213 gstate = PyGILState_Ensure();
216 if (loader_cat.is_info()) {
217 PyObject *repr = PyObject_Repr(_entry_point);
220 <<
"loading file type module: "
221 #if PY_MAJOR_VERSION >= 3
222 << PyUnicode_AsUTF8(repr) <<
"\n";
224 << PyString_AsString(repr) <<
"\n";
229 PyObject *result = PyObject_CallMethod(_entry_point, (
char *)
"load",
nullptr);
231 bool success =
false;
232 if (result !=
nullptr) {
233 success = ((PythonLoaderFileType *)
this)->init(result);
236 PyObject *repr = PyObject_Repr(_entry_point);
240 #if PY_MAJOR_VERSION >= 3
241 << PyUnicode_AsUTF8(repr) <<
"\n";
243 << PyString_AsString(repr) <<
"\n";
248 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
249 PyGILState_Release(gstate);
258 std::string PythonLoaderFileType::
260 return "Python loader";
266 std::string PythonLoaderFileType::
267 get_extension()
const {
275 std::string PythonLoaderFileType::
276 get_additional_extensions()
const {
277 return _additional_extensions;
284 bool PythonLoaderFileType::
285 supports_compressed()
const {
286 return ensure_loaded() && _supports_compressed;
294 bool PythonLoaderFileType::
295 supports_load()
const {
296 return ensure_loaded() && _load_func !=
nullptr;
304 bool PythonLoaderFileType::
305 supports_save()
const {
306 return ensure_loaded() && _save_func !=
nullptr;
318 if (vfile ==
nullptr) {
322 if (!supports_load()) {
326 if (record !=
nullptr) {
330 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
331 PyGILState_STATE gstate;
332 gstate = PyGILState_Ensure();
336 PyObject *args = PyTuple_New(3);
339 if (record !=
nullptr) {
341 PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((
void *)record, Dtool_BamCacheRecord,
true,
false, record->
get_type_index()));
343 PyTuple_SET_ITEM(args, 2, Py_None);
349 PyObject *result = PythonThread::call_python_func(_load_func, args);
350 if (result !=
nullptr) {
351 if (DtoolInstance_Check(result)) {
352 node = (
PandaNode *)DtoolInstance_UPCAST(result, Dtool_PandaNode);
359 if (node ==
nullptr) {
360 PyObject *exc_type = _PyErr_OCCURRED();
363 <<
"load_file must return valid PandaNode or raise exception\n";
367 <<
" failed with " << ((PyTypeObject *)exc_type)->tp_name <<
" exception.\n";
372 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
373 PyGILState_Release(gstate);
376 if (node !=
nullptr && node->is_of_type(ModelRoot::get_class_type())) {
388 bool PythonLoaderFileType::
391 if (!supports_save()) {
395 nassertr(node !=
nullptr,
false);
398 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
399 PyGILState_STATE gstate;
400 gstate = PyGILState_Ensure();
404 PyObject *args = PyTuple_New(3);
407 PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((
void *)node, Dtool_PandaNode,
true,
false, node->get_type_index()));
409 PyObject *result = PythonThread::call_python_func(_load_func, args);
411 if (result !=
nullptr) {
416 <<
"save_file failed with an exception.\n";
419 #if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
420 PyGILState_Release(gstate);
423 return (result !=
nullptr);
An instance of this class is written to the front of a Bam or Txo file to make the file a cached inst...
void add_dependent_file(const Filename &pathname)
Adds the indicated file to the list of files that will be loaded to generate the data in this record.
The name of a file, such as a texture file or an Egg file.
std::string get_basename() const
Returns the basename part of the filename.
Specifies parameters that may be passed to the loader.
A node of this type is created automatically at the root of each model file that is loaded.
set_fullpath
Sets the full pathname of the model represented by this node, as found on disk.
set_timestamp
Sets the timestamp of the file on disk that was read for this model.
A basic node of the scene graph or data graph.
void ref() const
Explicitly increments the reference count.
TypeHandle is the identifier used to differentiate C++ class types.
int get_type_index() const
Returns the internal index number associated with this object's TypeHandle, a unique number for each ...
A hierarchy of directories and files that appears to be one continuous file system,...
PointerTo< VirtualFile > get_file(const Filename &filename, bool status_only=false) const
Looks up the file by the indicated name in the file system.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
The abstract base class for a file or directory within the VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PyObject * DTool_CreatePyInstance(const T *obj, bool memory_rules)
These functions wrap a pointer for a class that defines get_type_handle().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.