Add set_shader_inputs for efficiently setting multiple shader inputs

This commit is contained in:
rdb 2017-02-06 13:16:27 +01:00
parent c3a196860a
commit cfe810ace7
7 changed files with 266 additions and 12 deletions

View File

@ -791,6 +791,15 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
_args_type = InterfaceMaker::AT_single_arg;
} else {
_args_type = InterfaceMaker::AT_varargs;
// If the arguments are named "args" and "kwargs", we will be directly
// passing the argument tuples to the function.
if (_parameters.size() == first_param + 2 &&
_parameters[first_param]._name == "args" &&
(_parameters[first_param + 1]._name == "kwargs" ||
_parameters[first_param + 1]._name == "kwds")) {
_flags |= F_explicit_args;
}
}
switch (_type) {
@ -890,7 +899,7 @@ setup_properties(const InterrogateFunction &ifunc, InterfaceMaker *interface_mak
if (_args_type == InterfaceMaker::AT_varargs) {
// Every other method can take keyword arguments, if they take more
// than one argument.
_args_type = InterfaceMaker::AT_keyword_args;
_args_type |= InterfaceMaker::AT_keyword_args;
}
}
break;

View File

@ -100,6 +100,7 @@ public:
F_coerce_constructor = 0x1000,
F_divide_float = 0x2000,
F_hash = 0x4000,
F_explicit_args = 0x8000,
};
typedef vector<Parameter> Parameters;

View File

