226 lines
7.1 KiB
C++
226 lines
7.1 KiB
C++
/**
|
|
* 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 renderState_ext.cxx
|
|
* @author CFSworks
|
|
* @date 2014-03-31
|
|
*/
|
|
|
|
#include "renderState_ext.h"
|
|
|
|
#ifdef HAVE_PYTHON
|
|
|
|
/**
|
|
* Returns a RenderState with a given number of attributes set.
|
|
*/
|
|
CPT(RenderState) Extension<RenderState>::
|
|
make(PyObject *args, PyObject *kwds) {
|
|
extern struct Dtool_PyTypedObject Dtool_RenderAttrib;
|
|
|
|
Py_ssize_t num_attribs = PyTuple_GET_SIZE(args);
|
|
|
|
// Check for the override keyword argument.
|
|
PyObject *py_override = nullptr;
|
|
if (kwds != nullptr && PyDict_GET_SIZE(kwds) > 0) {
|
|
if (PyDict_GET_SIZE(kwds) > 1) {
|
|
Dtool_Raise_TypeError("RenderState.make() received an unexpected keyword argument");
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject *key;
|
|
Py_ssize_t ppos = 0;
|
|
if (!PyDict_Next(kwds, &ppos, &key, &py_override)) {
|
|
return nullptr;
|
|
}
|
|
|
|
// We got the item, we just need to make sure that it had the right key.
|
|
if (!PyUnicode_CheckExact(key) || !_PyUnicode_EqualToASCIIString(key, "override")) {
|
|
Dtool_Raise_TypeError("RenderState.make() received an unexpected keyword argument");
|
|
return nullptr;
|
|
}
|
|
|
|
if (!PyLong_Check(py_override)) {
|
|
Dtool_Raise_TypeError("RenderState.make() override argument should be int");
|
|
return nullptr;
|
|
}
|
|
}
|
|
else if (num_attribs > 1 && PyLong_Check(PyTuple_GET_ITEM(args, num_attribs - 1))) {
|
|
// It was specified as last positional argument.
|
|
py_override = PyTuple_GET_ITEM(args, --num_attribs);
|
|
}
|
|
|
|
int override = 0;
|
|
if (py_override != nullptr) {
|
|
override = _PyLong_AsInt(py_override);
|
|
if (override == -1 && _PyErr_OCCURRED()) {
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
const RenderAttrib **attribs = (const RenderAttrib **)alloca(sizeof(RenderAttrib *) * num_attribs);
|
|
for (Py_ssize_t i = 0; i < num_attribs; ++i) {
|
|
PyObject *arg = PyTuple_GET_ITEM(args, i);
|
|
if (!DtoolInstance_GetPointer(arg, attribs[i], Dtool_RenderAttrib)) {
|
|
Dtool_Raise_ArgTypeError(arg, i, "RenderState.make", "RenderAttrib");
|
|
return nullptr;
|
|
}
|
|
}
|
|
return RenderState::make(attribs, num_attribs, override);
|
|
}
|
|
|
|
/**
|
|
* Returns a list of 2-tuples that represents the composition cache. For each
|
|
* tuple in the list, the first element is the source render, and the second
|
|
* is the result render. If both are None, there is no entry in the cache at
|
|
* that slot.
|
|
*
|
|
* In general, a->compose(source) == result.
|
|
*
|
|
* This has no practical value other than for examining the cache for
|
|
* performance analysis.
|
|
*/
|
|
PyObject *Extension<RenderState>::
|
|
get_composition_cache() const {
|
|
extern struct Dtool_PyTypedObject Dtool_RenderState;
|
|
LightReMutexHolder holder(*RenderState::_states_lock);
|
|
size_t cache_size = _this->_composition_cache.get_num_entries();
|
|
PyObject *list = PyList_New(cache_size);
|
|
|
|
for (size_t i = 0; i < cache_size; ++i) {
|
|
PyObject *tuple = PyTuple_New(2);
|
|
PyObject *a, *b;
|
|
const RenderState *source = _this->_composition_cache.get_key(i);
|
|
if (source == nullptr) {
|
|
a = Py_None;
|
|
Py_INCREF(a);
|
|
} else {
|
|
source->ref();
|
|
a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState,
|
|
true, true, source->get_type_index());
|
|
}
|
|
const RenderState *result = _this->_composition_cache.get_data(i)._result;
|
|
if (result == nullptr) {
|
|
b = Py_None;
|
|
Py_INCREF(b);
|
|
} else {
|
|
result->ref();
|
|
b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState,
|
|
true, true, result->get_type_index());
|
|
}
|
|
PyTuple_SET_ITEM(tuple, 0, a);
|
|
PyTuple_SET_ITEM(tuple, 1, b);
|
|
|
|
PyList_SET_ITEM(list, i, tuple);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of 2-tuples that represents the invert_composition cache.
|
|
* For each tuple in the list, the first element is the source render, and the
|
|
* second is the result render. If both are None, there is no entry in the
|
|
* cache at that slot.
|
|
*
|
|
* In general, a->invert_compose(source) == result.
|
|
*
|
|
* This has no practical value other than for examining the cache for
|
|
* performance analysis.
|
|
*/
|
|
PyObject *Extension<RenderState>::
|
|
get_invert_composition_cache() const {
|
|
extern struct Dtool_PyTypedObject Dtool_RenderState;
|
|
LightReMutexHolder holder(*RenderState::_states_lock);
|
|
size_t cache_size = _this->_invert_composition_cache.get_num_entries();
|
|
PyObject *list = PyList_New(cache_size);
|
|
|
|
for (size_t i = 0; i < cache_size; ++i) {
|
|
PyObject *tuple = PyTuple_New(2);
|
|
PyObject *a, *b;
|
|
const RenderState *source = _this->_invert_composition_cache.get_key(i);
|
|
if (source == nullptr) {
|
|
a = Py_None;
|
|
Py_INCREF(a);
|
|
} else {
|
|
source->ref();
|
|
a = DTool_CreatePyInstanceTyped((void *)source, Dtool_RenderState,
|
|
true, true, source->get_type_index());
|
|
}
|
|
const RenderState *result = _this->_invert_composition_cache.get_data(i)._result;
|
|
if (result == nullptr) {
|
|
b = Py_None;
|
|
Py_INCREF(b);
|
|
} else {
|
|
result->ref();
|
|
b = DTool_CreatePyInstanceTyped((void *)result, Dtool_RenderState,
|
|
true, true, result->get_type_index());
|
|
}
|
|
PyTuple_SET_ITEM(tuple, 0, a);
|
|
PyTuple_SET_ITEM(tuple, 1, b);
|
|
|
|
PyList_SET_ITEM(list, i, tuple);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all of the RenderState objects in the state cache. The
|
|
* order of elements in this cache is arbitrary.
|
|
*/
|
|
PyObject *Extension<RenderState>::
|
|
get_states() {
|
|
extern struct Dtool_PyTypedObject Dtool_RenderState;
|
|
LightReMutexHolder holder(*RenderState::_states_lock);
|
|
|
|
size_t num_states = RenderState::_states.get_num_entries();
|
|
PyObject *list = PyList_New(num_states);
|
|
size_t i = 0;
|
|
|
|
size_t size = RenderState::_states.get_num_entries();
|
|
for (size_t si = 0; si < size; ++si) {
|
|
const RenderState *state = RenderState::_states.get_key(si);
|
|
state->ref();
|
|
PyObject *a =
|
|
DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState,
|
|
true, true, state->get_type_index());
|
|
nassertr(i < num_states, list);
|
|
PyList_SET_ITEM(list, i, a);
|
|
++i;
|
|
}
|
|
nassertr(i == num_states, list);
|
|
return list;
|
|
}
|
|
|
|
/**
|
|
* Returns a list of all of the "unused" RenderState objects in the state
|
|
* cache. See get_num_unused_states().
|
|
*/
|
|
PyObject *Extension<RenderState>::
|
|
get_unused_states() {
|
|
extern struct Dtool_PyTypedObject Dtool_RenderState;
|
|
LightReMutexHolder holder(*RenderState::_states_lock);
|
|
|
|
PyObject *list = PyList_New(0);
|
|
size_t size = RenderState::_states.get_num_entries();
|
|
for (size_t si = 0; si < size; ++si) {
|
|
const RenderState *state = RenderState::_states.get_key(si);
|
|
if (state->get_cache_ref_count() == state->get_ref_count()) {
|
|
state->ref();
|
|
PyObject *a =
|
|
DTool_CreatePyInstanceTyped((void *)state, Dtool_RenderState,
|
|
true, true, state->get_type_index());
|
|
PyList_Append(list, a);
|
|
Py_DECREF(a);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
|
|
#endif // HAVE_PYTHON
|