Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/gameengine/Expressions')
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.cpp443
-rw-r--r--source/gameengine/Expressions/PyObjectPlus.h101
2 files changed, 544 insertions, 0 deletions
diff --git a/source/gameengine/Expressions/PyObjectPlus.cpp b/source/gameengine/Expressions/PyObjectPlus.cpp
index 1eca527151a..c31587628b0 100644
--- a/source/gameengine/Expressions/PyObjectPlus.cpp
+++ b/source/gameengine/Expressions/PyObjectPlus.cpp
@@ -131,6 +131,449 @@ int PyObjectPlus::_setattr(const STR_String& attr, PyObject *value)
return 1;
}
+PyObject *PyObjectPlus::_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr)
+{
+ const PyAttributeDef *attrdef;
+ for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
+ {
+ if (attr == attrdef->m_name)
+ {
+ if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
+ {
+ // fake attribute, ignore
+ return NULL;
+ }
+ char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
+ if (attrdef->m_length > 1)
+ {
+ PyObject* resultlist = PyList_New(attrdef->m_length);
+ for (int i=0; i<attrdef->m_length; i++)
+ {
+ switch (attrdef->m_type) {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ {
+ bool *val = reinterpret_cast<bool*>(ptr);
+ ptr += sizeof(bool);
+ PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ {
+ short int *val = reinterpret_cast<short int*>(ptr);
+ ptr += sizeof(short int);
+ PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_INT:
+ {
+ int *val = reinterpret_cast<int*>(ptr);
+ ptr += sizeof(int);
+ PyList_SetItem(resultlist,i,PyInt_FromLong(*val));
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ {
+ float *val = reinterpret_cast<float*>(ptr);
+ ptr += sizeof(float);
+ PyList_SetItem(resultlist,i,PyFloat_FromDouble(*val));
+ break;
+ }
+ default:
+ // no support for array of complex data
+ return NULL;
+ }
+ }
+ return resultlist;
+ }
+ else
+ {
+ switch (attrdef->m_type) {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ {
+ bool *val = reinterpret_cast<bool*>(ptr);
+ return PyInt_FromLong(*val);
+ }
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ {
+ short int *val = reinterpret_cast<short int*>(ptr);
+ return PyInt_FromLong(*val);
+ }
+ case KX_PYATTRIBUTE_TYPE_INT:
+ {
+ int *val = reinterpret_cast<int*>(ptr);
+ return PyInt_FromLong(*val);
+ }
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ {
+ float *val = reinterpret_cast<float*>(ptr);
+ return PyFloat_FromDouble(*val);
+ }
+ case KX_PYATTRIBUTE_TYPE_STRING:
+ {
+ STR_String *val = reinterpret_cast<STR_String*>(ptr);
+ return PyString_FromString(*val);
+ }
+ default:
+ return NULL;
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+int PyObjectPlus::_setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value)
+{
+ const PyAttributeDef *attrdef;
+ void *undoBuffer = NULL;
+ void *sourceBuffer = NULL;
+ size_t bufferSize = 0;
+
+ for (attrdef=attrlist; attrdef->m_name != NULL; attrdef++)
+ {
+ if (attr == attrdef->m_name)
+ {
+ if (attrdef->m_access == KX_PYATTRIBUTE_RO ||
+ attrdef->m_type == KX_PYATTRIBUTE_TYPE_DUMMY)
+ {
+ PyErr_SetString(PyExc_AttributeError, "property is read-only");
+ return 1;
+ }
+ char *ptr = reinterpret_cast<char*>(self)+attrdef->m_offset;
+ if (attrdef->m_length > 1)
+ {
+ if (!PySequence_Check(value))
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a sequence");
+ return 1;
+ }
+ if (PySequence_Size(value) != attrdef->m_length)
+ {
+ PyErr_SetString(PyExc_TypeError, "incorrect number of elements in sequence");
+ return 1;
+ }
+ switch (attrdef->m_type)
+ {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ bufferSize = sizeof(bool);
+ break;
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ bufferSize = sizeof(short int);
+ break;
+ case KX_PYATTRIBUTE_TYPE_INT:
+ bufferSize = sizeof(int);
+ break;
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ bufferSize = sizeof(float);
+ break;
+ default:
+ // should not happen
+ PyErr_SetString(PyExc_AttributeError, "Unsupported attribute type, report to blender.org");
+ return 1;
+ }
+ // let's implement a smart undo method
+ bufferSize *= attrdef->m_length;
+ undoBuffer = malloc(bufferSize);
+ sourceBuffer = ptr;
+ if (undoBuffer)
+ {
+ memcpy(undoBuffer, sourceBuffer, bufferSize);
+ }
+ for (int i=0; i<attrdef->m_length; i++)
+ {
+ PyObject *item = PySequence_GetItem(value, i); /* new ref */
+ // we can decrement the reference immediately, the reference count
+ // is at least 1 because the item is part of an array
+ Py_DECREF(item);
+ switch (attrdef->m_type)
+ {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ {
+ bool *var = reinterpret_cast<bool*>(ptr);
+ ptr += sizeof(bool);
+ if (PyInt_Check(item))
+ {
+ *var = (PyInt_AsLong(item) != 0);
+ }
+ else if (PyBool_Check(item))
+ {
+ *var = (item == Py_True);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
+ goto UNDO_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ {
+ short int *var = reinterpret_cast<short int*>(ptr);
+ ptr += sizeof(short int);
+ if (PyInt_Check(item))
+ {
+ long val = PyInt_AsLong(item);
+ if (val < attrdef->m_imin || val > attrdef->m_imax)
+ {
+ PyErr_SetString(PyExc_ValueError, "item value out of range");
+ goto UNDO_AND_ERROR;
+ }
+ *var = (short int)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer");
+ goto UNDO_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_INT:
+ {
+ int *var = reinterpret_cast<int*>(ptr);
+ ptr += sizeof(int);
+ if (PyInt_Check(item))
+ {
+ long val = PyInt_AsLong(item);
+ if (val < attrdef->m_imin || val > attrdef->m_imax)
+ {
+ PyErr_SetString(PyExc_ValueError, "item value out of range");
+ goto UNDO_AND_ERROR;
+ }
+ *var = (int)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer");
+ goto UNDO_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ {
+ float *var = reinterpret_cast<float*>(ptr);
+ ptr += sizeof(float);
+ if (PyFloat_Check(item))
+ {
+ double val = PyFloat_AsDouble(item);
+ if (val < attrdef->m_fmin || val > attrdef->m_fmax)
+ {
+ PyErr_SetString(PyExc_ValueError, "item value out of range");
+ goto UNDO_AND_ERROR;
+ }
+ *var = (float)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a float");
+ goto UNDO_AND_ERROR;
+ }
+ break;
+ }
+ default:
+ // should not happen
+ PyErr_SetString(PyExc_AttributeError, "attribute type check error, report to blender.org");
+ goto UNDO_AND_ERROR;
+ }
+ }
+ // no error, call check function if any
+ if (attrdef->m_function != NULL)
+ {
+ if ((*attrdef->m_function)(self) != 0)
+ {
+ // post check returned an error, restore values
+ UNDO_AND_ERROR:
+ if (undoBuffer)
+ {
+ memcpy(sourceBuffer, undoBuffer, bufferSize);
+ free(undoBuffer);
+ }
+ return 1;
+ }
+ }
+ if (undoBuffer)
+ free(undoBuffer);
+ return 0;
+ }
+ else // simple attribute value
+ {
+
+ if (attrdef->m_function != NULL)
+ {
+ // post check function is provided, prepare undo buffer
+ sourceBuffer = ptr;
+ switch (attrdef->m_type)
+ {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ bufferSize = sizeof(bool);
+ break;
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ bufferSize = sizeof(short);
+ break;
+ case KX_PYATTRIBUTE_TYPE_INT:
+ bufferSize = sizeof(int);
+ break;
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ bufferSize = sizeof(float);
+ break;
+ case KX_PYATTRIBUTE_TYPE_STRING:
+ sourceBuffer = reinterpret_cast<STR_String*>(ptr)->Ptr();
+ if (sourceBuffer)
+ bufferSize = strlen(reinterpret_cast<char*>(sourceBuffer))+1;
+ break;
+ default:
+ PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
+ return 1;
+ }
+ if (bufferSize)
+ {
+ undoBuffer = malloc(bufferSize);
+ if (undoBuffer)
+ {
+ memcpy(undoBuffer, sourceBuffer, bufferSize);
+ }
+ }
+ }
+
+ switch (attrdef->m_type)
+ {
+ case KX_PYATTRIBUTE_TYPE_BOOL:
+ {
+ bool *var = reinterpret_cast<bool*>(ptr);
+ if (PyInt_Check(value))
+ {
+ *var = (PyInt_AsLong(value) != 0);
+ }
+ else if (PyBool_Check(value))
+ {
+ *var = (value == Py_True);
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer or a bool");
+ goto FREE_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_SHORT:
+ {
+ short int *var = reinterpret_cast<short int*>(ptr);
+ if (PyInt_Check(value))
+ {
+ long val = PyInt_AsLong(value);
+ if (val < attrdef->m_imin || val > attrdef->m_imax)
+ {
+ PyErr_SetString(PyExc_ValueError, "value out of range");
+ goto FREE_AND_ERROR;
+ }
+ *var = (short int)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer");
+ goto FREE_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_INT:
+ {
+ int *var = reinterpret_cast<int*>(ptr);
+ if (PyInt_Check(value))
+ {
+ long val = PyInt_AsLong(value);
+ if (val < attrdef->m_imin || val > attrdef->m_imax)
+ {
+ PyErr_SetString(PyExc_ValueError, "value out of range");
+ goto FREE_AND_ERROR;
+ }
+ *var = (int)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected an integer");
+ goto FREE_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_FLOAT:
+ {
+ float *var = reinterpret_cast<float*>(ptr);
+ if (PyFloat_Check(value))
+ {
+ double val = PyFloat_AsDouble(value);
+ if (val < attrdef->m_fmin || val > attrdef->m_fmax)
+ {
+ PyErr_SetString(PyExc_ValueError, "value out of range");
+ goto FREE_AND_ERROR;
+ }
+ *var = (float)val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a float");
+ goto FREE_AND_ERROR;
+ }
+ break;
+ }
+ case KX_PYATTRIBUTE_TYPE_STRING:
+ {
+ STR_String *var = reinterpret_cast<STR_String*>(ptr);
+ if (PyString_Check(value))
+ {
+ char *val = PyString_AsString(value);
+ if (strlen(val) < attrdef->m_imin || strlen(val) > attrdef->m_imax)
+ {
+ PyErr_SetString(PyExc_ValueError, "string length out of range");
+ goto FREE_AND_ERROR;
+ }
+ *var = val;
+ }
+ else
+ {
+ PyErr_SetString(PyExc_TypeError, "expected a string");
+ goto FREE_AND_ERROR;
+ }
+ break;
+ }
+ default:
+ // should not happen
+ PyErr_SetString(PyExc_AttributeError, "unknown attribute type, report to blender.org");
+ goto FREE_AND_ERROR;
+ }
+ }
+ // check if post processing is needed
+ if (attrdef->m_function != NULL)
+ {
+ if ((*attrdef->m_function)(self) != 0)
+ {
+ // restore value
+ if (undoBuffer)
+ {
+ if (attrdef->m_type == KX_PYATTRIBUTE_TYPE_STRING)
+ {
+ // special case for STR_String: restore the string
+ STR_String *var = reinterpret_cast<STR_String*>(ptr);
+ *var = reinterpret_cast<char*>(undoBuffer);
+ }
+ else
+ {
+ // other field type have direct values
+ memcpy(ptr, undoBuffer, bufferSize);
+ }
+ }
+ FREE_AND_ERROR:
+ if (undoBuffer)
+ free(undoBuffer);
+ return 1;
+ }
+ }
+ if (undoBuffer)
+ free(undoBuffer);
+ return 0;
+ }
+ }
+ return -1;
+}
+
/*------------------------------
* PyObjectPlus repr -- representations
------------------------------*/
diff --git a/source/gameengine/Expressions/PyObjectPlus.h b/source/gameengine/Expressions/PyObjectPlus.h
index 55998ce1c97..016fa293d73 100644
--- a/source/gameengine/Expressions/PyObjectPlus.h
+++ b/source/gameengine/Expressions/PyObjectPlus.h
@@ -86,6 +86,7 @@ static inline void Py_Fatal(const char *M) {
public: \
static PyTypeObject Type; \
static PyMethodDef Methods[]; \
+ static PyAttributeDef Attributes[]; \
static PyParentObject Parents[]; \
virtual PyTypeObject *GetType(void) {return &Type;}; \
virtual PyParentObject *GetParents(void) {return Parents;}
@@ -210,6 +211,104 @@ PyObject* class_name::Py##method_name(PyObject*, PyObject* value)
const char class_name::method_name##_doc[] = doc_string; \
PyObject* class_name::Py##method_name(PyObject*)
+/**
+ * Attribute management
+ */
+enum KX_PYATTRIBUTE_TYPE {
+ KX_PYATTRIBUTE_TYPE_BOOL,
+ KX_PYATTRIBUTE_TYPE_SHORT,
+ KX_PYATTRIBUTE_TYPE_INT,
+ KX_PYATTRIBUTE_TYPE_FLOAT,
+ KX_PYATTRIBUTE_TYPE_STRING,
+ KX_PYATTRIBUTE_TYPE_DUMMY,
+};
+
+enum KX_PYATTRIBUTE_ACCESS {
+ KX_PYATTRIBUTE_RW,
+ KX_PYATTRIBUTE_RO
+};
+
+typedef int (*KX_PYATTRIBUTE_FUNCTION)(void *self);
+
+typedef struct KX_PYATTRIBUTE_DEF {
+ const char *m_name; // name of the python attribute
+ KX_PYATTRIBUTE_TYPE m_type; // type of value
+ KX_PYATTRIBUTE_ACCESS m_access; // read/write access or read-only
+ int m_imin; // minimum value in case of integer attributes
+ int m_imax; // maximum value in case of integer attributes
+ float m_fmin; // minimum value in case of float attributes
+ float m_fmax; // maximum value in case of float attributes
+ size_t m_offset; // position of field in structure
+ size_t m_length; // length of array, 1=simple attribute
+ KX_PYATTRIBUTE_FUNCTION m_function; // static function to check the assignment, returns 0 if no error
+ // The following pointers are just used to have compile time check for attribute type.
+ // It would have been good to use a union but that would require C99 compatibility
+ // to initialize specific union fields through designated initializers.
+ struct {
+ bool *m_boolPtr;
+ short int *m_shortPtr;
+ int *m_intPtr;
+ float *m_floatPtr;
+ STR_String *m_stringPtr;
+ } m_typeCheck;
+} PyAttributeDef;
+
+#define KX_PYATTRIBUTE_DUMMY(name) \
+ { name, KX_PYATTRIBUTE_TYPE_DUMMY, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, 0, 1, NULL, {NULL, NULL, NULL, NULL, NULL} }
+
+#define KX_PYATTRIBUTE_BOOL_RW(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, offsetof(object,field), 1, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_BOOL_RW_CHECK(name,object,field,function) \
+ { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RW, 0, 1, 0.f, 0.f, offsetof(object,field), 1, &object::function, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_BOOL_RO(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_BOOL, KX_PYATTRIBUTE_RO, 0, 1, 0.f, 0.f, offsetof(object,field), 1, NULL, {&((object *)0)->field, NULL, NULL, NULL, NULL} }
+
+#define KX_PYATTRIBUTE_SHORT_RW(name,min,max,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_RW_CHECK(name,min,max,object,field,function) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_RO(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RW(name,min,max,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+#define KX_PYATTRIBUTE_SHORT_ARRAY_RO(name,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_SHORT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, &((object *)0)->field, NULL, NULL, NULL} }
+
+#define KX_PYATTRIBUTE_INT_RW(name,min,max,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_RW_CHECK(name,min,max,object,field,function) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_RO(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RW(name,min,max,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), length, &object::function, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+#define KX_PYATTRIBUTE_INT_ARRAY_RO(name,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_INT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, &((object *)0)->field, NULL, NULL} }
+
+#define KX_PYATTRIBUTE_FLOAT_RW(name,min,max,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_RW_CHECK(name,min,max,object,field,function) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), 1, &object::function, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_RO(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW(name,min,max,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), length, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RW_CHECK(name,min,max,object,field,length,function) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RW, 0, 0, min, max, offsetof(object,field), length, &object::function, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+#define KX_PYATTRIBUTE_FLOAT_ARRAY_RO(name,object,field,length) \
+ { name, KX_PYATTRIBUTE_TYPE_FLOAT, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), length, NULL, {NULL, NULL, NULL, &((object *)0)->field, NULL} }
+
+#define KX_PYATTRIBUTE_STRING_RW(name,min,max,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
+#define KX_PYATTRIBUTE_STRING_RW_CHECK(name,min,max,object,field,function) \
+ { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RW, min, max, 0.f, 0.f, offsetof(object,field), 1, &object::function, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
+#define KX_PYATTRIBUTE_STRING_RO(name,object,field) \
+ { name, KX_PYATTRIBUTE_TYPE_STRING, KX_PYATTRIBUTE_RO, 0, 0, 0.f, 0.f, offsetof(object,field), 1 , NULL, {NULL, NULL, NULL, NULL, &((object *)0)->field} }
+
/*------------------------------
* PyObjectPlus
------------------------------*/
@@ -240,6 +339,8 @@ public:
{
return ((PyObjectPlus*) PyObj)->_getattr(STR_String(attr));
}
+ static PyObject *_getattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr);
+ static int _setattr_self(const PyAttributeDef attrlist[], void *self, const STR_String &attr, PyObject *value);
virtual int _delattr(const STR_String& attr);
virtual int _setattr(const STR_String& attr, PyObject *value); // _setattr method