void render(PyObject * obj) { uint8_t * pixels; int x, y; float h, s, v; PyArrayObject* arr = (PyArrayObject*)obj; assert(PyArray_ISCARRAY(arr)); assert(PyArray_NDIM(arr) == 3); assert(PyArray_DIM(arr, 0) == ccw_size); assert(PyArray_DIM(arr, 1) == ccw_size); assert(PyArray_DIM(arr, 2) == 4); pixels = (uint8_t*)(PyArray_DATA(arr)); precalcDataIndex++; precalcDataIndex %= 4; PrecalcData * pre = precalcData[precalcDataIndex]; if (!pre) { pre = precalcData[precalcDataIndex] = precalc_data(2*M_PI*(precalcDataIndex/4.0)); } for (y=0; y<ccw_size; y++) { for (x=0; x<ccw_size; x++) { get_hsv(h, s, v, pre); pre++; hsv_to_rgb_range_one (&h, &s, &v); uint8_t * p = pixels + 4*(y*ccw_size + x); p[0] = h; p[1] = s; p[2] = v; p[3] = 255; } } }
// set state from numpy array void python_set_state (PyObject * data) { assert(PyArray_NDIM(data) == 1); assert(PyArray_DIM(data, 0) == STATE_COUNT); assert(PyArray_ISCARRAY(data)); npy_float32 * data_p = (npy_float32*)PyArray_DATA(data); for (int i=0; i<STATE_COUNT; i++) { set_state(i, data_p[i]); } }
// set state from numpy array void python_set_state (PyObject * obj) { PyArrayObject* data = (PyArrayObject*)obj; assert(PyArray_NDIM(data) == 1); assert(PyArray_DIM(data, 0) == MYPAINT_BRUSH_STATES_COUNT); assert(PyArray_ISCARRAY(data)); npy_float32 * data_p = (npy_float32*)PyArray_DATA(data); for (int i=0; i<MYPAINT_BRUSH_STATES_COUNT; i++) { set_state((MyPaintBrushState)i, data_p[i]); } }
int good_array(PyObject* o, int typenum) { if (!PyArray_Check(o)) { PyErr_SetString(PyExc_ValueError, "not a NumPy array" ); return 0; } if (PyArray_TYPE((PyArrayObject*)o) != typenum) { PyErr_SetString(PyExc_ValueError, "array of unexpected type"); return 0; } if (!PyArray_ISCARRAY((PyArrayObject*)o)) { PyErr_SetString(PyExc_ValueError, "array is not contiguous or not well behaved"); return 0; } return 1; }
uint16_t * get_tile_memory(MyPaintTiledSurface *tiled_surface, int tx, int ty, gboolean readonly) { MyPaintPythonTiledSurface *self = (MyPaintPythonTiledSurface *)tiled_surface; // We assume that the memory location does not change between begin_atomic() and end_atomic(). for (int i=0; i<self->tileMemoryValid; i++) { if (self->tileMemory[i].tx == tx and self->tileMemory[i].ty == ty) { return self->tileMemory[i].rgba_p; } } if (PyErr_Occurred()) return NULL; PyObject* rgba = PyObject_CallMethod(self->py_obj, "get_tile_memory", "(iii)", tx, ty, readonly); if (rgba == NULL) { printf("Python exception during get_tile_memory()!\n"); return NULL; } #ifdef HEAVY_DEBUG assert(PyArray_NDIM(rgba) == 3); assert(PyArray_DIM(rgba, 0) == TILE_SIZE); assert(PyArray_DIM(rgba, 1) == TILE_SIZE); assert(PyArray_DIM(rgba, 2) == 4); assert(PyArray_ISCARRAY(rgba)); assert(PyArray_TYPE(rgba) == NPY_UINT16); #endif // tiledsurface.py will keep a reference in its tiledict, at least until the final end_atomic() Py_DECREF(rgba); uint16_t * rgba_p = (uint16_t*)((PyArrayObject*)rgba)->data; // Cache tiles to speed up small brush strokes with lots of dabs, like charcoal. // Not caching readonly requests; they are alternated with write requests anyway. if (!readonly) { if (self->tileMemoryValid < TILE_MEMORY_SIZE) { self->tileMemoryValid++; } // We always overwrite the oldest cache entry. // We are mainly optimizing for strokes with radius smaller than one tile. self->tileMemory[self->tileMemoryWrite].tx = tx; self->tileMemory[self->tileMemoryWrite].ty = ty; self->tileMemory[self->tileMemoryWrite].rgba_p = rgba_p; self->tileMemoryWrite = (self->tileMemoryWrite + 1) % TILE_MEMORY_SIZE; } return rgba_p; }
static void tile_request_start(MyPaintTiledSurface *tiled_surface, MyPaintTileRequest *request) { MyPaintPythonTiledSurface *self = (MyPaintPythonTiledSurface *)tiled_surface; const gboolean readonly = request->readonly; const int tx = request->tx; const int ty = request->ty; PyArrayObject* rgba = NULL; #pragma omp critical { rgba = (PyArrayObject*)PyObject_CallMethod(self->py_obj, "_get_tile_numpy", "(iii)", tx, ty, readonly); if (rgba == NULL) { request->buffer = NULL; printf("Python exception during get_tile_numpy()!\n"); if (PyErr_Occurred()) { PyErr_Print(); } } else { #ifdef HEAVY_DEBUG assert(PyArray_NDIM(rgba) == 3); assert(PyArray_DIM(rgba, 0) == tiled_surface->tile_size); assert(PyArray_DIM(rgba, 1) == tiled_surface->tile_size); assert(PyArray_DIM(rgba, 2) == 4); assert(PyArray_ISCARRAY(rgba)); assert(PyArray_TYPE(rgba) == NPY_UINT16); #endif // tiledsurface.py will keep a reference in its tiledict, at least until the final end_atomic() Py_DECREF((PyObject *)rgba); request->buffer = (uint16_t*)PyArray_DATA(rgba); } } // #end pragma opt critical }
extern PyArrayObject* array_from_pyobj(const int type_num, npy_intp *dims, const int rank, const int intent, PyObject *obj) { /* Note about reference counting ----------------------------- If the caller returns the array to Python, it must be done with Py_BuildValue("N",arr). Otherwise, if obj!=arr then the caller must call Py_DECREF(arr). Note on intent(cache,out,..) --------------------- Don't expect correct data when returning intent(cache) array. */ char mess[200]; PyArrayObject *arr = NULL; PyArray_Descr *descr; char typechar; int elsize; if ((intent & F2PY_INTENT_HIDE) || ((intent & F2PY_INTENT_CACHE) && (obj==Py_None)) || ((intent & F2PY_OPTIONAL) && (obj==Py_None)) ) { /* intent(cache), optional, intent(hide) */ if (count_nonpos(rank,dims)) { int i; strcpy(mess, "failed to create intent(cache|hide)|optional array" "-- must have defined dimensions but got ("); for(i=0;i<rank;++i) sprintf(mess+strlen(mess),"%" NPY_INTP_FMT ",",dims[i]); strcat(mess, ")"); PyErr_SetString(PyExc_ValueError,mess); return NULL; } arr = (PyArrayObject *) PyArray_New(&PyArray_Type, rank, dims, type_num, NULL,NULL,0, !(intent&F2PY_INTENT_C), NULL); if (arr==NULL) return NULL; if (!(intent & F2PY_INTENT_CACHE)) PyArray_FILLWBYTE(arr, 0); return arr; } descr = PyArray_DescrFromType(type_num); elsize = descr->elsize; typechar = descr->type; Py_DECREF(descr); if (PyArray_Check(obj)) { arr = (PyArrayObject *)obj; if (intent & F2PY_INTENT_CACHE) { /* intent(cache) */ if (PyArray_ISONESEGMENT(arr) && PyArray_ITEMSIZE(arr)>=elsize) { if (check_and_fix_dimensions(arr,rank,dims)) { return NULL; /*XXX: set exception */ } if (intent & F2PY_INTENT_OUT) Py_INCREF(arr); return arr; } strcpy(mess, "failed to initialize intent(cache) array"); if (!PyArray_ISONESEGMENT(arr)) strcat(mess, " -- input must be in one segment"); if (PyArray_ITEMSIZE(arr)<elsize) sprintf(mess+strlen(mess), " -- expected at least elsize=%d but got %" NPY_INTP_FMT, elsize, (npy_intp)PyArray_ITEMSIZE(arr) ); PyErr_SetString(PyExc_ValueError,mess); return NULL; } /* here we have always intent(in) or intent(inout) or intent(inplace) */ if (check_and_fix_dimensions(arr,rank,dims)) { return NULL; /*XXX: set exception */ } /* printf("intent alignement=%d\n", F2PY_GET_ALIGNMENT(intent)); printf("alignement check=%d\n", F2PY_CHECK_ALIGNMENT(arr, intent)); int i; for (i=1;i<=16;i++) printf("i=%d isaligned=%d\n", i, ARRAY_ISALIGNED(arr, i)); */ if ((! (intent & F2PY_INTENT_COPY)) && PyArray_ITEMSIZE(arr)==elsize && ARRAY_ISCOMPATIBLE(arr,type_num) && F2PY_CHECK_ALIGNMENT(arr, intent) ) { if ((intent & F2PY_INTENT_C)?PyArray_ISCARRAY(arr):PyArray_ISFARRAY(arr)) { if ((intent & F2PY_INTENT_OUT)) { Py_INCREF(arr); } /* Returning input array */ return arr; } } if (intent & F2PY_INTENT_INOUT) { strcpy(mess, "failed to initialize intent(inout) array"); if ((intent & F2PY_INTENT_C) && !PyArray_ISCARRAY(arr)) strcat(mess, " -- input not contiguous"); if (!(intent & F2PY_INTENT_C) && !PyArray_ISFARRAY(arr)) strcat(mess, " -- input not fortran contiguous"); if (PyArray_ITEMSIZE(arr)!=elsize) sprintf(mess+strlen(mess), " -- expected elsize=%d but got %" NPY_INTP_FMT, elsize, (npy_intp)PyArray_ITEMSIZE(arr) ); if (!(ARRAY_ISCOMPATIBLE(arr,type_num))) sprintf(mess+strlen(mess)," -- input '%c' not compatible to '%c'", PyArray_DESCR(arr)->type,typechar); if (!(F2PY_CHECK_ALIGNMENT(arr, intent))) sprintf(mess+strlen(mess)," -- input not %d-aligned", F2PY_GET_ALIGNMENT(intent)); PyErr_SetString(PyExc_ValueError,mess); return NULL; } /* here we have always intent(in) or intent(inplace) */ { PyArrayObject *retarr = (PyArrayObject *) \ PyArray_New(&PyArray_Type, PyArray_NDIM(arr), PyArray_DIMS(arr), type_num, NULL,NULL,0, !(intent&F2PY_INTENT_C), NULL); if (retarr==NULL) return NULL; F2PY_REPORT_ON_ARRAY_COPY_FROMARR; if (PyArray_CopyInto(retarr, arr)) { Py_DECREF(retarr); return NULL; } if (intent & F2PY_INTENT_INPLACE) { if (swap_arrays(arr,retarr)) return NULL; /* XXX: set exception */ Py_XDECREF(retarr); if (intent & F2PY_INTENT_OUT) Py_INCREF(arr); } else { arr = retarr; } } return arr; } if ((intent & F2PY_INTENT_INOUT) || (intent & F2PY_INTENT_INPLACE) || (intent & F2PY_INTENT_CACHE)) { PyErr_SetString(PyExc_TypeError, "failed to initialize intent(inout|inplace|cache) " "array, input not an array"); return NULL; } { F2PY_REPORT_ON_ARRAY_COPY_FROMANY; arr = (PyArrayObject *) \ PyArray_FromAny(obj,PyArray_DescrFromType(type_num), 0,0, ((intent & F2PY_INTENT_C)?NPY_ARRAY_CARRAY:NPY_ARRAY_FARRAY) \ | NPY_ARRAY_FORCECAST, NULL); if (arr==NULL) return NULL; if (check_and_fix_dimensions(arr,rank,dims)) return NULL; /*XXX: set exception */ return arr; } }
aligned_array(PyArrayObject* array) :array_base<BaseType>(array) ,is_carray_(PyArray_ISCARRAY(array)) { assert(PyArray_ISALIGNED(array)); }