Add Chromium-only Blender WebEngine parity work

This commit is contained in:
mes123456
2026-08-12 04:47:48 -04:00
commit 9fd26010f6
18225 changed files with 11622124 additions and 0 deletions

View File

@@ -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

View File

@@ -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 == nullptr) {
// 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,
nullptr,
0,
0,
/*NPY_ARRAY_ENSURECOPY*/ NPY_ARRAY_C_CONTIGUOUS |
NPY_ARRAY_ENSUREARRAY | NPY_ARRAY_NOTSWAPPED,
nullptr));
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

View File

@@ -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

View File

@@ -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(nullptr), mParent(parent), mPyObject(obj), mName(name), mHidden(false)
{
mMutex = new QMutex();
}
PbClass::PbClass(const PbClass &a)
: mMutex(nullptr), 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() == nullptr) {
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

View File

@@ -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 = nullptr);
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

View File

@@ -0,0 +1,663 @@
/******************************************************************************
*
* 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<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec)
{
PyObject *listObj = PyList_New(vec.size());
if (!listObj)
throw logic_error("Unable to allocate memory for Python list");
for (unsigned int i = 0; i < vec.size(); i++) {
PbClass *pb = vec[i];
PyObject *item = pb->getPyObject();
if (!item) {
Py_DECREF(listObj);
throw logic_error("Unable to allocate memory for Python list");
}
PyList_SET_ITEM(listObj, i, item);
}
return listObj;
}
template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec)
{
PyObject *listObj = PyList_New(vec.size());
if (!listObj)
throw logic_error("Unable to allocate memory for Python list");
for (unsigned int i = 0; i < vec.size(); i++) {
PyObject *item = toPy<float>(vec[i]);
if (!item) {
Py_DECREF(listObj);
throw logic_error("Unable to allocate memory for Python list");
}
PyList_SET_ITEM(listObj, i, item);
}
return listObj;
}
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<> PbClass *fromPy<PbClass *>(PyObject *obj)
{
PbClass *pbo = Pb::objFromPy(obj);
if (!PyType_Check(obj))
return pbo;
const char *tname = ((PyTypeObject *)obj)->tp_name;
pbo->setName(tname);
return pbo;
}
template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj)
{
std::vector<PbClass *> vec;
if (PyList_Check(obj)) {
int sz = PyList_Size(obj);
for (int i = 0; i < sz; ++i) {
PyObject *lobj = PyList_GetItem(obj, i);
vec.push_back(fromPy<PbClass *>(lobj));
}
}
return vec;
}
template<> std::vector<float> fromPy<std::vector<float>>(PyObject *obj)
{
std::vector<float> vec;
if (PyList_Check(obj)) {
int sz = PyList_Size(obj);
for (int i = 0; i < sz; ++i) {
PyObject *lobj = PyList_GetItem(obj, i);
vec.push_back(fromPy<float>(lobj));
}
}
return vec;
}
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))
#ifdef BLENDER
// Blender is completely UTF-8 based
return PyBytes_AsString(PyUnicode_AsUTF8String(obj));
#else
return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
#endif
#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))
#ifdef BLENDER
// Blender is completely UTF-8 based
return PyBytes_AsString(PyUnicode_AsUTF8String(obj));
#else
return PyBytes_AsString(PyUnicode_AsLatin1String(obj));
#endif
#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<TmpCleanupFn> *tmp)
{
if (!tmp)
throw Error("dynamic de-ref not supported for this type");
T *ptr = new T(fromPy<T>(obj));
tmp->push_back([ptr]() { delete ptr; });
return ptr;
}
template<> float *fromPyPtr<float>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<float>(obj, tmp);
}
template<> double *fromPyPtr<double>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<double>(obj, tmp);
}
template<> int *fromPyPtr<int>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<int>(obj, tmp);
}
template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<std::string>(obj, tmp);
}
template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<bool>(obj, tmp);
}
template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec3>(obj, tmp);
}
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec3i>(obj, tmp);
}
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec4>(obj, tmp);
}
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<Vec4i>(obj, tmp);
}
template<>
std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<TmpCleanupFn> *tmp)
{
return tmpAlloc<std::vector<PbClass *>>(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);
}
template<> bool isPy<std::vector<PbClass *>>(PyObject *obj)
{
if (PyList_Check(obj))
return true;
return false;
}
template<> bool isPy<std::vector<float>>(PyObject *obj)
{
if (PyList_Check(obj))
return true;
return false;
}
//******************************************************************************
// PbArgs class defs
PbArgs PbArgs::EMPTY(nullptr, nullptr);
PbArgs::PbArgs(PyObject *linarg, PyObject *dict) : mLinArgs(0), mKwds(0)
{
setup(linarg, dict);
}
PbArgs::~PbArgs()
{
for (auto &fn : mTmpStorageCleanup)
fn();
mTmpStorageCleanup.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, nullptr);
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 == nullptr)
solver = obj->getParent();
}
}
for (vector<DataElement>::iterator it = mLinData.begin(); it != mLinData.end(); it++) {
PbClass *obj = Pb::objFromPy(it->obj);
if (obj) {
if (solver == nullptr)
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 nullptr;
}
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 nullptr;
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

View File

@@ -0,0 +1,266 @@
/******************************************************************************
*
* 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 <functional>
# 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();
using TmpCleanupFn = std::function<void()>;
// for PbClass-derived classes
template<class T> T *fromPyPtr(PyObject *obj, std::vector<TmpCleanupFn> *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<TmpCleanupFn> *tmp);
template<> double *fromPyPtr<double>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> int *fromPyPtr<int>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> std::string *fromPyPtr<std::string>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> bool *fromPyPtr<bool>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec3 *fromPyPtr<Vec3>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec3i *fromPyPtr<Vec3i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec4 *fromPyPtr<Vec4>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<> Vec4i *fromPyPtr<Vec4i>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<>
std::vector<PbClass *> *fromPyPtr<std::vector<PbClass *>>(PyObject *obj, std::vector<TmpCleanupFn> *tmp);
template<>
std::vector<float> *fromPyPtr<std::vector<float>>(PyObject *obj, std::vector<TmpCleanupFn> *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<> PbClass *fromPy<PbClass *>(PyObject *obj);
template<> std::vector<PbClass *> fromPy<std::vector<PbClass *>>(PyObject *obj);
template<> std::vector<float> fromPy<std::vector<float>>(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<> PyObject *toPy<std::vector<PbClass *>>(const std::vector<PbClass *> &vec);
template<> PyObject *toPy<std::vector<float>>(const std::vector<float> &vec);
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);
template<> bool isPy<std::vector<PbClass *>>(PyObject *obj);
template<> bool isPy<std::vector<float>>(PyObject *obj);
//! Encapsulation of python arguments
class PbArgs {
public:
PbArgs(PyObject *linargs = nullptr, PyObject *dict = nullptr);
~PbArgs();
void setup(PyObject *linargs = nullptr, PyObject *dict = nullptr);
void check();
FluidSolver *obtainParent();
inline int numLinArgs()
{
return mLinData.size();
}
inline bool has(const std::string &key)
{
return getItem(key, false) != nullptr;
}
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 = nullptr)
{
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 = nullptr)
{
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 = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
if (number >= 0)
o = getItem(number, false, lk);
return o ? fromPyPtr<T>(o, &mTmpStorageCleanup) : defarg;
}
template<class T>
inline T *getPtr(const std::string &key, int number = -1, ArgLocker *lk = nullptr)
{
visit(number, key);
PyObject *o = getItem(key, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
o = getItem(number, false, lk);
if (o)
return fromPyPtr<T>(o, &mTmpStorageCleanup);
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 = nullptr);
PyObject *getItem(size_t number, bool strict, ArgLocker *lk = nullptr);
struct DataElement {
PyObject *obj;
bool visited;
};
std::map<std::string, DataElement> mData;
std::vector<DataElement> mLinData;
PyObject *mLinArgs, *mKwds;
std::vector<TmpCleanupFn> mTmpStorageCleanup;
};
} // namespace Manta
# if NUMPY == 1
# include "numpyWrap.h"
# endif
# endif
#endif

View File

@@ -0,0 +1,416 @@
/******************************************************************************
*
* 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"},
{nullptr} // Sentinel
};
static PyMethodDef PbVec3Methods[] = {
//{"name", (PyCFunction)Noddy_name, METH_NOARGS, "Return the name, combining the first and last
//name" },
{nullptr} // 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(nullptr, 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[] = {
{nullptr} // 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"},
{nullptr} // 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(nullptr, 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 */
nullptr, // &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

