Revision: 21263 http://projects.blender.org/plugins/scmsvn/viewcvs.php?view=rev&root=bf-blender&revision=21263 Author: campbellbarton Date: 2009-06-30 14:52:16 +0200 (Tue, 30 Jun 2009)
Log Message: ----------- python access to RNA arrays. coords = array.array('f', [0.0]) * len(me.verts) * 3 m.verts.foreach_get('co', coords) the reverse works with set also. currently works for python buffers or sequences (slower) Quick speed test with 1,179,654 verts. *foreach_get* list 0.377 array 0.032 py 10.29 *foreach_set* list 0.184 array 0.028 py 9.79 where python was done like this... ---- i= 0 for v in m.verts: co = v.co l[i] = co[0]; l[i+1] = co[0]; l[i+2] = co[0] i+=3 ---- some of the error checking here needs to be cleaned up to account for different invalid bad inputs. Modified Paths: -------------- branches/blender2.5/blender/source/blender/makesrna/RNA_access.h branches/blender2.5/blender/source/blender/makesrna/intern/rna_access.c branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c Modified: branches/blender2.5/blender/source/blender/makesrna/RNA_access.h =================================================================== --- branches/blender2.5/blender/source/blender/makesrna/RNA_access.h 2009-06-30 09:10:37 UTC (rev 21262) +++ branches/blender2.5/blender/source/blender/makesrna/RNA_access.h 2009-06-30 12:52:16 UTC (rev 21263) @@ -606,7 +606,10 @@ int RNA_property_collection_raw_array(PointerRNA *ptr, PropertyRNA *prop, PropertyRNA *itemprop, RawArray *array); int RNA_property_collection_raw_get(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len); int RNA_property_collection_raw_set(struct ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len); +int RNA_raw_type_sizeof(RawPropertyType type); +RawPropertyType RNA_property_raw_type(PropertyRNA *prop); + /* to create ID property groups */ void RNA_property_pointer_add(PointerRNA *ptr, PropertyRNA *prop); void RNA_property_pointer_remove(PointerRNA *ptr, PropertyRNA *prop); Modified: branches/blender2.5/blender/source/blender/makesrna/intern/rna_access.c =================================================================== --- branches/blender2.5/blender/source/blender/makesrna/intern/rna_access.c 2009-06-30 09:10:37 UTC (rev 21262) +++ branches/blender2.5/blender/source/blender/makesrna/intern/rna_access.c 2009-06-30 12:52:16 UTC (rev 21263) @@ -1580,6 +1580,17 @@ } \ } +int RNA_raw_type_sizeof(RawPropertyType type) +{ + switch(type) { + case PROP_RAW_CHAR: return sizeof(char); + case PROP_RAW_SHORT: return sizeof(short); + case PROP_RAW_INT: return sizeof(int); + case PROP_RAW_FLOAT: return sizeof(float); + case PROP_RAW_DOUBLE: return sizeof(double); + } +} + static int rna_raw_access(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *inarray, RawPropertyType intype, int inlen, int set) { StructRNA *ptype; @@ -1630,15 +1641,8 @@ int a, size; itemlen= (itemlen == 0)? 1: itemlen; + size= RNA_raw_type_sizeof(out.type) * itemlen; - switch(out.type) { - case PROP_RAW_CHAR: size= sizeof(char)*itemlen; break; - case PROP_RAW_SHORT: size= sizeof(short)*itemlen; break; - case PROP_RAW_INT: size= sizeof(int)*itemlen; break; - case PROP_RAW_FLOAT: size= sizeof(float)*itemlen; break; - case PROP_RAW_DOUBLE: size= sizeof(double)*itemlen; break; - } - for(a=0; a<out.len; a++) { if(set) memcpy(outp, inp, size); else memcpy(inp, outp, size); @@ -1819,6 +1823,11 @@ } } +RawPropertyType RNA_property_raw_type(PropertyRNA *prop) +{ + return prop->rawtype; +} + int RNA_property_collection_raw_get(ReportList *reports, PointerRNA *ptr, PropertyRNA *prop, char *propname, void *array, RawPropertyType type, int len) { return rna_raw_access(reports, ptr, prop, propname, array, type, len, 0); Modified: branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c =================================================================== --- branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c 2009-06-30 09:10:37 UTC (rev 21262) +++ branches/blender2.5/blender/source/blender/python/intern/bpy_rna.c 2009-06-30 12:52:16 UTC (rev 21263) @@ -1130,7 +1130,7 @@ return pyrna_py_to_prop(&self->ptr, prop, NULL, value); } -PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_keys(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -1162,7 +1162,7 @@ return ret; } -PyObject *pyrna_prop_items(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_items(BPy_PropertyRNA *self) { PyObject *ret; if (RNA_property_type(self->prop) != PROP_COLLECTION) { @@ -1203,7 +1203,7 @@ } -PyObject *pyrna_prop_values(BPy_PropertyRNA *self) +static PyObject *pyrna_prop_values(BPy_PropertyRNA *self) { PyObject *ret; @@ -1225,6 +1225,240 @@ return ret; } +static void foreach_attr_type( BPy_PropertyRNA *self, char *attr, + /* values to assign */ + RawPropertyType *raw_type, int *attr_tot, int *attr_signed ) +{ + PropertyRNA *prop; + *raw_type= -1; + *attr_tot= 0; + *attr_signed= 0; + + RNA_PROP_BEGIN(&self->ptr, itemptr, self->prop) { + prop = RNA_struct_find_property(&itemptr, attr); + *raw_type= RNA_property_raw_type(prop); + *attr_tot = RNA_property_array_length(prop); + *attr_signed= (RNA_property_subtype(prop)==PROP_UNSIGNED) ? 0:1; + break; + } + RNA_PROP_END; +} + +/* pyrna_prop_foreach_get/set both use this */ +static int foreach_parse_args( + BPy_PropertyRNA *self, PyObject *args, + + /*values to assign */ + char **attr, PyObject **seq, int *tot, int *size, RawPropertyType *raw_type, int *attr_tot, int *attr_signed) +{ + int array_tot; + int target_tot; + + *size= *raw_type= *attr_tot= *attr_signed= 0; + + if(!PyArg_ParseTuple(args, "sO", attr, seq) || (!PySequence_Check(*seq) && PyObject_CheckBuffer(*seq))) { + PyErr_SetString( PyExc_TypeError, "foreach_get(attr, sequence) expects a string and a sequence" ); + return -1; + } + + *tot= PySequence_Length(*seq); // TODO - buffer may not be a sequence! array.array() is tho. + + if(*tot>0) { + foreach_attr_type(self, *attr, raw_type, attr_tot, attr_signed); + *size= RNA_raw_type_sizeof(*raw_type); + +#if 0 // works fine but not strictly needed, we could allow RNA_property_collection_raw_* to do the checks + if((*attr_tot) < 1) + *attr_tot= 1; + + if (RNA_property_type(self->prop) == PROP_COLLECTION) + array_tot = RNA_property_collection_length(&self->ptr, self->prop); + else + array_tot = RNA_property_array_length(self->prop); + + + target_tot= array_tot * (*attr_tot); + + /* rna_access.c - rna_raw_access(...) uses this same method */ + if(target_tot != (*tot)) { + PyErr_Format( PyExc_TypeError, "foreach_get(attr, sequence) sequence length mismatch given %d, needed %d", *tot, target_tot); + return -1; + } +#endif + } + + return 0; +} + +static int foreach_compat_buffer(RawPropertyType raw_type, int attr_signed, const char *format) +{ + char f = format ? *format:'B'; /* B is assumed when not set */ + + switch(raw_type) { + case PROP_RAW_CHAR: + if (attr_signed) return (f=='b') ? 1:0; + else return (f=='B') ? 1:0; + case PROP_RAW_SHORT: + if (attr_signed) return (f=='h') ? 1:0; + else return (f=='H') ? 1:0; + case PROP_RAW_INT: + if (attr_signed) return (f=='i') ? 1:0; + else return (f=='I') ? 1:0; + case PROP_RAW_FLOAT: + return (f=='f') ? 1:0; + case PROP_RAW_DOUBLE: + return (f=='d') ? 1:0; + } + + return 0; +} + +static PyObject *foreach_getset(BPy_PropertyRNA *self, PyObject *args, int set) +{ + PyObject *item; + int i=0, ok, buffer_is_compat; + void *array= NULL; + + /* get/set both take the same args currently */ + char *attr; + PyObject *seq; + int tot, size, attr_tot, attr_signed; + RawPropertyType raw_type; + + if(foreach_parse_args(self, args, &attr, &seq, &tot, &size, &raw_type, &attr_tot, &attr_signed) < 0) + return NULL; + + if(tot==0) + Py_RETURN_NONE; + + + + if(set) { /* get the array from python */ + buffer_is_compat = 0; + if(PyObject_CheckBuffer(seq)) { + Py_buffer buf; + PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); + + /* check if the buffer matches, TODO - signed/unsigned types */ + + buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); + + if(buffer_is_compat) { + ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); + } + + PyBuffer_Release(&buf); + } + + /* could not use the buffer, fallback to sequence */ + if(!buffer_is_compat) { + array= PyMem_Malloc(size * tot); + + for( ; i<tot; i++) { + item= PySequence_GetItem(seq, i); + switch(raw_type) { + case PROP_RAW_CHAR: + ((char *)array)[i]= (char)PyLong_AsSsize_t(item); + break; + case PROP_RAW_SHORT: + ((short *)array)[i]= (short)PyLong_AsSsize_t(item); + break; + case PROP_RAW_INT: + ((int *)array)[i]= (int)PyLong_AsSsize_t(item); + break; + case PROP_RAW_FLOAT: + ((float *)array)[i]= (float)PyFloat_AsDouble(item); + break; + case PROP_RAW_DOUBLE: + ((double *)array)[i]= (double)PyFloat_AsDouble(item); + break; + } + + Py_DECREF(item); + } + + ok = RNA_property_collection_raw_set(NULL, &self->ptr, self->prop, attr, array, raw_type, tot); + } + } + else { + buffer_is_compat = 0; + if(PyObject_CheckBuffer(seq)) { + Py_buffer buf; + PyObject_GetBuffer(seq, &buf, PyBUF_SIMPLE | PyBUF_FORMAT); + + /* check if the buffer matches, TODO - signed/unsigned types */ + + buffer_is_compat = foreach_compat_buffer(raw_type, attr_signed, buf.format); + + if(buffer_is_compat) { + ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, buf.buf, raw_type, tot); + } + + PyBuffer_Release(&buf); + } + + /* could not use the buffer, fallback to sequence */ + if(!buffer_is_compat) { + array= PyMem_Malloc(size * tot); + + ok = RNA_property_collection_raw_get(NULL, &self->ptr, self->prop, attr, array, raw_type, tot); + + if(!ok) i= tot; /* skip the loop */ + + for( ; i<tot; i++) { + + switch(raw_type) { + case PROP_RAW_CHAR: + item= PyLong_FromSsize_t( (Py_ssize_t) ((char *)array)[i] ); + break; + case PROP_RAW_SHORT: + item= PyLong_FromSsize_t( (Py_ssize_t) ((short *)array)[i] ); + break; + case PROP_RAW_INT: + item= PyLong_FromSsize_t( (Py_ssize_t) ((int *)array)[i] ); + break; + case PROP_RAW_FLOAT: + item= PyFloat_FromDouble( (double) ((float *)array)[i] ); + break; + case PROP_RAW_DOUBLE: + item= PyFloat_FromDouble( (double) ((double *)array)[i] ); + break; + } + + PySequence_SetItem(seq, i, item); + Py_DECREF(item); + } + } + } + + if(PyErr_Occurred()) { + /* Maybe we could make our own error */ + PyErr_Print(); + PyErr_SetString(PyExc_SystemError, "could not access the py sequence"); + return NULL; + } + if (!ok) { + PyErr_SetString(PyExc_SystemError, "internal error setting the array"); + return NULL; + } + + if(array) + PyMem_Free(array); + + Py_RETURN_NONE; +} + +static PyObject *pyrna_prop_foreach_get(BPy_PropertyRNA *self, PyObject *args) +{ + return foreach_getset(self, args, 0); +} + +static PyObject *pyrna_prop_foreach_set(BPy_PropertyRNA *self, PyObject *args) +{ + return foreach_getset(self, args, 1); +} + + /* A bit of a kludge, make a list out of a collection or array, @@ Diff output truncated at 10240 characters. @@ _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org http://lists.blender.org/mailman/listinfo/bf-blender-cvs