@ -3453,7 +3453,13 @@ write_function_for_name(ostream &out, Object *obj,
max_required_args = collapse_default_remaps(map_sets, max_required_args);
}
if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) {
if (remap->_flags & FunctionRemap::F_explicit_args) {
// We have a remap that wants to handle the wrapper itself.
string expected_params;
write_function_instance(out, remap, 0, 0, expected_params, 2, true, true,
args_type, return_flags);
} else if (map_sets.size() > 1 && (args_type == AT_varargs || args_type == AT_keyword_args)) {
switch (args_type) {
case AT_keyword_args:
indent(out, 2) << "int parameter_count = (int)PyTuple_Size(args);\n";
@ -4536,19 +4542,23 @@ write_function_instance(ostream &out, FunctionRemap *remap,
expected_params += methodNameFromCppName(remap, "", false);
expected_params += "(";
int num_params = max_num_args;
if (remap->_has_this) {
num_params += 1;
}
if (num_params > (int)remap->_parameters.size()) {
// Limit to how many parameters this remap actually has.
num_params = (int)remap->_parameters.size();
max_num_args = num_params;
int num_params = 0;
if ((remap->_flags & FunctionRemap::F_explicit_args) == 0) {
num_params = max_num_args;
if (remap->_has_this) {
--max_num_args;
num_params += 1;
}
if (num_params > (int)remap->_parameters.size()) {
// Limit to how many parameters this remap actually has.
num_params = (int)remap->_parameters.size();
max_num_args = num_params;
if (remap->_has_this) {
--max_num_args;
}
}
nassertv(num_params <= (int)remap->_parameters.size());
}
nassertv(num_params <= (int)remap->_parameters.size());
bool only_pyobjects = true;
@ -4584,6 +4594,17 @@ write_function_instance(ostream &out, FunctionRemap *remap,
}
}
if (remap->_flags & FunctionRemap::F_explicit_args) {
// The function handles the arguments by itself.
expected_params += "*args";
pexprs.push_back("args");
if (args_type == AT_keyword_args) {
expected_params += ", **kwargs";
pexprs.push_back("kwds");
}
num_params = 0;
}
// Now convert (the rest of the) actual arguments, one by one.
for (; pn < num_params; ++pn) {
ParameterRemap *param = remap->_parameters[pn]._remap;

View File

@ -659,6 +659,8 @@ PUBLISHED:
INLINE void set_shader_input(CPT_InternalName id, PN_stdfloat n1, PN_stdfloat n2=0,
PN_stdfloat n3=0, PN_stdfloat n4=0, int priority=0);
EXTENSION(void set_shader_inputs(PyObject *args, PyObject *kwargs));
void clear_shader_input(CPT_InternalName id);
void set_instance_count(int instance_count);

View File

@ -13,6 +13,7 @@
#include "nodePath_ext.h"
#include "typedWritable_ext.h"
#include "shaderAttrib.h"
#ifdef HAVE_PYTHON
@ -24,6 +25,35 @@ extern struct Dtool_PyTypedObject Dtool_LPoint3d;
#else
extern struct Dtool_PyTypedObject Dtool_LPoint3f;
#endif
extern struct Dtool_PyTypedObject Dtool_Texture;
extern struct Dtool_PyTypedObject Dtool_NodePath;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_float;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_double;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_int;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4f;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3f;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2f;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4f;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3f;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4d;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3d;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2d;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLMatrix4d;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LMatrix3d;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_UnalignedLVecBase4i;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase3i;
extern struct Dtool_PyTypedObject Dtool_PointerToArray_LVecBase2i;
extern struct Dtool_PyTypedObject Dtool_LVecBase4f;
extern struct Dtool_PyTypedObject Dtool_LVecBase3f;
extern struct Dtool_PyTypedObject Dtool_LVecBase2f;
extern struct Dtool_PyTypedObject Dtool_LVecBase4d;
extern struct Dtool_PyTypedObject Dtool_LVecBase3d;
extern struct Dtool_PyTypedObject Dtool_LVecBase2d;
extern struct Dtool_PyTypedObject Dtool_LVecBase4i;
extern struct Dtool_PyTypedObject Dtool_LVecBase3i;
extern struct Dtool_PyTypedObject Dtool_LVecBase2i;
extern struct Dtool_PyTypedObject Dtool_ShaderBuffer;
extern struct Dtool_PyTypedObject Dtool_ParamValueBase;
#endif // CPPPARSER
/**
@ -211,6 +241,192 @@ py_decode_NodePath_from_bam_stream_persist(PyObject *unpickler, const string &da
return NodePath::decode_from_bam_stream(data, reader);
}
/**
* Sets multiple shader inputs at the same time. This can be significantly
* more efficient if many inputs need to be set at the same time.
*/
void Extension<NodePath>::
set_shader_inputs(PyObject *args, PyObject *kwargs) {
if (PyObject_Size(args) > 0) {
Dtool_Raise_TypeError("NodePath.set_shader_inputs takes only keyword arguments");
return;
}
PT(PandaNode) node = _this->node();
CPT(RenderAttrib) prev_attrib = node->get_attrib(ShaderAttrib::get_class_slot());
PT(ShaderAttrib) attrib;
if (prev_attrib == nullptr) {
attrib = new ShaderAttrib();
} else {
attrib = new ShaderAttrib(*(const ShaderAttrib *)prev_attrib.p());
}
PyObject *key, *value;
Py_ssize_t pos = 0;
while (PyDict_Next(kwargs, &pos, &key, &value)) {
char *buffer;
Py_ssize_t length;
#if PY_MAJOR_VERSION >= 3
buffer = (char *)PyUnicode_AsUTF8AndSize(key, &length);
if (buffer == nullptr) {
#else
if (PyString_AsStringAndSize(key, &buffer, &length) == -1) {
#endif
Dtool_Raise_TypeError("NodePath.set_shader_inputs accepts only string keywords");
return;
}
CPT_InternalName name(string(buffer, length));
ShaderInput *input = nullptr;
if (PyTuple_CheckExact(value)) {
// A tuple is interpreted as a vector.
Py_ssize_t size = PyTuple_GET_SIZE(value);
if (size > 4) {
Dtool_Raise_TypeError("NodePath.set_shader_inputs tuple input should not have more than 4 scalars");
return;
}
// If any of them is a float, we are storing it as a float vector.
bool is_float = false;
for (Py_ssize_t i = 0; i < size; ++i) {
if (PyFloat_CheckExact(PyTuple_GET_ITEM(value, i))) {
is_float = true;
break;
}
}
if (is_float) {
LVecBase4 vec(0);
for (Py_ssize_t i = 0; i < size; ++i) {
vec[i] = (PN_stdfloat)PyFloat_AsDouble(PyTuple_GET_ITEM(value, i));
}
input = new ShaderInput(name, vec);
} else {
LVecBase4i vec(0);
for (Py_ssize_t i = 0; i < size; ++i) {
vec[i] = (int)PyLong_AsLong(PyTuple_GET_ITEM(value, i));
}
input = new ShaderInput(name, vec);
}
} else if (DtoolCanThisBeAPandaInstance(value)) {
Dtool_PyInstDef *inst = (Dtool_PyInstDef *)value;
void *ptr;
if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_Texture))) {
input = new ShaderInput(name, (Texture *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_NodePath))) {
input = new ShaderInput(name, *(const NodePath *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_float))) {
input = new ShaderInput(name, *(const PTA_float *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_double))) {
input = new ShaderInput(name, *(const PTA_double *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_int))) {
input = new ShaderInput(name, *(const PTA_int *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4f))) {
input = new ShaderInput(name, *(const PTA_LVecBase4f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3f))) {
input = new ShaderInput(name, *(const PTA_LVecBase3f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2f))) {
input = new ShaderInput(name, *(const PTA_LVecBase2f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4f))) {
input = new ShaderInput(name, *(const PTA_LMatrix4f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3f))) {
input = new ShaderInput(name, *(const PTA_LMatrix3f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4d))) {
input = new ShaderInput(name, *(const PTA_LVecBase4d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3d))) {
input = new ShaderInput(name, *(const PTA_LVecBase3d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2d))) {
input = new ShaderInput(name, *(const PTA_LVecBase2d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLMatrix4d))) {
input = new ShaderInput(name, *(const PTA_LMatrix4d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LMatrix3d))) {
input = new ShaderInput(name, *(const PTA_LMatrix3d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_UnalignedLVecBase4i))) {
input = new ShaderInput(name, *(const PTA_LVecBase4i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase3i))) {
input = new ShaderInput(name, *(const PTA_LVecBase3i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_PointerToArray_LVecBase2i))) {
input = new ShaderInput(name, *(const PTA_LVecBase2i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4f))) {
input = new ShaderInput(name, *(const LVecBase4f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3f))) {
input = new ShaderInput(name, *(const LVecBase3f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2f))) {
input = new ShaderInput(name, *(const LVecBase2f *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4d))) {
input = new ShaderInput(name, *(const LVecBase4d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3d))) {
input = new ShaderInput(name, *(const LVecBase3d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2d))) {
input = new ShaderInput(name, *(const LVecBase2d *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase4i))) {
input = new ShaderInput(name, *(const LVecBase4i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase3i))) {
input = new ShaderInput(name, *(const LVecBase3i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_LVecBase2i))) {
input = new ShaderInput(name, *(const LVecBase2i *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ShaderBuffer))) {
input = new ShaderInput(name, (ShaderBuffer *)ptr);
} else if ((ptr = inst->_My_Type->_Dtool_UpcastInterface(value, &Dtool_ParamValueBase))) {
input = new ShaderInput(name, (ParamValueBase *)ptr);
} else {
Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs");
return;
}
} else if (PyFloat_Check(value)) {
input = new ShaderInput(name, LVecBase4(PyFloat_AS_DOUBLE(value), 0, 0, 0));
#if PY_MAJOR_VERSION < 3
} else if (PyInt_Check(value)) {
input = new ShaderInput(name, LVecBase4i((int)PyInt_AS_LONG(value), 0, 0, 0));
#endif
} else if (PyLong_Check(value)) {
input = new ShaderInput(name, LVecBase4i((int)PyLong_AsLong(value), 0, 0, 0));
} else {
Dtool_Raise_TypeError("unknown type passed to NodePath.set_shader_inputs");
return;
}
attrib->_inputs[move(name)] = input;
}
node->set_attrib(ShaderAttrib::return_new(attrib));
}
/**
* Returns the tight bounds as a 2-tuple of LPoint3 objects. This is a
* convenience function for Python users, among which the use of

View File

@ -49,6 +49,8 @@ public:
// This is defined to implement cycle detection in Python tags.
INLINE int __traverse__(visitproc visit, void *arg);
void set_shader_inputs(PyObject *args, PyObject *kwargs);
PyObject *get_tight_bounds(const NodePath &other = NodePath()) const;
};

View File

@ -31,6 +31,7 @@
#include "pta_LVecBase4.h"
#include "pta_LVecBase3.h"
#include "pta_LVecBase2.h"
#include "extension.h"
/**
*
@ -147,6 +148,8 @@ private:
typedef pmap<CPT_InternalName, CPT(ShaderInput)> Inputs;
Inputs _inputs;
friend class Extension<NodePath>;
PUBLISHED:
static int get_class_slot() {
return _attrib_slot;