View File

@@ -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

View File

@@ -0,0 +1,817 @@
/******************************************************************************
*
* 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], nullptr};
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(bool python_lifecycle, const std::string &scriptname, const vector<string> &args);
void cleanup();
void renameObjects();
void runPreInit(PyObject *name_space);
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();
~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 != nullptr) {
// lookup and link classdef
self->classdef = WrapperRegistry::instance().lookup(type->tp_name);
self->instance = nullptr;
// 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_manta_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", "");
}
WrapperRegistry::~WrapperRegistry()
{
// Some static constructions may have called WrapperRegistry.instance() and added
// own classes, functions, etc. Ensure everything is cleaned up properly.
cleanup();
}
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 = nullptr;
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 nullptr;
}
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(PyObject *name_space)
{
// 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 == nullptr || path == nullptr || PyList_Append(sys_path, path) < 0) {
errMsg("unable to set python path");
}
Py_DECREF(path);
}
if (!mCode.empty()) {
mCode = "from manta import *\n" + mCode;
PyObject *return_value = PyRun_String(mCode.c_str(), Py_file_input, name_space, name_space);
if (return_value == nullptr) {
if (PyErr_Occurred()) {
PyErr_Print();
}
}
else {
Py_DECREF(return_value);
}
}
}
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, nullptr, nullptr);
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 bool python_lifecycle,
const string &scriptname,
const vector<string> &args)
{
mScriptName = scriptname;
this->args = args;
registerBaseclasses();
registerMeta();
registerDummyTypes();
// Don't extend the init-tab when Python is already initialized.
// Since Python 3.12 this isn't supported and will crash.
//
// When `python_lifecycle` is false (when manta-flow is embedded), it's the responsibility
// of the application embedding this code to include #PyInit_manta_main in the init-tab.
if (python_lifecycle) {
// work around for certain gcc versions, cast to char*
PyImport_AppendInittab((char *)gDefaultModuleName.c_str(), PyInit_manta_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 = {nullptr, nullptr, 0, nullptr};
PyGetSetDef sentinelGetSet = {nullptr, nullptr, nullptr, nullptr, nullptr};
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,
nullptr,
nullptr,
nullptr,
nullptr,
nullptr};
// 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 == nullptr)
return nullptr;
// 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(nullptr, 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 bool python_lifecycle,
const std::string &filename,
const std::vector<std::string> &args,
PyObject *name_space)
{
WrapperRegistry::instance().construct(python_lifecycle, filename, args);
if (python_lifecycle) {
Py_Initialize();
}
WrapperRegistry::instance().runPreInit(name_space);
}
void finalize(const bool python_lifecycle)
{
if (python_lifecycle) {
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 nullptr;
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

View File

@@ -0,0 +1,109 @@
/******************************************************************************
*
* 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(bool python_lifecycle,
const std::string &filename,
const std::vector<std::string> &args,
PyObject *name_space);
void finalize(bool python_lifecycle);
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_manta_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