diff options
Diffstat (limited to 'extern/mantaflow/helper/pwrapper')
-rw-r--r-- | extern/mantaflow/helper/pwrapper/manta.h | 31 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/numpyWrap.cpp | 132 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/numpyWrap.h | 86 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pclass.cpp | 220 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pclass.h | 126 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pconvert.cpp | 568 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pconvert.h | 251 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pvec3.cpp | 414 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/pythonInclude.h | 48 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/registry.cpp | 784 | ||||
-rw-r--r-- | extern/mantaflow/helper/pwrapper/registry.h | 106 |
11 files changed, 2766 insertions, 0 deletions
diff --git a/extern/mantaflow/helper/pwrapper/manta.h b/extern/mantaflow/helper/pwrapper/manta.h new file mode 100644 index 00000000000..efbca6cc493 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/manta.h @@ -0,0 +1,31 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Include pwrapper headers + * + ******************************************************************************/ + +#ifndef _MANTA_H +#define _MANTA_H + +// Remove preprocessor keywords, so there won't infere with autocompletion etc. +#define KERNEL(...) extern int i, j, k, idx, X, Y, Z; +#define PYTHON(...) +#define returns(X) extern X; +#define alias typedef + +#include "general.h" +#include "vectorbase.h" +#include "vector4d.h" +#include "registry.h" +#include "pclass.h" +#include "pconvert.h" +#include "fluidsolver.h" + +#endif diff --git a/extern/mantaflow/helper/pwrapper/numpyWrap.cpp b/extern/mantaflow/helper/pwrapper/numpyWrap.cpp new file mode 100644 index 00000000000..d2ddb21be70 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/numpyWrap.cpp @@ -0,0 +1,132 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2017-2018 Steffen Wiewel, Moritz Becher, Rachel Chu + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Convert mantaflow grids to/from numpy arrays + * + ******************************************************************************/ + +#include "manta.h" +#include "pythonInclude.h" + +#define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +#include "numpy/arrayobject.h" + +namespace Manta { + +#if PY_VERSION_HEX < 0x03000000 +PyMODINIT_FUNC initNumpy() +{ + import_array(); +} +#endif + +// ------------------------------------------------------------------------ +// Class Functions +// ------------------------------------------------------------------------ +PyArrayContainer::PyArrayContainer(void *_pParentPyArray) : pParentPyArray(_pParentPyArray) +{ + ExtractData(pParentPyArray); +} +// ------------------------------------------------------------------------ +PyArrayContainer::PyArrayContainer(const PyArrayContainer &_Other) + : pParentPyArray(_Other.pParentPyArray) +{ + ExtractData(pParentPyArray); + Py_INCREF(pParentPyArray); +} +// ------------------------------------------------------------------------ +PyArrayContainer::~PyArrayContainer() +{ + Py_DECREF(pParentPyArray); +} +// ------------------------------------------------------------------------ +PyArrayContainer &PyArrayContainer::operator=(const PyArrayContainer &_Other) +{ + if (this != &_Other) { + // DecRef the existing resource + Py_DECREF(pParentPyArray); + + // Relink new data + pParentPyArray = _Other.pParentPyArray; + ExtractData(pParentPyArray); + Py_INCREF(pParentPyArray); + } + return *this; +} +// ------------------------------------------------------------------------ +void PyArrayContainer::ExtractData(void *_pParentPyArray) +{ + PyArrayObject *pParent = reinterpret_cast<PyArrayObject *>(pParentPyArray); + + int numDims = PyArray_NDIM(pParent); + long *pDims = (long *)PyArray_DIMS(pParent); + + pData = PyArray_DATA(pParent); + TotalSize = PyArray_SIZE(pParent); + Dims = std::vector<long>(&pDims[0], &pDims[numDims]); + + int iDataType = PyArray_TYPE(pParent); + switch (iDataType) { + case NPY_FLOAT: + DataType = N_FLOAT; + break; + case NPY_DOUBLE: + DataType = N_DOUBLE; + break; + case NPY_INT: + DataType = N_INT; + break; + default: + errMsg("unknown type of Numpy array"); + break; + } +} + +// ------------------------------------------------------------------------ +// Conversion Functions +// ------------------------------------------------------------------------ + +template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj) +{ + if (PyArray_API == NULL) { + // python 3 uses the return value +#if PY_VERSION_HEX >= 0x03000000 + import_array(); +#else + initNumpy(); +#endif + } + + if (!PyArray_Check(obj)) { + errMsg("argument is not an numpy array"); + } + + PyArrayObject *obj_p = reinterpret_cast<PyArrayObject *>( + PyArray_CheckFromAny(obj, + NULL, + 0, + 0, + /*NPY_ARRAY_ENSURECOPY*/ NPY_ARRAY_C_CONTIGUOUS | + NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_NOTSWAPPED, + NULL)); + PyArrayContainer container = PyArrayContainer(obj_p); + + return container; +} + +// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* tmp) +// { +// if (!tmp) throw Error("dynamic de-ref not supported for this type"); +// void* ptr = malloc(sizeof(PyArrayContainer)); +// tmp->push_back(ptr); + +// *((PyArrayContainer*) ptr) = fromPy<PyArrayContainer>(obj); +// return (PyArrayContainer*) ptr; +// } +} // namespace Manta diff --git a/extern/mantaflow/helper/pwrapper/numpyWrap.h b/extern/mantaflow/helper/pwrapper/numpyWrap.h new file mode 100644 index 00000000000..c92a2eaaa97 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/numpyWrap.h @@ -0,0 +1,86 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2017 Steffen Wiewel, Moritz Baecher, Rachel Chu + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Convert mantaflow grids to/from numpy arrays + * + ******************************************************************************/ + +#ifdef _PCONVERT_H +# ifndef _NUMPYCONVERT_H +# define _NUMPYCONVERT_H + +enum NumpyTypes { + N_BOOL = 0, + N_BYTE, + N_UBYTE, + N_SHORT, + N_USHORT, + N_INT, + N_UINT, + N_LONG, + N_ULONG, + N_LONGLONG, + N_ULONGLONG, + N_FLOAT, + N_DOUBLE, + N_LONGDOUBLE, + N_CFLOAT, + N_CDOUBLE, + N_CLONGDOUBLE, + N_OBJECT = 17, + N_STRING, + N_UNICODE, + N_VOID, + /* + * New 1.6 types appended, may be integrated + * into the above in 2.0. + */ + N_DATETIME, + N_TIMEDELTA, + N_HALF, + + N_NTYPES, + N_NOTYPE, + N_CHAR, /* special flag */ + N_USERDEF = 256, /* leave room for characters */ + + /* The number of types not including the new 1.6 types */ + N_NTYPES_ABI_COMPATIBLE = 21 +}; + +namespace Manta { +class PyArrayContainer { + public: + /// Constructors + PyArrayContainer(void *_pParentPyArray); + PyArrayContainer(const PyArrayContainer &_Other); + ~PyArrayContainer(); + /// Operators + PyArrayContainer &operator=(const PyArrayContainer &_Other); + + private: + void ExtractData(void *_pParentPyArray); + + public: + void *pData; + NumpyTypes DataType; + unsigned int TotalSize; + std::vector<long> Dims; + + private: + void *pParentPyArray; +}; + +// template<> PyArrayContainer* fromPyPtr<PyArrayContainer>(PyObject* obj, std::vector<void*>* +// tmp); +template<> PyArrayContainer fromPy<PyArrayContainer>(PyObject *obj); +} // namespace Manta + +# endif +#endif diff --git a/extern/mantaflow/helper/pwrapper/pclass.cpp b/extern/mantaflow/helper/pwrapper/pclass.cpp new file mode 100644 index 00000000000..a95254ebe11 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pclass.cpp @@ -0,0 +1,220 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Functions for property setting/getting via python + * + ******************************************************************************/ + +#include "pythonInclude.h" +#include "structmember.h" +#include "manta.h" +#include "general.h" +#include "timing.h" + +#ifdef GUI +# include <QMutex> +#else +class QMutex { + public: + void lock(){}; + void unlock(){}; + bool tryLock() + { + return true; + }; +}; +#endif + +using namespace std; +namespace Manta { + +//****************************************************************************** +// Free functions + +void pbPreparePlugin(FluidSolver *parent, const string &name, bool doTime) +{ + if (doTime) + TimingData::instance().start(parent, name); +} + +void pbFinalizePlugin(FluidSolver *parent, const string &name, bool doTime) +{ + if (doTime) + TimingData::instance().stop(parent, name); + + // GUI update, also print name of parent if there's more than one + std::ostringstream msg; + if (name != "FluidSolver::step") { + if (parent && (parent->getNumInstances() > 0)) + msg << parent->getName() << string("."); + msg << name; + } + updateQtGui(false, 0, 0., msg.str()); + + debMsg(name << " done", 3); + // name unnamed PbClass Objects from var name + PbClass::renameObjects(); +} + +void pbSetError(const string &fn, const string &ex) +{ + debMsg("Error in " << fn, 1); + if (!ex.empty()) + PyErr_SetString(PyExc_RuntimeError, ex.c_str()); +} + +//****************************************************************************** +// Helpers + +string PbTypeVec::str() const +{ + if (T.empty()) + return ""; + string s = "<"; + for (int i = 0; i < (int)T.size(); i++) { + s += T[i].str(); + s += (i != (int)T.size() - 1) ? ',' : '>'; + } + return s; +} +string PbType::str() const +{ + if (S == "float") + return "Real"; + if (S == "manta.vec3") + return "Vec3"; + return S; +} + +//****************************************************************************** +// PbClass + +vector<PbClass *> PbClass::mInstances; + +PbClass::PbClass(FluidSolver *parent, const string &name, PyObject *obj) + : mMutex(NULL), mParent(parent), mPyObject(obj), mName(name), mHidden(false) +{ + mMutex = new QMutex(); +} + +PbClass::PbClass(const PbClass &a) + : mMutex(NULL), mParent(a.mParent), mPyObject(0), mName("_unnamed"), mHidden(false) +{ + mMutex = new QMutex(); +} + +PbClass::~PbClass() +{ + for (vector<PbClass *>::iterator it = mInstances.begin(); it != mInstances.end(); ++it) { + if (*it == this) { + mInstances.erase(it); + break; + } + } + delete mMutex; +} + +void PbClass::lock() +{ + mMutex->lock(); +} +void PbClass::unlock() +{ + mMutex->unlock(); +} +bool PbClass::tryLock() +{ + return mMutex->tryLock(); +} + +PbClass *PbClass::getInstance(int idx) +{ + if (idx < 0 || idx > (int)mInstances.size()) + errMsg("PbClass::getInstance(): invalid index"); + return mInstances[idx]; +} + +int PbClass::getNumInstances() +{ + return mInstances.size(); +} + +bool PbClass::isNullRef(PyObject *obj) +{ + return PyLong_Check(obj) && PyLong_AsDouble(obj) == 0; +} + +bool PbClass::isNoneRef(PyObject *obj) +{ + return (obj == Py_None); +} + +void PbClass::registerObject(PyObject *obj, PbArgs *args) +{ + // cross link + Pb::setReference(this, obj); + mPyObject = obj; + + mInstances.push_back(this); + + if (args) { + string _name = args->getOpt<std::string>("name", -1, ""); + if (!_name.empty()) + setName(_name); + } +} + +PbClass *PbClass::createPyObject(const string &classname, + const string &name, + PbArgs &args, + PbClass *parent) +{ + return Pb::createPy(classname, name, args, parent); +} + +void PbClass::checkParent() +{ + if (getParent() == NULL) { + errMsg("New class " + mName + ": no parent given -- specify using parent=xxx !"); + } +} +//! Assign unnamed PbClass objects their Python variable name +void PbClass::renameObjects() +{ + PyObject *sys_mod_dict = PyImport_GetModuleDict(); + PyObject *loc_mod = PyMapping_GetItemString(sys_mod_dict, (char *)"__main__"); + if (!loc_mod) + return; + PyObject *locdict = PyObject_GetAttrString(loc_mod, "__dict__"); + if (!locdict) + return; + + // iterate all PbClass instances + for (size_t i = 0; i < mInstances.size(); i++) { + PbClass *obj = mInstances[i]; + if (obj->getName().empty()) { + // empty, try to find instance in module local dictionary + + PyObject *lkey, *lvalue; + Py_ssize_t lpos = 0; + while (PyDict_Next(locdict, &lpos, &lkey, &lvalue)) { + if (lvalue == obj->mPyObject) { + string varName = fromPy<string>(PyObject_Str(lkey)); + obj->setName(varName); + // cout << "assigning variable name '" << varName << "' to unnamed instance" << endl; + break; + } + } + } + } + Py_DECREF(locdict); + Py_DECREF(loc_mod); +} + +} // namespace Manta diff --git a/extern/mantaflow/helper/pwrapper/pclass.h b/extern/mantaflow/helper/pwrapper/pclass.h new file mode 100644 index 00000000000..b34103ca9a7 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pclass.h @@ -0,0 +1,126 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Base class for all Python-exposed classes + * + ******************************************************************************/ + +// ----------------------------------------------------------------- +// NOTE: +// Do not include this file in user code, include "manta.h" instead +// ----------------------------------------------------------------- + +#ifdef _MANTA_H +# ifndef _PTYPE_H +# define _PTYPE_H + +# include <string> +# include <vector> +# include <map> + +class QMutex; + +namespace Manta { +struct PbClassData; +class FluidSolver; +class PbArgs; + +struct PbType { + std::string S; + std::string str() const; +}; +struct PbTypeVec { + std::vector<PbType> T; + std::string str() const; +}; + +//! Base class for all classes exposed to Python +class PbClass { + public: + PbClass(FluidSolver *parent, const std::string &name = "", PyObject *obj = NULL); + PbClass(const PbClass &a); + virtual ~PbClass(); + + // basic property setter/getters + void setName(const std::string &name) + { + mName = name; + } + std::string getName() const + { + return mName; + } + PyObject *getPyObject() const + { + return mPyObject; + } + void registerObject(PyObject *obj, PbArgs *args); + FluidSolver *getParent() const + { + return mParent; + } + void setParent(FluidSolver *v) + { + mParent = v; + } + void checkParent(); + + // hidden flag for GUI, debug output + inline bool isHidden() + { + return mHidden; + } + inline void setHidden(bool v) + { + mHidden = v; + } + + void lock(); + void unlock(); + bool tryLock(); + + // PbClass instance registry + static int getNumInstances(); + static PbClass *getInstance(int index); + static void renameObjects(); + + // converters + static bool isNullRef(PyObject *o); + static bool isNoneRef(PyObject *o); + static PbClass *createPyObject(const std::string &classname, + const std::string &name, + PbArgs &args, + PbClass *parent); + inline bool canConvertTo(const std::string &classname) + { + return Pb::canConvert(mPyObject, classname); + } + + protected: + QMutex *mMutex; + FluidSolver *mParent; + PyObject *mPyObject; + std::string mName; + bool mHidden; + + static std::vector<PbClass *> mInstances; +}; + +//!\cond Register + +void pbFinalizePlugin(FluidSolver *parent, const std::string &name, bool doTime = true); +void pbPreparePlugin(FluidSolver *parent, const std::string &name, bool doTime = true); +void pbSetError(const std::string &fn, const std::string &ex); + +//!\endcond + +} // namespace Manta + +# endif +#endif diff --git a/extern/mantaflow/helper/pwrapper/pconvert.cpp b/extern/mantaflow/helper/pwrapper/pconvert.cpp new file mode 100644 index 00000000000..c8c92cbf585 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pconvert.cpp @@ -0,0 +1,568 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Python argument wrappers and conversion tools + * + ******************************************************************************/ + +#include "pythonInclude.h" +#include <sstream> +#include <algorithm> +#include "vectorbase.h" +#include "manta.h" + +using namespace std; + +//****************************************************************************** +// Explicit definition and instantiation of python object converters + +namespace Manta { + +extern PyTypeObject PbVec3Type; +extern PyTypeObject PbVec4Type; + +struct PbVec3 { + PyObject_HEAD float data[3]; +}; + +struct PbVec4 { + PyObject_HEAD float data[4]; +}; + +PyObject *getPyNone() +{ + Py_INCREF(Py_None); + return Py_None; +} +PyObject *incref(PyObject *obj) +{ + Py_INCREF(obj); + return obj; +} + +/*template<> PyObject* toPy<PyObject*>(PyObject* obj) { + return obj; +}*/ +template<> PyObject *toPy<int>(const int &v) +{ + return PyLong_FromLong(v); +} +/*template<> PyObject* toPy<char*>(const (char*) & val) { + return PyUnicode_DecodeLatin1(val,strlen(val),"replace"); +}*/ +template<> PyObject *toPy<string>(const string &val) +{ + return PyUnicode_DecodeLatin1(val.c_str(), val.length(), "replace"); +} +template<> PyObject *toPy<float>(const float &v) +{ + return PyFloat_FromDouble(v); +} +template<> PyObject *toPy<double>(const double &v) +{ + return PyFloat_FromDouble(v); +} +template<> PyObject *toPy<bool>(const bool &v) +{ + return PyBool_FromLong(v); +} +template<> PyObject *toPy<Vec3i>(const Vec3i &v) +{ + float x = (float)v.x, y = (float)v.y, z = (float)v.z; + return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z); +} +template<> PyObject *toPy<Vec3>(const Vec3 &v) +{ + float x = (float)v.x, y = (float)v.y, z = (float)v.z; + return PyObject_CallFunction((PyObject *)&PbVec3Type, (char *)"fff", x, y, z); +} +template<> PyObject *toPy<Vec4i>(const Vec4i &v) +{ + float x = (float)v.x, y = (float)v.y, z = (float)v.z; + return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z); +} +template<> PyObject *toPy<Vec4>(const Vec4 &v) +{ + float x = (float)v.x, y = (float)v.y, z = (float)v.z; + return PyObject_CallFunction((PyObject *)&PbVec4Type, (char *)"ffff", x, y, z); +} +template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj) +{ + return obj->getPyObject(); +} + +template<> float fromPy<float>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return PyInt_AsLong(obj); +#endif + if (PyFloat_Check(obj)) + return PyFloat_AsDouble(obj); + if (PyLong_Check(obj)) + return PyLong_AsDouble(obj); + errMsg("argument is not a float"); +} +template<> double fromPy<double>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return PyInt_AsLong(obj); +#endif + if (PyFloat_Check(obj)) + return PyFloat_AsDouble(obj); + if (PyLong_Check(obj)) + return PyLong_AsDouble(obj); + errMsg("argument is not a double"); +} +template<> PyObject *fromPy<PyObject *>(PyObject *obj) +{ + return obj; +} +template<> int fromPy<int>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return PyInt_AsLong(obj); +#endif + if (PyLong_Check(obj)) + return PyLong_AsDouble(obj); + if (PyFloat_Check(obj)) { + double a = PyFloat_AsDouble(obj); + if (fabs(a - floor(a + 0.5)) > 1e-5) + errMsg("argument is not an int"); + return (int)(a + 0.5); + } + errMsg("argument is not an int"); +} +template<> string fromPy<string>(PyObject *obj) +{ + if (PyUnicode_Check(obj)) + return PyBytes_AsString(PyUnicode_AsLatin1String(obj)); +#if PY_MAJOR_VERSION <= 2 + else if (PyString_Check(obj)) + return PyString_AsString(obj); +#endif + else + errMsg("argument is not a string"); +} +template<> const char *fromPy<const char *>(PyObject *obj) +{ + if (PyUnicode_Check(obj)) + return PyBytes_AsString(PyUnicode_AsLatin1String(obj)); +#if PY_MAJOR_VERSION <= 2 + else if (PyString_Check(obj)) + return PyString_AsString(obj); +#endif + else + errMsg("argument is not a string"); +} +template<> bool fromPy<bool>(PyObject *obj) +{ + if (!PyBool_Check(obj)) + errMsg("argument is not a boolean"); + return PyLong_AsLong(obj) != 0; +} +template<> Vec3 fromPy<Vec3>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) { + return Vec3(((PbVec3 *)obj)->data); + } + else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) { + return Vec3(fromPy<Real>(PyTuple_GetItem(obj, 0)), + fromPy<Real>(PyTuple_GetItem(obj, 1)), + fromPy<Real>(PyTuple_GetItem(obj, 2))); + } + errMsg("argument is not a Vec3"); +} +template<> Vec3i fromPy<Vec3i>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) { + return toVec3iChecked(((PbVec3 *)obj)->data); + } + else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) { + return Vec3i(fromPy<int>(PyTuple_GetItem(obj, 0)), + fromPy<int>(PyTuple_GetItem(obj, 1)), + fromPy<int>(PyTuple_GetItem(obj, 2))); + } + errMsg("argument is not a Vec3i"); +} +template<> Vec4 fromPy<Vec4>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) { + return Vec4(((PbVec4 *)obj)->data); + } + else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) { + return Vec4(fromPy<Real>(PyTuple_GetItem(obj, 0)), + fromPy<Real>(PyTuple_GetItem(obj, 1)), + fromPy<Real>(PyTuple_GetItem(obj, 2)), + fromPy<Real>(PyTuple_GetItem(obj, 3))); + } + errMsg("argument is not a Vec4"); +} +template<> Vec4i fromPy<Vec4i>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) { + return toVec4i(((PbVec4 *)obj)->data); + } + else if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) { + return Vec4i(fromPy<int>(PyTuple_GetItem(obj, 0)), + fromPy<int>(PyTuple_GetItem(obj, 1)), + fromPy<int>(PyTuple_GetItem(obj, 2)), + fromPy<int>(PyTuple_GetItem(obj, 3))); + } + errMsg("argument is not a Vec4i"); +} +template<> PbType fromPy<PbType>(PyObject *obj) +{ + PbType pb = {""}; + if (!PyType_Check(obj)) + return pb; + + const char *tname = ((PyTypeObject *)obj)->tp_name; + pb.S = tname; + return pb; +} +template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj) +{ + PbTypeVec vec; + if (PyType_Check(obj)) { + vec.T.push_back(fromPy<PbType>(obj)); + } + else if (PyTuple_Check(obj)) { + int sz = PyTuple_Size(obj); + for (int i = 0; i < sz; i++) + vec.T.push_back(fromPy<PbType>(PyTuple_GetItem(obj, i))); + } + else + errMsg("argument is not a type tuple"); + return vec; +} + +template<class T> T *tmpAlloc(PyObject *obj, std::vector<void *> *tmp) +{ + if (!tmp) + throw Error("dynamic de-ref not supported for this type"); + void *ptr = malloc(sizeof(T)); + tmp->push_back(ptr); + + *((T *)ptr) = fromPy<T>(obj); + return (T *)ptr; +} +template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<float>(obj, tmp); +} +template<> double *fromPyPtr<double>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<double>(obj, tmp); +} +template<> int *fromPyPtr<int>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<int>(obj, tmp); +} +template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<std::string>(obj, tmp); +} +template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<bool>(obj, tmp); +} +template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<Vec3>(obj, tmp); +} +template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<Vec3i>(obj, tmp); +} +template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<Vec4>(obj, tmp); +} +template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp) +{ + return tmpAlloc<Vec4i>(obj, tmp); +} + +template<> bool isPy<float>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return true; +#endif + return PyFloat_Check(obj) || PyLong_Check(obj); +} +template<> bool isPy<double>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return true; +#endif + return PyFloat_Check(obj) || PyLong_Check(obj); +} +template<> bool isPy<PyObject *>(PyObject *obj) +{ + return true; +} +template<> bool isPy<int>(PyObject *obj) +{ +#if PY_MAJOR_VERSION <= 2 + if (PyInt_Check(obj)) + return true; +#endif + if (PyLong_Check(obj)) + return true; + if (PyFloat_Check(obj)) { + double a = PyFloat_AsDouble(obj); + return fabs(a - floor(a + 0.5)) < 1e-5; + } + return false; +} +template<> bool isPy<string>(PyObject *obj) +{ + if (PyUnicode_Check(obj)) + return true; +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(obj)) + return true; +#endif + return false; +} +template<> bool isPy<const char *>(PyObject *obj) +{ + if (PyUnicode_Check(obj)) + return true; +#if PY_MAJOR_VERSION <= 2 + if (PyString_Check(obj)) + return true; +#endif + return false; +} +template<> bool isPy<bool>(PyObject *obj) +{ + return PyBool_Check(obj); +} +template<> bool isPy<Vec3>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) + return true; + if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) { + return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) && + isPy<Real>(PyTuple_GetItem(obj, 2)); + } + return false; +} +template<> bool isPy<Vec3i>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec3Type)) + return true; + if (PyTuple_Check(obj) && PyTuple_Size(obj) == 3) { + return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) && + isPy<int>(PyTuple_GetItem(obj, 2)); + } + return false; +} +template<> bool isPy<Vec4>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) + return true; + if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) { + return isPy<Real>(PyTuple_GetItem(obj, 0)) && isPy<Real>(PyTuple_GetItem(obj, 1)) && + isPy<Real>(PyTuple_GetItem(obj, 2)) && isPy<Real>(PyTuple_GetItem(obj, 3)); + } + return false; +} +template<> bool isPy<Vec4i>(PyObject *obj) +{ + if (PyObject_IsInstance(obj, (PyObject *)&PbVec4Type)) + return true; + if (PyTuple_Check(obj) && PyTuple_Size(obj) == 4) { + return isPy<int>(PyTuple_GetItem(obj, 0)) && isPy<int>(PyTuple_GetItem(obj, 1)) && + isPy<int>(PyTuple_GetItem(obj, 2)) && isPy<int>(PyTuple_GetItem(obj, 3)); + } + return false; +} +template<> bool isPy<PbType>(PyObject *obj) +{ + return PyType_Check(obj); +} + +//****************************************************************************** +// PbArgs class defs + +PbArgs PbArgs::EMPTY(NULL, NULL); + +PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0) +{ + setup(linarg, dict); +} +PbArgs::~PbArgs() +{ + for (int i = 0; i < (int)mTmpStorage.size(); i++) + free(mTmpStorage[i]); + mTmpStorage.clear(); +} + +void PbArgs::copy(PbArgs &a) +{ + mKwds = a.mKwds; + mData = a.mData; + mLinData = a.mLinData; + mLinArgs = a.mLinArgs; +} +void PbArgs::clear() +{ + mLinArgs = 0; + mKwds = 0; + mData.clear(); + mLinData.clear(); +} + +PbArgs &PbArgs::operator=(const PbArgs &a) +{ + // mLinArgs = 0; + // mKwds = 0; + return *this; +} + +void PbArgs::setup(PyObject *linarg, PyObject *dict) +{ + if (dict) { + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(dict, &pos, &key, &value)) { + DataElement el; + el.obj = value; + el.visited = false; + mData[fromPy<string>(key)] = el; + } + mKwds = dict; + } + if (linarg) { + size_t len = PyTuple_Size(linarg); + for (size_t i = 0; i < len; i++) { + DataElement el; + el.obj = PyTuple_GetItem(linarg, i); + el.visited = false; + mLinData.push_back(el); + } + mLinArgs = linarg; + } +} + +void PbArgs::addLinArg(PyObject *obj) +{ + DataElement el = {obj, false}; + mLinData.push_back(el); +} + +void PbArgs::check() +{ + if (has("nocheck")) + return; + + for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) { + if (!it->second.visited) + errMsg("Argument '" + it->first + "' unknown"); + } + for (size_t i = 0; i < mLinData.size(); i++) { + if (!mLinData[i].visited) { + stringstream s; + s << "Function does not read argument number #" << i; + errMsg(s.str()); + } + } +} + +FluidSolver *PbArgs::obtainParent() +{ + FluidSolver *solver = getPtrOpt<FluidSolver>("solver", -1, NULL); + if (solver != 0) + return solver; + + for (map<string, DataElement>::iterator it = mData.begin(); it != mData.end(); it++) { + PbClass *obj = Pb::objFromPy(it->second.obj); + + if (obj) { + if (solver == NULL) + solver = obj->getParent(); + } + } + for (vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) { + PbClass *obj = Pb::objFromPy(it->obj); + + if (obj) { + if (solver == NULL) + solver = obj->getParent(); + } + } + + return solver; +} + +void PbArgs::visit(int number, const string &key) +{ + if (number >= 0 && number < (int)mLinData.size()) + mLinData[number].visited = true; + map<string, DataElement>::iterator lu = mData.find(key); + if (lu != mData.end()) + lu->second.visited = true; +} + +PyObject *PbArgs::getItem(const std::string &key, bool strict, ArgLocker *lk) +{ + map<string, DataElement>::iterator lu = mData.find(key); + if (lu == mData.end()) { + if (strict) + errMsg("Argument '" + key + "' is not defined."); + return NULL; + } + PbClass *pbo = Pb::objFromPy(lu->second.obj); + // try to lock + if (pbo && lk) + lk->add(pbo); + return lu->second.obj; +} + +PyObject *PbArgs::getItem(size_t number, bool strict, ArgLocker *lk) +{ + if (number >= mLinData.size()) { + if (!strict) + return NULL; + stringstream s; + s << "Argument number #" << number << " not specified."; + errMsg(s.str()); + } + PbClass *pbo = Pb::objFromPy(mLinData[number].obj); + // try to lock + if (pbo && lk) + lk->add(pbo); + return mLinData[number].obj; +} + +//****************************************************************************** +// ArgLocker class defs + +void ArgLocker::add(PbClass *p) +{ + if (find(locks.begin(), locks.end(), p) == locks.end()) { + locks.push_back(p); + p->lock(); + } +} +ArgLocker::~ArgLocker() +{ + for (size_t i = 0; i < locks.size(); i++) + locks[i]->unlock(); + locks.clear(); +} + +} // namespace Manta diff --git a/extern/mantaflow/helper/pwrapper/pconvert.h b/extern/mantaflow/helper/pwrapper/pconvert.h new file mode 100644 index 00000000000..9c72b8b57b9 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pconvert.h @@ -0,0 +1,251 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Python argument wrappers and conversion tools + * + ******************************************************************************/ + +// ----------------------------------------------------------------- +// NOTE: +// Do not include this file in user code, include "manta.h" instead +// ----------------------------------------------------------------- + +#ifdef _MANTA_H +# ifndef _PCONVERT_H +# define _PCONVERT_H + +# include <string> +# include <map> +# include <vector> + +namespace Manta { +template<class T> class Grid; + +//! Locks the given PbClass Arguments until ArgLocker goes out of scope +struct ArgLocker { + void add(PbClass *p); + ~ArgLocker(); + std::vector<PbClass *> locks; +}; + +PyObject *getPyNone(); + +// for PbClass-derived classes +template<class T> T *fromPyPtr(PyObject *obj, std::vector<void *> *tmp) +{ + if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj)) + return 0; + PbClass *pbo = Pb::objFromPy(obj); + const std::string &type = Namify<T>::S; + if (!pbo || !(pbo->canConvertTo(type))) + throw Error("can't convert argument to " + type + "*"); + return (T *)(pbo); +} + +template<> float *fromPyPtr<float>(PyObject *obj, std::vector<void *> *tmp); +template<> double *fromPyPtr<double>(PyObject *obj, std::vector<void *> *tmp); +template<> int *fromPyPtr<int>(PyObject *obj, std::vector<void *> *tmp); +template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<void *> *tmp); +template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<void *> *tmp); +template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<void *> *tmp); +template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<void *> *tmp); +template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<void *> *tmp); +template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<void *> *tmp); + +PyObject *incref(PyObject *obj); +template<class T> PyObject *toPy(const T &v) +{ + PyObject *obj = v.getPyObject(); + if (obj) { + return incref(obj); + } + T *co = new T(v); + const std::string &type = Namify<typename remove_pointers<T>::type>::S; + return Pb::copyObject(co, type); +} +template<class T> bool isPy(PyObject *obj) +{ + if (PbClass::isNullRef(obj) || PbClass::isNoneRef(obj)) + return false; + PbClass *pbo = Pb::objFromPy(obj); + const std::string &type = Namify<typename remove_pointers<T>::type>::S; + return pbo && pbo->canConvertTo(type); +} + +template<class T> T fromPy(PyObject *obj) +{ + throw Error( + "Unknown type conversion. Did you pass a PbClass by value? Instead always pass " + "grids/particlesystems/etc. by reference or using a pointer."); +} + +// builtin types +template<> float fromPy<float>(PyObject *obj); +template<> double fromPy<double>(PyObject *obj); +template<> int fromPy<int>(PyObject *obj); +template<> PyObject *fromPy<PyObject *>(PyObject *obj); +template<> std::string fromPy<std::string>(PyObject *obj); +template<> const char *fromPy<const char *>(PyObject *obj); +template<> bool fromPy<bool>(PyObject *obj); +template<> Vec3 fromPy<Vec3>(PyObject *obj); +template<> Vec3i fromPy<Vec3i>(PyObject *obj); +template<> Vec4 fromPy<Vec4>(PyObject *obj); +template<> Vec4i fromPy<Vec4i>(PyObject *obj); +template<> PbType fromPy<PbType>(PyObject *obj); +template<> PbTypeVec fromPy<PbTypeVec>(PyObject *obj); + +template<> PyObject *toPy<int>(const int &v); +template<> PyObject *toPy<std::string>(const std::string &val); +template<> PyObject *toPy<float>(const float &v); +template<> PyObject *toPy<double>(const double &v); +template<> PyObject *toPy<bool>(const bool &v); +template<> PyObject *toPy<Vec3i>(const Vec3i &v); +template<> PyObject *toPy<Vec3>(const Vec3 &v); +template<> PyObject *toPy<Vec4i>(const Vec4i &v); +template<> PyObject *toPy<Vec4>(const Vec4 &v); +typedef PbClass *PbClass_Ptr; +template<> PyObject *toPy<PbClass *>(const PbClass_Ptr &obj); + +template<> bool isPy<float>(PyObject *obj); +template<> bool isPy<double>(PyObject *obj); +template<> bool isPy<int>(PyObject *obj); +template<> bool isPy<PyObject *>(PyObject *obj); +template<> bool isPy<std::string>(PyObject *obj); +template<> bool isPy<const char *>(PyObject *obj); +template<> bool isPy<bool>(PyObject *obj); +template<> bool isPy<Vec3>(PyObject *obj); +template<> bool isPy<Vec3i>(PyObject *obj); +template<> bool isPy<Vec4>(PyObject *obj); +template<> bool isPy<Vec4i>(PyObject *obj); +template<> bool isPy<PbType>(PyObject *obj); + +//! Encapsulation of python arguments +class PbArgs { + public: + PbArgs(PyObject *linargs = NULL, PyObject *dict = NULL); + ~PbArgs(); + void setup(PyObject *linargs = NULL, PyObject *dict = NULL); + + void check(); + FluidSolver *obtainParent(); + + inline int numLinArgs() + { + return mLinData.size(); + } + + inline bool has(const std::string &key) + { + return getItem(key, false) != NULL; + } + inline void deleteItem(const std::string &key) + { + if (mData.find(key) != mData.end()) + mData.erase(mData.find(key)); + } + + inline PyObject *linArgs() + { + return mLinArgs; + } + inline PyObject *kwds() + { + return mKwds; + } + + void addLinArg(PyObject *obj); + + template<class T> inline void add(const std::string &key, T arg) + { + DataElement el = {toPy(arg), false}; + mData[key] = el; + } + template<class T> inline T get(const std::string &key, int number = -1, ArgLocker *lk = NULL) + { + visit(number, key); + PyObject *o = getItem(key, false, lk); + if (o) + return fromPy<T>(o); + o = getItem(number, false, lk); + if (o) + return fromPy<T>(o); + errMsg("Argument '" + key + "' is not defined."); + } + template<class T> + inline T getOpt(const std::string &key, int number, T defarg, ArgLocker *lk = NULL) + { + visit(number, key); + PyObject *o = getItem(key, false, lk); + if (o) + return fromPy<T>(o); + if (number >= 0) + o = getItem(number, false, lk); + return (o) ? fromPy<T>(o) : defarg; + } + template<class T> + inline T *getPtrOpt(const std::string &key, int number, T *defarg, ArgLocker *lk = NULL) + { + visit(number, key); + PyObject *o = getItem(key, false, lk); + if (o) + return fromPyPtr<T>(o, &mTmpStorage); + if (number >= 0) + o = getItem(number, false, lk); + return o ? fromPyPtr<T>(o, &mTmpStorage) : defarg; + } + template<class T> inline T *getPtr(const std::string &key, int number = -1, ArgLocker *lk = NULL) + { + visit(number, key); + PyObject *o = getItem(key, false, lk); + if (o) + return fromPyPtr<T>(o, &mTmpStorage); + o = getItem(number, false, lk); + if (o) + return fromPyPtr<T>(o, &mTmpStorage); + errMsg("Argument '" + key + "' is not defined."); + } + + // automatic template type deduction + template<class T> bool typeCheck(int num, const std::string &name) + { + PyObject *o = getItem(name, false, 0); + if (!o) + o = getItem(num, false, 0); + return o ? isPy<typename remove_pointers<T>::type>(o) : false; + } + + PbArgs &operator=(const PbArgs &a); // dummy + void copy(PbArgs &a); + void clear(); + void visit(int num, const std::string &key); + + static PbArgs EMPTY; + + protected: + PyObject *getItem(const std::string &key, bool strict, ArgLocker *lk = NULL); + PyObject *getItem(size_t number, bool strict, ArgLocker *lk = NULL); + + struct DataElement { + PyObject *obj; + bool visited; + }; + std::map<std::string, DataElement> mData; + std::vector<DataElement> mLinData; + PyObject *mLinArgs, *mKwds; + std::vector<void *> mTmpStorage; +}; + +} // namespace Manta + +# if NUMPY == 1 +# include "numpyWrap.h" +# endif + +# endif +#endif diff --git a/extern/mantaflow/helper/pwrapper/pvec3.cpp b/extern/mantaflow/helper/pwrapper/pvec3.cpp new file mode 100644 index 00000000000..69bde2a2ad0 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pvec3.cpp @@ -0,0 +1,414 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Vec3 class extension for python + * + ******************************************************************************/ + +#include "pythonInclude.h" +#include <string> +#include <sstream> +#include "vectorbase.h" +#include "structmember.h" +#include "manta.h" + +using namespace std; + +namespace Manta { + +extern PyTypeObject PbVec3Type; + +struct PbVec3 { + PyObject_HEAD float data[3]; +}; + +static void PbVec3Dealloc(PbVec3 *self) +{ + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject *PbVec3New(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static int PbVec3Init(PbVec3 *self, PyObject *args, PyObject *kwds) +{ + + float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1; + if (!PyArg_ParseTuple(args, "|fff", &x1, &x2, &x3)) + return -1; + + if (!c_isnan(x1)) { + self->data[0] = x1; + if (!c_isnan(x2) && !c_isnan(x3)) { + self->data[1] = x2; + self->data[2] = x3; + } + else { + if (!c_isnan(x2) || !c_isnan(x3)) { + errMsg("Invalid partial init of vec3"); + } + self->data[1] = x1; + self->data[2] = x1; + } + } + else { + self->data[0] = 0; + self->data[1] = 0; + self->data[2] = 0; + } + return 0; +} + +static PyObject *PbVec3Repr(PbVec3 *self) +{ + Manta::Vec3 v(self->data[0], self->data[1], self->data[2]); + return PyUnicode_FromFormat(v.toString().c_str()); +} + +static PyMemberDef PbVec3Members[] = { + {(char *)"x", T_FLOAT, offsetof(PbVec3, data), 0, (char *)"X"}, + {(char *)"y", T_FLOAT, offsetof(PbVec3, data) + sizeof(float), 0, (char *)"Y"}, + {(char *)"z", T_FLOAT, offsetof(PbVec3, data) + sizeof(float) * 2, 0, (char *)"Z"}, + {NULL} // Sentinel +}; + +static PyMethodDef PbVec3Methods[] = { + //{"name", (PyCFunction)Noddy_name, METH_NOARGS, "Return the name, combining the first and last + //name" }, + {NULL} // Sentinel +}; + +// operator overloads + +inline PyObject *PbNew(const Vec3 &a) +{ + PbVec3 *obj = (PbVec3 *)PbVec3New(&PbVec3Type, 0, 0); + obj->data[0] = a.x; + obj->data[1] = a.y; + obj->data[2] = a.z; + return (PyObject *)obj; +} + +#define CONVERTVEC(obj) \ + Vec3 v##obj; \ + if (PyObject_TypeCheck(obj, &PbVec3Type)) \ + v##obj = Vec3(&(((PbVec3 *)obj)->data[0])); \ + else if (PyFloat_Check(obj)) \ + v##obj = Vec3(PyFloat_AsDouble(obj)); \ + else if (PyLong_Check(obj)) \ + v##obj = Vec3(PyLong_AsDouble(obj)); \ + else { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } + +#define OPHEADER \ + if (!PyObject_TypeCheck(a, &PbVec3Type) && !PyObject_TypeCheck(b, &PbVec3Type)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + CONVERTVEC(a) \ + CONVERTVEC(b) + +#define OPHEADER1 \ + if (!PyObject_TypeCheck(a, &PbVec3Type)) { \ + Py_INCREF(Py_NotImplemented); \ + return Py_NotImplemented; \ + } \ + CONVERTVEC(a) + +PyObject *PbVec3Add(PyObject *a, PyObject *b) +{ + OPHEADER + return PbNew(va + vb); +} + +PyObject *PbVec3Sub(PyObject *a, PyObject *b) +{ + OPHEADER + return PbNew(va - vb); +} + +PyObject *PbVec3Mult(PyObject *a, PyObject *b) +{ + OPHEADER + return PbNew(va * vb); +} + +PyObject *PbVec3Div(PyObject *a, PyObject *b) +{ + OPHEADER + return PbNew(va / vb); +} + +PyObject *PbVec3Negative(PyObject *a) +{ + OPHEADER1 + return PbNew(-va); +} + +// numbers are defined subtely different in Py3 (WTF?) +#if PY_MAJOR_VERSION >= 3 +static PyNumberMethods PbVec3NumberMethods = { + (binaryfunc)PbVec3Add, // binaryfunc nb_add; + (binaryfunc)PbVec3Sub, // binaryfunc nb_sub; + (binaryfunc)PbVec3Mult, // binaryfunc nb_mult; + 0, // binaryfunc nb_remainder; + 0, // binaryfunc nb_divmod; + 0, // ternaryfunc nb_power; + (unaryfunc)PbVec3Negative, // unaryfunc nb_negative; + 0, // unaryfunc nb_positive; + 0, // unaryfunc nb_absolute; + 0, // inquiry nb_bool; + 0, // unaryfunc nb_invert; + 0, // binaryfunc nb_lshift; + 0, // binaryfunc nb_rshift; + 0, // binaryfunc nb_and; + 0, // binaryfunc nb_xor; + 0, // binaryfunc nb_or; + 0, // unaryfunc nb_int; + 0, // void *nb_reserved; + 0, // unaryfunc nb_float; + 0, // binaryfunc nb_inplace_add; + 0, // binaryfunc nb_inplace_subtract; + 0, // binaryfunc nb_inplace_multiply; + 0, // binaryfunc nb_inplace_remainder; + 0, // ternaryfunc nb_inplace_power; + 0, // binaryfunc nb_inplace_lshift; + 0, // binaryfunc nb_inplace_rshift; + 0, // binaryfunc nb_inplace_and; + 0, // binaryfunc nb_inplace_xor; + 0, // binaryfunc nb_inplace_or; + + 0, // binaryfunc nb_floor_divide; + (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide; + 0, // binaryfunc nb_inplace_floor_divide; + 0, // binaryfunc nb_inplace_true_divide; + + 0 // unaryfunc nb_index; +}; +#else +static PyNumberMethods PbVec3NumberMethods = { + (binaryfunc)PbVec3Add, // binaryfunc nb_add; + (binaryfunc)PbVec3Sub, // binaryfunc nb_sub; + (binaryfunc)PbVec3Mult, // binaryfunc nb_mult; + 0, // binaryfunc nb_divide; + 0, // binaryfunc nb_remainder; + 0, // binaryfunc nb_divmod; + 0, // ternaryfunc nb_power; + (unaryfunc)PbVec3Negative, // unaryfunc nb_negative; + 0, // unaryfunc nb_positive; + 0, // unaryfunc nb_absolute; + 0, // inquiry nb_nonzero; + 0, // unaryfunc nb_invert; + 0, // binaryfunc nb_lshift; + 0, // binaryfunc nb_rshift; + 0, // binaryfunc nb_and; + 0, // binaryfunc nb_xor; + 0, // binaryfunc nb_or; + 0, // coercion nb_coerce; + 0, // unaryfunc nb_int; + 0, // unaryfunc nb_long; + 0, // unaryfunc nb_float; + 0, // unaryfunc nb_oct; + 0, // unaryfunc nb_hex; + 0, // binaryfunc nb_inplace_add; + 0, // binaryfunc nb_inplace_subtract; + 0, // binaryfunc nb_inplace_multiply; + 0, // binaryfunc nb_inplace_divide; + 0, // binaryfunc nb_inplace_remainder; + 0, // ternaryfunc nb_inplace_power; + 0, // binaryfunc nb_inplace_lshift; + 0, // binaryfunc nb_inplace_rshift; + 0, // binaryfunc nb_inplace_and; + 0, // binaryfunc nb_inplace_xor; + 0, // binaryfunc nb_inplace_or; + 0, // binaryfunc nb_floor_divide; + (binaryfunc)PbVec3Div, // binaryfunc nb_true_divide; + 0, // binaryfunc nb_inplace_floor_divide; + 0, // binaryfunc nb_inplace_true_divide; + 0, // unaryfunc nb_index; +}; +#endif + +PyTypeObject PbVec3Type = { + PyVarObject_HEAD_INIT(NULL, 0) "manta.vec3", /* tp_name */ + sizeof(PbVec3), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PbVec3Dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)PbVec3Repr, /* tp_repr */ + &PbVec3NumberMethods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ +#if PY_MAJOR_VERSION >= 3 + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "float vector type", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PbVec3Methods, /* tp_methods */ + PbVec3Members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PbVec3Init, /* tp_init */ + 0, /* tp_alloc */ + PbVec3New, /* tp_new */ +}; + +inline PyObject *castPy(PyTypeObject *p) +{ + return reinterpret_cast<PyObject *>(static_cast<void *>(p)); +} + +// 4d vector + +extern PyTypeObject PbVec4Type; + +struct PbVec4 { + PyObject_HEAD float data[4]; +}; + +static PyMethodDef PbVec4Methods[] = { + {NULL} // Sentinel +}; + +static PyMemberDef PbVec4Members[] = { + {(char *)"x", T_FLOAT, offsetof(PbVec4, data), 0, (char *)"X"}, + {(char *)"y", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 1, 0, (char *)"Y"}, + {(char *)"z", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 2, 0, (char *)"Z"}, + {(char *)"t", T_FLOAT, offsetof(PbVec4, data) + sizeof(float) * 3, 0, (char *)"T"}, + {NULL} // Sentinel +}; + +static void PbVec4Dealloc(PbVec4 *self) +{ + Py_TYPE(self)->tp_free((PyObject *)self); +} + +static PyObject *PbVec4New(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + return type->tp_alloc(type, 0); +} + +static int PbVec4Init(PbVec4 *self, PyObject *args, PyObject *kwds) +{ + + float x1 = numeric_limits<float>::quiet_NaN(), x2 = x1, x3 = x1, x4 = x1; + if (!PyArg_ParseTuple(args, "|ffff", &x1, &x2, &x3, &x4)) + return -1; + + if (!c_isnan(x1)) { + self->data[0] = x1; + if (!c_isnan(x2) && !c_isnan(x3) && !c_isnan(x4)) { + self->data[1] = x2; + self->data[2] = x3; + self->data[3] = x4; + } + else { + if (!c_isnan(x2) || !c_isnan(x3) || !c_isnan(x4)) { + errMsg("Invalid partial init of vec4"); + } + self->data[1] = self->data[2] = self->data[3] = x1; + } + } + else { + self->data[0] = self->data[1] = self->data[2] = self->data[3] = 0; + } + return 0; +} + +static PyObject *PbVec4Repr(PbVec4 *self) +{ + Manta::Vec4 v(self->data[0], self->data[1], self->data[2], self->data[3]); + return PyUnicode_FromFormat(v.toString().c_str()); +} + +PyTypeObject PbVec4Type = { + PyVarObject_HEAD_INIT(NULL, 0) "manta.vec4", /* tp_name */ + sizeof(PbVec4), /* tp_basicsize */ + 0, /* tp_itemsize */ + (destructor)PbVec4Dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + (reprfunc)PbVec4Repr, /* tp_repr */ + NULL, // &PbVec4NumberMethods, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ +#if PY_MAJOR_VERSION >= 3 + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ +#else + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_CHECKTYPES, /* tp_flags */ +#endif + "float vector type", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PbVec4Methods, /* tp_methods */ + PbVec4Members, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + (initproc)PbVec4Init, /* tp_init */ + 0, /* tp_alloc */ + PbVec4New, /* tp_new */ +}; + +// register + +void PbVecInitialize(PyObject *module) +{ + if (PyType_Ready(&PbVec3Type) < 0) + errMsg("can't initialize Vec3 type"); + Py_INCREF(castPy(&PbVec3Type)); + PyModule_AddObject(module, "vec3", (PyObject *)&PbVec3Type); + + if (PyType_Ready(&PbVec4Type) < 0) + errMsg("can't initialize Vec4 type"); + Py_INCREF(castPy(&PbVec4Type)); + PyModule_AddObject(module, "vec4", (PyObject *)&PbVec4Type); +} +const static Pb::Register _REG(PbVecInitialize); + +} // namespace Manta diff --git a/extern/mantaflow/helper/pwrapper/pythonInclude.h b/extern/mantaflow/helper/pwrapper/pythonInclude.h new file mode 100644 index 00000000000..0f78c6641d2 --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/pythonInclude.h @@ -0,0 +1,48 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Base class for particle systems + * + ******************************************************************************/ + +#ifndef _PYTHONINCLUDE_H +#define _PYTHONINCLUDE_H + +#if defined(WIN32) || defined(_WIN32) + +// note - we have to include these first! +# include <string> +# include <vector> +# include <iostream> + +#endif + +// the PYTHON_DEBUG_WITH_RELEASE define enables linking with python debug libraries +#if (defined(_DEBUG) || (DEBUG == 1)) && defined(DEBUG_PYTHON_WITH_RELEASE) + +// special handling, disable linking with debug version of python libs +# undef _DEBUG +# define NDEBUG +# include <Python.h> +# if NUMPY == 1 +# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +# include "numpy/arrayobject.h" +# endif +# define _DEBUG +# undef NDEBUG + +#else +# include <Python.h> +# if NUMPY == 1 +# define NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION +# include "numpy/arrayobject.h" +# endif +#endif + +#endif diff --git a/extern/mantaflow/helper/pwrapper/registry.cpp b/extern/mantaflow/helper/pwrapper/registry.cpp new file mode 100644 index 00000000000..332b9e158ac --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/registry.cpp @@ -0,0 +1,784 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Auto python registry + * + ******************************************************************************/ + +#include <string.h> +#include "pythonInclude.h" +#include "structmember.h" +#include "manta.h" + +using namespace std; + +const string gDefaultModuleName = "manta"; + +namespace Pb { + +//****************************************************************************** +// Custom object definition + +struct Method { + Method(const string &n, const string &d, GenericFunction f) : name(n), doc(d), func(f) + { + } + string name, doc; + GenericFunction func; + + PyMethodDef def() + { + PyMethodDef def = {&name[0], (PyCFunction)func, METH_VARARGS | METH_KEYWORDS, &doc[0]}; + return def; + } +}; +struct GetSet { + GetSet() : getter(0), setter(0) + { + } + GetSet(const string &n, const string &d, Getter g, Setter s) + : name(n), doc(d), getter(g), setter(s) + { + } + string name, doc; + Getter getter; + Setter setter; + + PyGetSetDef def() + { + PyGetSetDef def = {&name[0], getter, setter, &doc[0], NULL}; + return def; + } +}; + +struct ClassData { + string cName, pyName; + string cPureName, cTemplate; + InitFunc init; + PyTypeObject typeInfo; + PyNumberMethods numInfo; + // PySequenceMethods seqInfo; + vector<Method> methods; + map<string, GetSet> getset; + map<string, OperatorFunction> ops; + ClassData *baseclass; + string baseclassName; + Constructor constructor; + + vector<PyMethodDef> genMethods; + vector<PyGetSetDef> genGetSet; +}; + +struct PbObject { + PyObject_HEAD Manta::PbClass *instance; + ClassData *classdef; +}; + +//****************************************************** +// Internal wrapper class + +//! Registers all classes and methods exposed to Python. +/*! This class is only used internally by Pb:: framwork. + * Please use the functionality of PbClass to lookup and translate pointers. */ +class WrapperRegistry { + public: + static WrapperRegistry &instance(); + void addClass(const std::string &name, + const std::string &internalName, + const std::string &baseclass); + void addEnumEntry(const std::string &name, int value); + void addExternalInitializer(InitFunc func); + void addMethod(const std::string &classname, + const std::string &methodname, + GenericFunction method); + void addOperator(const std::string &classname, + const std::string &methodname, + OperatorFunction method); + void addConstructor(const std::string &classname, Constructor method); + void addGetSet(const std::string &classname, + const std::string &property, + Getter getfunc, + Setter setfunc); + void addPythonPath(const std::string &path); + void addPythonCode(const std::string &file, const std::string &code); + PyObject *createPyObject(const std::string &classname, + const std::string &name, + Manta::PbArgs &args, + Manta::PbClass *parent); + void construct(const std::string &scriptname, const vector<string> &args); + void cleanup(); + void renameObjects(); + void runPreInit(); + PyObject *initModule(); + ClassData *lookup(const std::string &name); + bool canConvert(ClassData *from, ClassData *to); + + private: + ClassData *getOrConstructClass(const string &name); + void registerBaseclasses(); + void registerDummyTypes(); + void registerMeta(); + void addConstants(PyObject *module); + void registerOperators(ClassData *cls); + void addParentMethods(ClassData *cls, ClassData *base); + WrapperRegistry(); + std::map<std::string, ClassData *> mClasses; + std::vector<ClassData *> mClassList; + std::vector<InitFunc> mExtInitializers; + std::vector<std::string> mPaths; + std::string mCode, mScriptName; + std::vector<std::string> args; + std::map<std::string, int> mEnumValues; +}; + +//****************************************************************************** +// Callback functions + +PyObject *cbGetClass(PbObject *self, void *cl) +{ + return Manta::toPy(self->classdef->cPureName); +} + +PyObject *cbGetTemplate(PbObject *self, void *cl) +{ + return Manta::toPy(self->classdef->cTemplate); +} + +PyObject *cbGetCName(PbObject *self, void *cl) +{ + return Manta::toPy(self->classdef->cName); +} + +void cbDealloc(PbObject *self) +{ + // cout << "dealloc " << self->instance->getName() << " " << self->classdef->cName << endl; + if (self->instance) { +#ifndef BLENDER + // don't delete top-level objects + if (self->instance->getParent() != self->instance) + delete self->instance; +#else + // in Blender we *have* to delete all objects + delete self->instance; +#endif + } + Py_TYPE(self)->tp_free((PyObject *)self); +} + +PyObject *cbNew(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PbObject *self = (PbObject *)type->tp_alloc(type, 0); + if (self != NULL) { + // lookup and link classdef + self->classdef = WrapperRegistry::instance().lookup(type->tp_name); + self->instance = NULL; + // cout << "creating " << self->classdef->cName << endl; + } + else + errMsg("can't allocate new python class object"); + return (PyObject *)self; +} + +int cbDisableConstructor(PyObject *self, PyObject *args, PyObject *kwds) +{ + errMsg("Can't instantiate a class template without template arguments"); + return -1; +} + +PyMODINIT_FUNC PyInit_Main(void) +{ + MantaEnsureRegistration(); +#if PY_MAJOR_VERSION >= 3 + return WrapperRegistry::instance().initModule(); +#else + WrapperRegistry::instance().initModule(); +#endif +} + +//****************************************************** +// WrapperRegistry + +WrapperRegistry::WrapperRegistry() +{ + addClass("__modclass__", "__modclass__", ""); + addClass("PbClass", "PbClass", ""); +} + +ClassData *WrapperRegistry::getOrConstructClass(const string &classname) +{ + map<string, ClassData *>::iterator it = mClasses.find(classname); + + if (it != mClasses.end()) + return it->second; + ClassData *data = new ClassData; + data->cName = classname; + data->cPureName = classname; + data->cTemplate = ""; + size_t tplIdx = classname.find('<'); + if (tplIdx != string::npos) { + data->cPureName = classname.substr(0, tplIdx); + data->cTemplate = classname.substr(tplIdx + 1, classname.find('>') - tplIdx - 1); + } + data->baseclass = NULL; + data->constructor = cbDisableConstructor; + mClasses[classname] = data; + mClassList.push_back(data); + return data; +} + +void replaceAll(string &source, string const &find, string const &replace) +{ + for (string::size_type i = 0; (i = source.find(find, i)) != std::string::npos;) { + source.replace(i, find.length(), replace); + i += replace.length() - find.length() + 1; + } +} + +void WrapperRegistry::addClass(const string &pyName, + const string &internalName, + const string &baseclass) +{ + ClassData *data = getOrConstructClass(internalName); + + // regularize python name + string pythonName = pyName; + replaceAll(pythonName, "<", "_"); + replaceAll(pythonName, ">", ""); + replaceAll(pythonName, ",", "_"); + + if (data->pyName.empty()) + data->pyName = pythonName; + mClasses[pythonName] = data; + if (!baseclass.empty()) + data->baseclassName = baseclass; +} + +void WrapperRegistry::addEnumEntry(const string &name, int value) +{ + /// Gather static definitions to add them as static python objects afterwards + if (mEnumValues.insert(std::make_pair(name, value)).second == false) { + errMsg("Enum entry '" + name + "' already existing..."); + } +} + +void WrapperRegistry::addExternalInitializer(InitFunc func) +{ + mExtInitializers.push_back(func); +} + +void WrapperRegistry::addPythonPath(const string &path) +{ + mPaths.push_back(path); +} + +void WrapperRegistry::addPythonCode(const string &file, const string &code) +{ + mCode += code + "\n"; +} + +void WrapperRegistry::addGetSet(const string &classname, + const string &property, + Getter getfunc, + Setter setfunc) +{ + ClassData *classdef = getOrConstructClass(classname); + GetSet &def = classdef->getset[property]; + if (def.name.empty()) { + def.name = property; + def.doc = property; + } + if (getfunc) + def.getter = getfunc; + if (setfunc) + def.setter = setfunc; +} + +void WrapperRegistry::addMethod(const string &classname, + const string &methodname, + GenericFunction func) +{ + string aclass = classname; + if (aclass.empty()) + aclass = "__modclass__"; + + ClassData *classdef = getOrConstructClass(aclass); + for (int i = 0; i < (int)classdef->methods.size(); i++) + if (classdef->methods[i].name == methodname) + return; // avoid duplicates + classdef->methods.push_back(Method(methodname, methodname, func)); +} + +void WrapperRegistry::addOperator(const string &classname, + const string &methodname, + OperatorFunction func) +{ + if (classname.empty()) + errMsg("PYTHON operators have to be defined within classes."); + + string op = methodname.substr(8); + ClassData *classdef = getOrConstructClass(classname); + classdef->ops[op] = func; +} + +void WrapperRegistry::addConstructor(const string &classname, Constructor func) +{ + ClassData *classdef = getOrConstructClass(classname); + classdef->constructor = func; +} + +void WrapperRegistry::addParentMethods(ClassData *cur, ClassData *base) +{ + if (base == 0) + return; + + for (vector<Method>::iterator it = base->methods.begin(); it != base->methods.end(); ++it) + addMethod(cur->cName, it->name, it->func); + + for (map<string, GetSet>::iterator it = base->getset.begin(); it != base->getset.end(); ++it) + addGetSet(cur->cName, it->first, it->second.getter, it->second.setter); + + for (map<string, OperatorFunction>::iterator it = base->ops.begin(); it != base->ops.end(); ++it) + cur->ops[it->first] = it->second; + + addParentMethods(cur, base->baseclass); +} + +void WrapperRegistry::registerBaseclasses() +{ + for (int i = 0; i < (int)mClassList.size(); i++) { + string bname = mClassList[i]->baseclassName; + if (!bname.empty()) { + mClassList[i]->baseclass = lookup(bname); + if (!mClassList[i]->baseclass) + errMsg("Registering class '" + mClassList[i]->cName + "' : Base class '" + bname + + "' not found"); + } + } + + for (int i = 0; i < (int)mClassList.size(); i++) { + addParentMethods(mClassList[i], mClassList[i]->baseclass); + } +} + +void WrapperRegistry::registerMeta() +{ + for (int i = 0; i < (int)mClassList.size(); i++) { + mClassList[i]->getset["_class"] = GetSet("_class", "C class name", (Getter)cbGetClass, 0); + mClassList[i]->getset["_cname"] = GetSet("_cname", "Full C name", (Getter)cbGetCName, 0); + mClassList[i]->getset["_T"] = GetSet("_T", "C template argument", (Getter)cbGetTemplate, 0); + } +} + +void WrapperRegistry::registerOperators(ClassData *cls) +{ + PyNumberMethods &num = cls->numInfo; + for (map<string, OperatorFunction>::iterator it = cls->ops.begin(); it != cls->ops.end(); it++) { + const string &op = it->first; + OperatorFunction func = it->second; + if (op == "+=") + num.nb_inplace_add = func; + else if (op == "-=") + num.nb_inplace_subtract = func; + else if (op == "*=") + num.nb_inplace_multiply = func; + else if (op == "+") + num.nb_add = func; + else if (op == "-") + num.nb_subtract = func; + else if (op == "*") + num.nb_multiply = func; +#if PY_MAJOR_VERSION < 3 + else if (op == "/=") + num.nb_inplace_divide = func; + else if (op == "/") + num.nb_divide = func; +#else + else if (op == "/=") + num.nb_inplace_true_divide = func; + else if (op == "/") + num.nb_true_divide = func; +#endif + else + errMsg("PYTHON operator " + op + " not supported"); + } +} + +void WrapperRegistry::registerDummyTypes() +{ + vector<string> add; + for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) { + string cName = (*it)->cName; + if (cName.find('<') != string::npos) + add.push_back(cName.substr(0, cName.find('<'))); + } + for (int i = 0; i < (int)add.size(); i++) + addClass(add[i], add[i], ""); +} + +ClassData *WrapperRegistry::lookup(const string &name) +{ + for (map<string, ClassData *>::iterator it = mClasses.begin(); it != mClasses.end(); ++it) { + if (it->first == name || it->second->cName == name) + return it->second; + } + return NULL; +} + +void WrapperRegistry::cleanup() +{ + for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) { + delete *it; + } + mClasses.clear(); + mClassList.clear(); +} + +WrapperRegistry &WrapperRegistry::instance() +{ + static WrapperRegistry inst; + return inst; +} + +bool WrapperRegistry::canConvert(ClassData *from, ClassData *to) +{ + if (from == to) + return true; + if (from->baseclass) + return canConvert(from->baseclass, to); + return false; +} + +void WrapperRegistry::addConstants(PyObject *module) +{ + // expose arguments + PyObject *list = PyList_New(args.size()); + for (int i = 0; i < (int)args.size(); i++) + PyList_SET_ITEM(list, i, Manta::toPy(args[i])); + PyModule_AddObject(module, "args", list); + PyModule_AddObject(module, "SCENEFILE", Manta::toPy(mScriptName)); + + // expose compile flags +#ifdef DEBUG + PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(true)); +#else + PyModule_AddObject(module, "DEBUG", Manta::toPy<bool>(false)); +#endif +#ifdef MANTA_MT + PyModule_AddObject(module, "MT", Manta::toPy<bool>(true)); +#else + PyModule_AddObject(module, "MT", Manta::toPy<bool>(false)); +#endif +#ifdef GUI + PyModule_AddObject(module, "GUI", Manta::toPy<bool>(true)); +#else + PyModule_AddObject(module, "GUI", Manta::toPy<bool>(false)); +#endif +#if FLOATINGPOINT_PRECISION == 2 + PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(true)); +#else + PyModule_AddObject(module, "DOUBLEPRECISION", Manta::toPy<bool>(false)); +#endif + // cuda off for now + PyModule_AddObject(module, "CUDA", Manta::toPy<bool>(false)); + + // expose enum entries + std::map<std::string, int>::iterator it; + for (it = mEnumValues.begin(); it != mEnumValues.end(); it++) { + PyModule_AddObject(module, it->first.c_str(), Manta::toPy(it->second)); + // Alternative would be: + // e.g. PyModule_AddIntConstant(module, "FlagFluid", 1); + } +} + +void WrapperRegistry::runPreInit() +{ + // add python directories to path + PyObject *sys_path = PySys_GetObject((char *)"path"); + for (size_t i = 0; i < mPaths.size(); i++) { + PyObject *path = Manta::toPy(mPaths[i]); + if (sys_path == NULL || path == NULL || PyList_Append(sys_path, path) < 0) { + errMsg("unable to set python path"); + } + Py_DECREF(path); + } + if (!mCode.empty()) { + mCode = "from manta import *\n" + mCode; + PyRun_SimpleString(mCode.c_str()); + } +} + +PyObject *WrapperRegistry::createPyObject(const string &classname, + const string &name, + Manta::PbArgs &args, + Manta::PbClass *parent) +{ + ClassData *classdef = lookup(classname); + if (!classdef) + errMsg("Class " + classname + " doesn't exist."); + + // create object + PyObject *obj = cbNew(&classdef->typeInfo, NULL, NULL); + PbObject *self = (PbObject *)obj; + PyObject *nkw = 0; + + if (args.kwds()) + nkw = PyDict_Copy(args.kwds()); + else + nkw = PyDict_New(); + + PyObject *nocheck = Py_BuildValue("s", "yes"); + PyDict_SetItemString(nkw, "nocheck", nocheck); + if (parent) + PyDict_SetItemString(nkw, "parent", parent->getPyObject()); + + // create instance + if (self->classdef->constructor(obj, args.linArgs(), nkw) < 0) + errMsg("error raised in constructor"); // assume condition is already set + + Py_DECREF(nkw); + Py_DECREF(nocheck); + self->instance->setName(name); + + return obj; +} + +// prepare typeinfo and register python module +void WrapperRegistry::construct(const string &scriptname, const vector<string> &args) +{ + mScriptName = scriptname; + this->args = args; + + registerBaseclasses(); + registerMeta(); + registerDummyTypes(); + + // work around for certain gcc versions, cast to char* + PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_Main); +} + +inline PyObject *castPy(PyTypeObject *p) +{ + return reinterpret_cast<PyObject *>(static_cast<void *>(p)); +} + +PyObject *WrapperRegistry::initModule() +{ + // generate and terminate all method lists + PyMethodDef sentinelFunc = {NULL, NULL, 0, NULL}; + PyGetSetDef sentinelGetSet = {NULL, NULL, NULL, NULL, NULL}; + for (int i = 0; i < (int)mClassList.size(); i++) { + ClassData *cls = mClassList[i]; + cls->genMethods.clear(); + cls->genGetSet.clear(); + for (vector<Method>::iterator i2 = cls->methods.begin(); i2 != cls->methods.end(); ++i2) + cls->genMethods.push_back(i2->def()); + for (map<string, GetSet>::iterator i2 = cls->getset.begin(); i2 != cls->getset.end(); ++i2) + cls->genGetSet.push_back(i2->second.def()); + + cls->genMethods.push_back(sentinelFunc); + cls->genGetSet.push_back(sentinelGetSet); + } + + // prepare module info +#if PY_MAJOR_VERSION >= 3 + static PyModuleDef MainModule = {PyModuleDef_HEAD_INIT, + gDefaultModuleName.c_str(), + "Bridge module to the C++ solver", + -1, + NULL, + NULL, + NULL, + NULL, + NULL}; + // get generic methods (plugin functions) + MainModule.m_methods = &mClasses["__modclass__"]->genMethods[0]; + + // create module + PyObject *module = PyModule_Create(&MainModule); +#else + PyObject *module = Py_InitModule(gDefaultModuleName.c_str(), + &mClasses["__modclass__"]->genMethods[0]); +#endif + if (module == NULL) + return NULL; + + // load classes + for (vector<ClassData *>::iterator it = mClassList.begin(); it != mClassList.end(); ++it) { + ClassData &data = **it; + char *nameptr = (char *)data.pyName.c_str(); + + // define numeric substruct + PyNumberMethods *num = 0; + if (!data.ops.empty()) { + num = &data.numInfo; + memset(num, 0, sizeof(PyNumberMethods)); + registerOperators(&data); + } + + // define python classinfo + PyTypeObject t = { + PyVarObject_HEAD_INIT(NULL, 0)(char *) data.pyName.c_str(), // tp_name + sizeof(PbObject), // tp_basicsize + 0, // tp_itemsize + (destructor)cbDealloc, // tp_dealloc + 0, // tp_print + 0, // tp_getattr + 0, // tp_setattr + 0, // tp_reserved + 0, // tp_repr + num, // tp_as_number + 0, // tp_as_sequence + 0, // tp_as_mapping + 0, // tp_hash + 0, // tp_call + 0, // tp_str + 0, // tp_getattro + 0, // tp_setattro + 0, // tp_as_buffer + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, // tp_flags + nameptr, // tp_doc + 0, // tp_traverse + 0, // tp_clear + 0, // tp_richcompare + 0, // tp_weaklistoffset + 0, // tp_iter + 0, // tp_iternext + &data.genMethods[0], // tp_methods + 0, // tp_members + &data.genGetSet[0], // tp_getset + 0, // tp_base + 0, // tp_dict + 0, // tp_descr_get + 0, // tp_descr_set + 0, // tp_dictoffset + (initproc)(data.constructor), // tp_init + 0, // tp_alloc + cbNew // tp_new + }; + data.typeInfo = t; + + if (PyType_Ready(&data.typeInfo) < 0) + continue; + + for (map<string, ClassData *>::iterator i2 = mClasses.begin(); i2 != mClasses.end(); ++i2) { + if (*it != i2->second) + continue; + // register all aliases + Py_INCREF(castPy(&data.typeInfo)); + PyModule_AddObject(module, (char *)i2->first.c_str(), (PyObject *)&data.typeInfo); + } + } + + // externals + for (vector<InitFunc>::iterator it = mExtInitializers.begin(); it != mExtInitializers.end(); + ++it) { + (*it)(module); + } + + addConstants(module); + + return module; +} + +//****************************************************** +// Register members and exposed functions + +void setup(const std::string &filename, const std::vector<std::string> &args) +{ + WrapperRegistry::instance().construct(filename, args); + Py_Initialize(); + WrapperRegistry::instance().runPreInit(); +} + +void finalize() +{ + Py_Finalize(); + WrapperRegistry::instance().cleanup(); +} + +bool canConvert(PyObject *obj, const string &classname) +{ + ClassData *from = ((PbObject *)obj)->classdef; + ClassData *dest = WrapperRegistry::instance().lookup(classname); + if (!dest) + errMsg("Classname '" + classname + "' is not registered."); + return WrapperRegistry::instance().canConvert(from, dest); +} + +Manta::PbClass *objFromPy(PyObject *obj) +{ + if (Py_TYPE(obj)->tp_dealloc != (destructor)cbDealloc) // not a manta object + return NULL; + + return ((PbObject *)obj)->instance; +} + +PyObject *copyObject(Manta::PbClass *cls, const string &classname) +{ + ClassData *classdef = WrapperRegistry::instance().lookup(classname); + assertMsg(classdef, "python class " + classname + " does not exist."); + + // allocate new object + PbObject *obj = (PbObject *)classdef->typeInfo.tp_alloc(&(classdef->typeInfo), 0); + assertMsg(obj, "cannot allocate new python object"); + + obj->classdef = classdef; + cls->registerObject((PyObject *)obj, 0); + + return cls->getPyObject(); +} + +Manta::PbClass *createPy(const std::string &classname, + const std::string &name, + Manta::PbArgs &args, + Manta::PbClass *parent) +{ + PyObject *obj = WrapperRegistry::instance().createPyObject(classname, name, args, parent); + return ((PbObject *)obj)->instance; +} + +void setReference(Manta::PbClass *cls, PyObject *obj) +{ + ((PbObject *)obj)->instance = cls; +} + +Register::Register(const string &className, const string &funcName, GenericFunction func) +{ + WrapperRegistry::instance().addMethod(className, funcName, func); +} +Register::Register(const string &className, const string &funcName, OperatorFunction func) +{ + WrapperRegistry::instance().addOperator(className, funcName, func); +} +Register::Register(const string &className, const string &funcName, Constructor func) +{ + WrapperRegistry::instance().addConstructor(className, func); +} +Register::Register(const string &className, const string &property, Getter getter, Setter setter) +{ + WrapperRegistry::instance().addGetSet(className, property, getter, setter); +} +Register::Register(const string &className, const string &pyName, const string &baseClass) +{ + WrapperRegistry::instance().addClass(pyName, className, baseClass); +} +Register::Register(const string &name, const int value) +{ + WrapperRegistry::instance().addEnumEntry(name, value); +} +Register::Register(const string &file, const string &pythonCode) +{ + WrapperRegistry::instance().addPythonCode(file, pythonCode); +} +Register::Register(InitFunc func) +{ + WrapperRegistry::instance().addExternalInitializer(func); +} + +} // namespace Pb diff --git a/extern/mantaflow/helper/pwrapper/registry.h b/extern/mantaflow/helper/pwrapper/registry.h new file mode 100644 index 00000000000..139863df85d --- /dev/null +++ b/extern/mantaflow/helper/pwrapper/registry.h @@ -0,0 +1,106 @@ +/****************************************************************************** + * + * MantaFlow fluid solver framework + * Copyright 2011-2014 Tobias Pfaff, Nils Thuerey + * + * This program is free software, distributed under the terms of the + * Apache License, Version 2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Auto python registry + * + ******************************************************************************/ + +#ifndef _REGISTRY_H +#define _REGISTRY_H + +#include <string> +#include <vector> + +// forward declaration to minimize Python.h includes +#ifndef PyObject_HEAD +# ifndef PyObject_Fake +struct _object; +typedef _object PyObject; +# define PyObject_Fake +# endif +#endif + +namespace Manta { +class PbClass; +class PbArgs; +} // namespace Manta + +// ************************************************** +// NOTE +// Everything in this file is intend only for internal +// use by the generated wrappers or pclass/pconvert. +// For user code, use the functionality exposed in +// pclass.h / pconvert.h instead. +// ************************************************** + +// Used to turn names into strings +namespace Manta { +template<class T> struct Namify { + static const char *S; +}; +} // namespace Manta +namespace Pb { + +// internal registry access +void setup(const std::string &filename, const std::vector<std::string> &args); +void finalize(); +bool canConvert(PyObject *obj, const std::string &to); +Manta::PbClass *objFromPy(PyObject *obj); +Manta::PbClass *createPy(const std::string &classname, + const std::string &name, + Manta::PbArgs &args, + Manta::PbClass *parent); +void setReference(Manta::PbClass *cls, PyObject *obj); +PyObject *copyObject(Manta::PbClass *cls, const std::string &classname); +void MantaEnsureRegistration(); + +#ifdef BLENDER +# ifdef PyMODINIT_FUNC +PyMODINIT_FUNC PyInit_Main(void); +# endif +#endif + +// callback type +typedef void (*InitFunc)(PyObject *); +typedef PyObject *(*GenericFunction)(PyObject *self, PyObject *args, PyObject *kwds); +typedef PyObject *(*OperatorFunction)(PyObject *self, PyObject *o); +typedef int (*Constructor)(PyObject *self, PyObject *args, PyObject *kwds); +typedef PyObject *(*Getter)(PyObject *self, void *closure); +typedef int (*Setter)(PyObject *self, PyObject *value, void *closure); + +//! Auto registry of python methods and classes +struct Register { + //! register method + Register(const std::string &className, const std::string &funcName, GenericFunction func); + //! register operator + Register(const std::string &className, const std::string &funcName, OperatorFunction func); + //! register constructor + Register(const std::string &className, const std::string &funcName, Constructor func); + //! register getter/setter + Register(const std::string &className, + const std::string &property, + Getter getter, + Setter setter); + //! register class + Register(const std::string &className, const std::string &pyName, const std::string &baseClass); + //! register enum entry + Register(const std::string &name, const int value); + //! register python code + Register(const std::string &file, const std::string &pythonCode); + //! register external code + Register(InitFunc func); +}; + +#define KEEP_UNUSED(var) \ + do { \ + (void)var; \ + } while (false); + +} // namespace Pb +#endif |