mirror of
https://github.com/panda3d/panda3d.git
synced 2025-12-30 19:49:46 -06:00
Merge branch 'release/1.10.x'
This commit is contained in:
@@ -77,6 +77,7 @@ class DirectOptionMenu(DirectButton):
|
||||
state = 'normal')
|
||||
# Make sure this is on top of all the other widgets
|
||||
self.cancelFrame.setBin('gui-popup', 0)
|
||||
self.cancelFrame.node().setBounds(OmniBoundingVolume())
|
||||
self.cancelFrame.bind(DGG.B1PRESS, self.hidePopupMenu)
|
||||
# Default action on press is to show popup menu
|
||||
self.bind(DGG.B1PRESS, self.showPopupMenu)
|
||||
|
||||
@@ -147,12 +147,28 @@ class Loader(DirectObject):
|
||||
Loader.loaderIndex += 1
|
||||
self.accept(self.hook, self.__gotAsyncObject)
|
||||
|
||||
if ConfigVariableBool('loader-support-entry-points', True):
|
||||
self._loadPythonFileTypes()
|
||||
|
||||
def destroy(self):
|
||||
self.ignore(self.hook)
|
||||
self.loader.stopThreads()
|
||||
del self.base
|
||||
del self.loader
|
||||
|
||||
def _loadPythonFileTypes(self):
|
||||
import importlib
|
||||
try:
|
||||
pkg_resources = importlib.import_module('pkg_resources')
|
||||
except ImportError:
|
||||
pkg_resources = None
|
||||
|
||||
if pkg_resources:
|
||||
registry = LoaderFileTypeRegistry.getGlobalPtr()
|
||||
|
||||
for entry_point in pkg_resources.iter_entry_points('panda3d.loaders'):
|
||||
registry.register_deferred_type(entry_point)
|
||||
|
||||
# model loading funcs
|
||||
def loadModel(self, modelPath, loaderOptions = None, noCache = None,
|
||||
allowInstance = False, okMissing = None,
|
||||
|
||||
@@ -29,6 +29,20 @@ AsyncFuture::
|
||||
// If this triggers, the future destroyed before it was cancelled, which is
|
||||
// not valid. Unless we should simply call cancel() here?
|
||||
nassertv(_waiting.empty());
|
||||
|
||||
// This is an attempt to work around what appears to be a compiler bug in
|
||||
// MSVC when compiling with optimizations and having an EventStoreInt stored
|
||||
// in this field. It crashes when we delete via the ReferenceCount base
|
||||
// instead of via the TypedObject. I haven't been able to find out why;
|
||||
// just that it doesn't happen with ParamString. ~rdb
|
||||
ReferenceCount *result_ref = _result_ref.p();
|
||||
if (result_ref != nullptr) {
|
||||
_result_ref.cheat() = nullptr;
|
||||
if (!result_ref->unref()) {
|
||||
delete _result;
|
||||
}
|
||||
_result = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -890,6 +890,7 @@ reflect_uniform(int i, char *name_buffer, GLsizei name_buflen) {
|
||||
|
||||
// Add it once for each index.
|
||||
for (bind._index = 0; bind._index < param_size; ++bind._index) {
|
||||
bind._id._seqno = p + bind._index;
|
||||
_shader->_mat_spec.push_back(bind);
|
||||
}
|
||||
_shader->_mat_deps |= bind._dep[0];
|
||||
|
||||
@@ -36,6 +36,9 @@ public:
|
||||
void register_deferred_type(const std::string &extension, const std::string &library);
|
||||
|
||||
PUBLISHED:
|
||||
EXTENSION(void register_type(PyObject *type));
|
||||
EXTENSION(void register_deferred_type(PyObject *entry_point));
|
||||
|
||||
int get_num_types() const;
|
||||
LoaderFileType *get_type(int n) const;
|
||||
MAKE_SEQ(get_types, get_num_types, get_type);
|
||||
|
||||
67
panda/src/pgraph/loaderFileTypeRegistry_ext.cxx
Normal file
67
panda/src/pgraph/loaderFileTypeRegistry_ext.cxx
Normal file
@@ -0,0 +1,67 @@
|
||||
/**
|
||||
* 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 loaderFileTypeRegistry_ext.cxx
|
||||
* @author rdb
|
||||
* @date 2019-07-30
|
||||
*/
|
||||
|
||||
#include "loaderFileTypeRegistry_ext.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "pythonLoaderFileType.h"
|
||||
|
||||
/**
|
||||
* Registers a loader file type that is implemented in Python.
|
||||
*/
|
||||
void Extension<LoaderFileTypeRegistry>::
|
||||
register_type(PyObject *type) {
|
||||
PythonLoaderFileType *loader = new PythonLoaderFileType();
|
||||
|
||||
if (loader->init(type)) {
|
||||
_this->register_type(loader);
|
||||
} else {
|
||||
delete loader;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a loader file type from a pkg_resources.EntryPoint object, which
|
||||
* will be loaded when a file with the extension is encountered.
|
||||
*/
|
||||
void Extension<LoaderFileTypeRegistry>::
|
||||
register_deferred_type(PyObject *entry_point) {
|
||||
// The "name" attribute holds the extension.
|
||||
PyObject *name = PyObject_GetAttrString(entry_point, "name");
|
||||
if (name == nullptr) {
|
||||
Dtool_Raise_TypeError("entry_point argument is missing name attribute");
|
||||
return;
|
||||
}
|
||||
|
||||
const char *name_str;
|
||||
Py_ssize_t name_len;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
name_str = PyUnicode_AsUTF8AndSize(name, &name_len);
|
||||
#else
|
||||
if (PyString_AsStringAndSize(name, (char **)&name_str, &name_len) == -1) {
|
||||
name_str = nullptr;
|
||||
}
|
||||
#endif
|
||||
Py_DECREF(name);
|
||||
|
||||
if (name_str == nullptr) {
|
||||
Dtool_Raise_TypeError("entry_point.name is expected to be str");
|
||||
return;
|
||||
}
|
||||
|
||||
PythonLoaderFileType *loader = new PythonLoaderFileType(std::string(name_str, name_len), entry_point);
|
||||
_this->register_type(loader);
|
||||
}
|
||||
|
||||
#endif
|
||||
38
panda/src/pgraph/loaderFileTypeRegistry_ext.h
Normal file
38
panda/src/pgraph/loaderFileTypeRegistry_ext.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 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 loaderFileTypeRegistry_ext.h
|
||||
* @author rdb
|
||||
* @date 2019-07-30
|
||||
*/
|
||||
|
||||
#ifndef LOADERFILETYPEREGISTRYEXT_H
|
||||
#define LOADERFILETYPEREGISTRYEXT_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "extension.h"
|
||||
#include "loaderFileTypeRegistry.h"
|
||||
#include "py_panda.h"
|
||||
|
||||
/**
|
||||
* This class defines the extension methods for LoaderFileTypeRegistry, which are called
|
||||
* instead of any C++ methods with the same prototype.
|
||||
*/
|
||||
template<>
|
||||
class Extension<LoaderFileTypeRegistry> : public ExtensionBase<LoaderFileTypeRegistry> {
|
||||
public:
|
||||
void register_type(PyObject *type);
|
||||
void register_deferred_type(PyObject *entry_point);
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif
|
||||
@@ -1,6 +1,8 @@
|
||||
#include "loaderFileTypeRegistry_ext.cxx"
|
||||
#include "nodePath_ext.cxx"
|
||||
#include "nodePathCollection_ext.cxx"
|
||||
#include "pandaNode_ext.cxx"
|
||||
#include "pythonLoaderFileType.cxx"
|
||||
#include "renderState_ext.cxx"
|
||||
#include "shaderAttrib_ext.cxx"
|
||||
#include "shaderInput_ext.cxx"
|
||||
|
||||
409
panda/src/pgraph/pythonLoaderFileType.cxx
Normal file
409
panda/src/pgraph/pythonLoaderFileType.cxx
Normal file
@@ -0,0 +1,409 @@
|
||||
/**
|
||||
* 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 pythonLoaderFileType.cxx
|
||||
* @author rdb
|
||||
* @date 2019-07-29
|
||||
*/
|
||||
|
||||
#include "pythonLoaderFileType.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "modelRoot.h"
|
||||
#include "pythonThread.h"
|
||||
#include "py_panda.h"
|
||||
#include "virtualFileSystem.h"
|
||||
|
||||
extern struct Dtool_PyTypedObject Dtool_BamCacheRecord;
|
||||
extern struct Dtool_PyTypedObject Dtool_Filename;
|
||||
extern struct Dtool_PyTypedObject Dtool_LoaderOptions;
|
||||
extern struct Dtool_PyTypedObject Dtool_PandaNode;
|
||||
extern struct Dtool_PyTypedObject Dtool_PythonLoaderFileType;
|
||||
|
||||
TypeHandle PythonLoaderFileType::_type_handle;
|
||||
|
||||
/**
|
||||
* This constructor expects init() to be called manually.
|
||||
*/
|
||||
PythonLoaderFileType::
|
||||
PythonLoaderFileType() {
|
||||
init_type();
|
||||
}
|
||||
|
||||
/**
|
||||
* This constructor expects a single pkg_resources.EntryPoint argument for a
|
||||
* deferred loader.
|
||||
*/
|
||||
PythonLoaderFileType::
|
||||
PythonLoaderFileType(std::string extension, PyObject *entry_point) :
|
||||
_extension(std::move(extension)),
|
||||
_entry_point(entry_point) {
|
||||
|
||||
init_type();
|
||||
Py_INCREF(entry_point);
|
||||
}
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
PythonLoaderFileType::
|
||||
~PythonLoaderFileType() {
|
||||
if (_entry_point != nullptr || _load_func != nullptr || _save_func != nullptr) {
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
#endif
|
||||
|
||||
Py_CLEAR(_entry_point);
|
||||
Py_CLEAR(_load_func);
|
||||
Py_CLEAR(_save_func);
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the fields from the given Python loader object.
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
init(PyObject *loader) {
|
||||
nassertr(loader != nullptr, false);
|
||||
nassertr(_load_func == nullptr, false);
|
||||
nassertr(_save_func == nullptr, false);
|
||||
|
||||
// Check the extensions member. If we already have a registered extension,
|
||||
// it must occur in the list.
|
||||
PyObject *extensions = PyObject_GetAttrString(loader, "extensions");
|
||||
if (extensions != nullptr) {
|
||||
PyObject *sequence = PySequence_Fast(extensions, "extensions must be a sequence");
|
||||
PyObject **items = PySequence_Fast_ITEMS(sequence);
|
||||
Py_ssize_t num_items = PySequence_Fast_GET_SIZE(sequence);
|
||||
Py_DECREF(extensions);
|
||||
bool found_extension = false;
|
||||
|
||||
for (Py_ssize_t i = 0; i < num_items; ++i) {
|
||||
PyObject *extension = items[i];
|
||||
const char *extension_str;
|
||||
Py_ssize_t extension_len;
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
extension_str = PyUnicode_AsUTF8AndSize(extension, &extension_len);
|
||||
#else
|
||||
if (PyString_AsStringAndSize(extension, (char **)&extension_str, &extension_len) == -1) {
|
||||
extension_str = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (extension_str == nullptr) {
|
||||
Py_DECREF(sequence);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (_extension.empty()) {
|
||||
_extension.assign(extension_str, extension_len);
|
||||
found_extension = true;
|
||||
} else {
|
||||
std::string new_extension(extension_str, extension_len);
|
||||
if (_extension == new_extension) {
|
||||
found_extension = true;
|
||||
} else {
|
||||
if (!_additional_extensions.empty()) {
|
||||
_additional_extensions += ' ';
|
||||
}
|
||||
_additional_extensions += new_extension;
|
||||
}
|
||||
}
|
||||
}
|
||||
Py_DECREF(sequence);
|
||||
|
||||
if (!found_extension) {
|
||||
PyObject *repr = PyObject_Repr(loader);
|
||||
loader_cat.error()
|
||||
<< "Registered extension '" << _extension
|
||||
<< "' does not occur in extensions list of "
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
<< PyUnicode_AsUTF8(repr) << "\n";
|
||||
#else
|
||||
<< PyString_AsString(repr) << "\n";
|
||||
#endif
|
||||
Py_DECREF(repr);
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
PyObject *supports_compressed = PyObject_GetAttrString(loader, "supports_compressed");
|
||||
if (supports_compressed != nullptr) {
|
||||
if (supports_compressed == Py_True) {
|
||||
_supports_compressed = true;
|
||||
}
|
||||
else if (supports_compressed == Py_False) {
|
||||
_supports_compressed = false;
|
||||
}
|
||||
else {
|
||||
Dtool_Raise_TypeError("supports_compressed must be a bool");
|
||||
Py_DECREF(supports_compressed);
|
||||
return false;
|
||||
}
|
||||
Py_DECREF(supports_compressed);
|
||||
}
|
||||
|
||||
_load_func = PyObject_GetAttrString(loader, "load_file");
|
||||
_save_func = PyObject_GetAttrString(loader, "save_file");
|
||||
PyErr_Clear();
|
||||
|
||||
if (_load_func == nullptr && _save_func == nullptr) {
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"loader plug-in %R does not define load_file or save_file function",
|
||||
loader);
|
||||
#else
|
||||
PyObject *repr = PyObject_Repr(loader);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"loader plug-in %s does not define load_file or save_file function",
|
||||
PyString_AsString(repr));
|
||||
Py_DECREF(repr);
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
// We don't need this any more.
|
||||
Py_CLEAR(_entry_point);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures that the referenced Python module is loaded.
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
ensure_loaded() const {
|
||||
if (_load_func != nullptr || _save_func != nullptr) {
|
||||
return true;
|
||||
}
|
||||
nassertr_always(_entry_point != nullptr, false);
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
#endif
|
||||
|
||||
if (loader_cat.is_info()) {
|
||||
PyObject *repr = PyObject_Repr(_entry_point);
|
||||
|
||||
loader_cat.info()
|
||||
<< "loading file type module: "
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
<< PyUnicode_AsUTF8(repr) << "\n";
|
||||
#else
|
||||
<< PyString_AsString(repr) << "\n";
|
||||
#endif
|
||||
Py_DECREF(repr);
|
||||
}
|
||||
|
||||
PyObject *result = PyObject_CallMethod(_entry_point, (char *)"load", nullptr);
|
||||
|
||||
bool success = false;
|
||||
if (result != nullptr) {
|
||||
success = ((PythonLoaderFileType *)this)->init(result);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
PyObject *repr = PyObject_Repr(_entry_point);
|
||||
|
||||
loader_cat.error()
|
||||
<< "unable to load "
|
||||
#if PY_MAJOR_VERSION >= 3
|
||||
<< PyUnicode_AsUTF8(repr) << "\n";
|
||||
#else
|
||||
<< PyString_AsString(repr) << "\n";
|
||||
#endif
|
||||
Py_DECREF(repr);
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string PythonLoaderFileType::
|
||||
get_name() const {
|
||||
return "Python loader";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string PythonLoaderFileType::
|
||||
get_extension() const {
|
||||
return _extension;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a space-separated list of extension, in addition to the one
|
||||
* returned by get_extension(), that are recognized by this converter.
|
||||
*/
|
||||
std::string PythonLoaderFileType::
|
||||
get_additional_extensions() const {
|
||||
return _additional_extensions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this file type can transparently load compressed files
|
||||
* (with a .pz or .gz extension), false otherwise.
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
supports_compressed() const {
|
||||
return ensure_loaded() && _supports_compressed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file type can be used to load files, and load_file() is
|
||||
* supported. Returns false if load_file() is unimplemented and will always
|
||||
* fail.
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
supports_load() const {
|
||||
return ensure_loaded() && _load_func != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the file type can be used to save files, and save_file() is
|
||||
* supported. Returns false if save_file() is unimplemented and will always
|
||||
* fail.
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
supports_save() const {
|
||||
return ensure_loaded() && _save_func != nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
PT(PandaNode) PythonLoaderFileType::
|
||||
load_file(const Filename &path, const LoaderOptions &options,
|
||||
BamCacheRecord *record) const {
|
||||
// Let's check whether the file even exists before calling Python.
|
||||
VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
|
||||
PT(VirtualFile) vfile = vfs->get_file(path);
|
||||
if (vfile == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!supports_load()) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (record != nullptr) {
|
||||
record->add_dependent_file(vfile);
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
#endif
|
||||
|
||||
// Wrap the arguments.
|
||||
PyObject *args = PyTuple_New(3);
|
||||
PyTuple_SET_ITEM(args, 0, DTool_CreatePyInstance((void *)&path, Dtool_Filename, false, true));
|
||||
PyTuple_SET_ITEM(args, 1, DTool_CreatePyInstance((void *)&options, Dtool_LoaderOptions, false, true));
|
||||
if (record != nullptr) {
|
||||
record->ref();
|
||||
PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((void *)record, Dtool_BamCacheRecord, true, false, record->get_type_index()));
|
||||
} else {
|
||||
PyTuple_SET_ITEM(args, 2, Py_None);
|
||||
Py_INCREF(Py_None);
|
||||
}
|
||||
|
||||
PT(PandaNode) node;
|
||||
|
||||
PyObject *result = PythonThread::call_python_func(_load_func, args);
|
||||
if (result != nullptr) {
|
||||
if (DtoolInstance_Check(result)) {
|
||||
node = (PandaNode *)DtoolInstance_UPCAST(result, Dtool_PandaNode);
|
||||
}
|
||||
Py_DECREF(result);
|
||||
}
|
||||
|
||||
Py_DECREF(args);
|
||||
|
||||
if (node == nullptr) {
|
||||
PyObject *exc_type = _PyErr_OCCURRED();
|
||||
if (!exc_type) {
|
||||
loader_cat.error()
|
||||
<< "load_file must return valid PandaNode or raise exception\n";
|
||||
} else {
|
||||
loader_cat.error()
|
||||
<< "Loading " << path.get_basename()
|
||||
<< " failed with " << ((PyTypeObject *)exc_type)->tp_name << " exception.\n";
|
||||
PyErr_Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
|
||||
if (node != nullptr && node->is_of_type(ModelRoot::get_class_type())) {
|
||||
ModelRoot *model_root = DCAST(ModelRoot, node.p());
|
||||
model_root->set_fullpath(path);
|
||||
model_root->set_timestamp(vfile->get_timestamp());
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool PythonLoaderFileType::
|
||||
save_file(const Filename &path, const LoaderOptions &options,
|
||||
PandaNode *node) const {
|
||||
if (!supports_save()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nassertr(node != nullptr, false);
|
||||
node->ref();
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_STATE gstate;
|
||||
gstate = PyGILState_Ensure();
|
||||
#endif
|
||||
|
||||
// Wrap the arguments.
|
||||
PyObject *args = PyTuple_New(3);
|
||||
PyTuple_SET_ITEM(args, 0, DTool_CreatePyInstance((void *)&path, Dtool_Filename, false, true));
|
||||
PyTuple_SET_ITEM(args, 1, DTool_CreatePyInstance((void *)&options, Dtool_LoaderOptions, false, true));
|
||||
PyTuple_SET_ITEM(args, 2, DTool_CreatePyInstanceTyped((void *)node, Dtool_PandaNode, true, false, node->get_type_index()));
|
||||
|
||||
PyObject *result = PythonThread::call_python_func(_load_func, args);
|
||||
Py_DECREF(args);
|
||||
if (result != nullptr) {
|
||||
Py_DECREF(result);
|
||||
} else {
|
||||
PyErr_Clear();
|
||||
loader_cat.error()
|
||||
<< "save_file failed with an exception.\n";
|
||||
}
|
||||
|
||||
#if defined(HAVE_THREADS) && !defined(SIMPLE_THREADS)
|
||||
PyGILState_Release(gstate);
|
||||
#endif
|
||||
|
||||
return (result != nullptr);
|
||||
}
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
81
panda/src/pgraph/pythonLoaderFileType.h
Normal file
81
panda/src/pgraph/pythonLoaderFileType.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/**
|
||||
* 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 pythonLoaderFileType.h
|
||||
* @author rdb
|
||||
* @date 2019-07-29
|
||||
*/
|
||||
|
||||
#ifndef PYTHONLOADERFILETYPE_H
|
||||
#define PYTHONLOADERFILETYPE_H
|
||||
|
||||
#include "pandabase.h"
|
||||
|
||||
#ifdef HAVE_PYTHON
|
||||
|
||||
#include "loaderFileType.h"
|
||||
|
||||
/**
|
||||
* This defines a Python-based loader plug-in. An instance of this can be
|
||||
* constructed by inheritance and explicitly registered, or it can be created
|
||||
* by passing in a pkg_resources.EntryPoint instance.
|
||||
*/
|
||||
class PythonLoaderFileType : public LoaderFileType {
|
||||
public:
|
||||
PythonLoaderFileType();
|
||||
PythonLoaderFileType(std::string extension, PyObject *entry_point);
|
||||
~PythonLoaderFileType();
|
||||
|
||||
bool init(PyObject *loader);
|
||||
bool ensure_loaded() const;
|
||||
|
||||
virtual std::string get_name() const override;
|
||||
virtual std::string get_extension() const override;
|
||||
virtual std::string get_additional_extensions() const override;
|
||||
virtual bool supports_compressed() const override;
|
||||
|
||||
virtual bool supports_load() const override;
|
||||
virtual bool supports_save() const override;
|
||||
|
||||
virtual PT(PandaNode) load_file(const Filename &path, const LoaderOptions &options,
|
||||
BamCacheRecord *record) const override;
|
||||
virtual bool save_file(const Filename &path, const LoaderOptions &options,
|
||||
PandaNode *node) const override;
|
||||
|
||||
private:
|
||||
std::string _extension;
|
||||
std::string _additional_extensions;
|
||||
PyObject *_entry_point = nullptr;
|
||||
PyObject *_load_func = nullptr;
|
||||
PyObject *_save_func = nullptr;
|
||||
bool _supports_compressed = false;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
}
|
||||
static void init_type() {
|
||||
LoaderFileType::init_type();
|
||||
register_type(_type_handle, "PythonLoaderFileType",
|
||||
LoaderFileType::get_class_type());
|
||||
}
|
||||
virtual TypeHandle get_type() const override {
|
||||
return get_class_type();
|
||||
}
|
||||
virtual TypeHandle force_init_type() override {
|
||||
init_type();
|
||||
return get_class_type();
|
||||
}
|
||||
|
||||
private:
|
||||
static TypeHandle _type_handle;
|
||||
};
|
||||
|
||||
#endif // HAVE_PYTHON
|
||||
|
||||
#endif
|
||||
@@ -16,6 +16,7 @@
|
||||
#include "wglGraphicsBuffer.h"
|
||||
#include "wglGraphicsPipe.h"
|
||||
#include "string_utils.h"
|
||||
#include <atomic>
|
||||
|
||||
TypeHandle wglGraphicsStateGuardian::_type_handle;
|
||||
|
||||
@@ -49,7 +50,6 @@ wglGraphicsStateGuardian(GraphicsEngine *engine, GraphicsPipe *pipe,
|
||||
_wglCreateContextAttribsARB = nullptr;
|
||||
|
||||
get_gamma_table();
|
||||
atexit(atexit_function);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -886,6 +886,12 @@ static_set_gamma(bool restore, PN_stdfloat gamma) {
|
||||
|
||||
if (SetDeviceGammaRamp (hdc, ramp)) {
|
||||
set = true;
|
||||
|
||||
// Register an atexit handler
|
||||
static std::atomic_flag gamma_modified = ATOMIC_FLAG_INIT;
|
||||
if (!gamma_modified.test_and_set()) {
|
||||
atexit(atexit_function);
|
||||
}
|
||||
}
|
||||
|
||||
ReleaseDC (nullptr, hdc);
|
||||
|
||||
Reference in New Issue
Block a user