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

Reply via email to