2079
*surf_get_buffer (PyObject *self)
2083
SDL_Surface *surface = PySurface_AsSurface (self);
2086
length = (Py_ssize_t) surface->pitch * surface->h;
2088
buffer = PyBufferProxy_New (self, NULL, length, NULL);
2090
return RAISE (PyExc_SDLError,
2091
"could not acquire a buffer for the surface");
2094
lock = PySurface_LockLifetime (self, buffer);
2097
return RAISE (PyExc_SDLError, "could not lock surface");
2099
((PyBufferProxy *) buffer)->buffer = surface->pixels;
2100
((PyBufferProxy *) buffer)->lock = lock;
2105
2181
static PyObject *
2106
2182
_raise_get_view_ndim_error(int bitsize, SurfViewKind kind) {
2107
const char *kind_names[] = {"2D", "3D", "red", "green", "blue", "alpha"};
2183
const char *name = "<unknown>"; /* guard against a segfault */
2185
/* Put a human readable name to a surface view kind */
2110
2186
switch (kind) {
2187
/* This switch statement is exhaustive over the SurfViewKind enum */
2190
name = "contiguous bytes";
2193
name = "contigous pixels";
2112
2195
case VIEWKIND_2D:
2113
name = kind_names[0];
2115
2198
case VIEWKIND_3D:
2116
name = kind_names[1];
2118
2201
case VIEWKIND_RED:
2119
name = kind_names[2];
2121
2204
case VIEWKIND_GREEN:
2122
name = kind_names[3];
2124
2207
case VIEWKIND_BLUE:
2125
name = kind_names[4];
2127
2210
case VIEWKIND_ALPHA:
2128
name = kind_names[5];
2215
/* Assert this switch statement is exhaustive */
2217
/* Should not be here */
2131
2218
PyErr_Format(PyExc_SystemError,
2132
2219
"pygame bug in _raise_get_view_ndim_error:"
2133
2220
" unknown view kind %d", (int) kind);
2136
PyErr_Format(PyExc_ValueError,
2224
PyErr_Format(PyExc_ValueError,
2137
2225
"unsupported bit depth %d for %s reference array",
2138
2226
bitsize, name);
2143
surf_get_view(PyObject *self, PyObject *args, PyObject *kwds)
2231
surf_get_view (PyObject *self, PyObject *args)
2145
# define SURF_GET_VIEW_MAXDIM 3
2146
const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
2147
const int maxdim = SURF_GET_VIEW_MAXDIM;
2149
PyArrayInterface inter;
2150
Py_intptr_t shape_mem[SURF_GET_VIEW_MAXDIM];
2151
Py_intptr_t strides_mem[SURF_GET_VIEW_MAXDIM];
2153
# undef SURF_GET_VIEW_MAXDIM
2233
SDL_Surface *surface = PySurface_AsSurface (self);
2234
SDL_PixelFormat *format;
2154
2236
SurfViewKind view_kind = VIEWKIND_2D;
2157
Interface *allocation;
2158
PyArrayInterface *inter;
2159
SDL_Surface *surface = PySurface_AsSurface(self);
2163
Py_intptr_t *strides;
2169
char *keywords[] = {"kind", 0};
2237
getbufferproc get_buffer = 0;
2171
if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O&", keywords,
2172
surf_view_kind, &view_kind)) {
2239
if (!PyArg_ParseTuple (args, "|O&", _view_kind, &view_kind)) {
2176
2243
if (!surface) {
2177
return RAISE(PyExc_SDLError, "display Surface quit");
2180
allocation = PyMem_New(Interface, 1);
2182
return PyErr_NoMemory();
2184
inter = (PyArrayInterface *)allocation;
2185
inter->shape = allocation->shape_mem;
2186
inter->strides = allocation->strides_mem;
2188
capsule = PyCapsule_New(inter, 0, surf_arraystruct_capsule_destr);
2190
capsule = PyCObject_FromVoidPtr(inter, PyMem_Free);
2196
view = PgView_New(capsule, self, surf_view_destr);
2201
if (!PySurface_LockBy(self, view)) {
2206
startpixel = surface->pixels;
2207
pixelsize = surface->format->BytesPerPixel;
2209
inter->typekind = 'u';
2210
inter->flags = PAI_ALIGNED | PAI_NOTSWAPPED | PAI_WRITEABLE;
2212
shape = inter->shape;
2213
strides = inter->strides;
2214
shape[0] = (Py_intptr_t)surface->w;
2215
shape[1] = (Py_intptr_t)surface->h;
2216
strides[0] = (Py_intptr_t)pixelsize;
2217
strides[1] = (Py_intptr_t)surface->pitch;
2244
return RAISE (PyExc_SDLError, "display Surface quit");
2247
format = surface->format;
2218
2248
switch (view_kind) {
2249
/* This switch statement is exhaustive over the SurfViewKind enum */
2252
if (surface->pitch != format->BytesPerPixel * surface->w) {
2253
PyErr_SetString (PyExc_ValueError,
2254
"Surface data is not contiguous");
2257
get_buffer = _get_buffer_0D;
2260
if (surface->pitch != format->BytesPerPixel * surface->w) {
2261
PyErr_SetString (PyExc_ValueError,
2262
"Surface data is not contiguous");
2265
get_buffer = _get_buffer_1D;
2220
2267
case VIEWKIND_2D:
2222
itemsize = pixelsize;
2223
if (strides[1] == shape[0] * pixelsize) {
2224
inter->flags |= PAI_CONTIGUOUS;
2268
get_buffer = _get_buffer_2D;
2227
2270
case VIEWKIND_3D:
2228
if (pixelsize < 3) {
2230
return _raise_get_view_ndim_error(pixelsize * 8, view_kind);
2235
if (surface->format->Rmask == 0xff0000 &&
2236
surface->format->Gmask == 0x00ff00 &&
2237
surface->format->Bmask == 0x0000ff)
2239
strides[2] = lilendian ? -1 : 1;
2240
startpixel += lilendian ? 2 : 1;
2242
else if (surface->format->Bmask == 0xff0000 &&
2243
surface->format->Gmask == 0x00ff00 &&
2244
surface->format->Rmask == 0x0000ff)
2246
strides[2] = lilendian ? 1 : -1;
2247
startpixel += lilendian ? 0 : (pixelsize - 1);
2251
return RAISE(PyExc_ValueError,
2252
"unsupport colormasks for 3D reference array");
2271
if (format->BytesPerPixel < 3) {
2272
return _raise_get_view_ndim_error (format->BytesPerPixel * 8,
2275
if (format->Gmask != 0x00ff00 &&
2276
(format->BytesPerPixel != 4 ||
2277
format->Gmask != 0xff0000)) {
2278
return RAISE (PyExc_ValueError,
2279
"unsupport colormasks for 3D reference array");
2281
get_buffer = _get_buffer_3D;
2255
2283
case VIEWKIND_RED:
2256
mask = surface->format->Rmask;
2284
mask = format->Rmask;
2285
if (mask != 0x000000ffU &&
2286
mask != 0x0000ff00U &&
2287
mask != 0x00ff0000U &&
2288
mask != 0xff000000U ) {
2289
return RAISE (PyExc_ValueError,
2290
"unsupported colormasks for red reference array");
2292
get_buffer = _get_buffer_red;
2258
2294
case VIEWKIND_GREEN:
2259
mask = surface->format->Gmask;
2295
mask = format->Gmask;
2296
if (mask != 0x000000ffU &&
2297
mask != 0x0000ff00U &&
2298
mask != 0x00ff0000U &&
2299
mask != 0xff000000U ) {
2300
return RAISE (PyExc_ValueError,
2301
"unsupported colormasks for green reference array");
2303
get_buffer = _get_buffer_green;
2261
2305
case VIEWKIND_BLUE:
2262
mask = surface->format->Bmask;
2306
mask = format->Bmask;
2307
if (mask != 0x000000ffU &&
2308
mask != 0x0000ff00U &&
2309
mask != 0x00ff0000U &&
2310
mask != 0xff000000U ) {
2311
return RAISE (PyExc_ValueError,
2312
"unsupported colormasks for blue reference array");
2314
get_buffer = _get_buffer_blue;
2264
2316
case VIEWKIND_ALPHA:
2265
mask = surface->format->Amask;
2317
mask = format->Amask;
2318
if (mask != 0x000000ffU &&
2319
mask != 0x0000ff00U &&
2320
mask != 0x00ff0000U &&
2321
mask != 0xff000000U ) {
2322
return RAISE (PyExc_ValueError,
2323
"unsupported colormasks for alpha reference array");
2325
get_buffer = _get_buffer_alpha;
2329
/* Assert this switch statement is exhaustive */
2269
PyErr_Format(PyExc_SystemError,
2270
"pygame bug in surf_get_view:"
2271
" unrecognized view kind %d", (int)view_kind);
2331
/* Should not be here */
2332
PyErr_Format (PyExc_SystemError,
2333
"pygame bug in surf_get_view:"
2334
" unrecognized view kind %d", (int)view_kind);
2277
pixelstep = pixelsize;
2282
startpixel += lilendian ? 0 : 3;
2285
startpixel += lilendian ? 1 : 2;
2288
startpixel += lilendian ? 2 : 1;
2291
startpixel += lilendian ? 3 : 0;
2295
return RAISE(PyExc_ValueError,
2296
"unsupported colormasks for alpha reference array");
2300
inter->flags |= PAI_FORTRAN;
2303
inter->itemsize = itemsize;
2304
inter->data = startpixel;
2310
surf_view_kind(PyObject *obj, void *view_kind_vptr)
2338
assert (get_buffer);
2339
return PgBufproxy_New (self, get_buffer);
2343
surf_get_buffer (PyObject *self)
2345
SDL_Surface *surface = PySurface_AsSurface (self);
2346
PyObject *proxy_obj;
2349
return RAISE (PyExc_SDLError, "display Surface quit");
2352
proxy_obj = PgBufproxy_New (self, _get_buffer_0D);
2354
if (PgBufproxy_Trip (proxy_obj)) {
2355
Py_DECREF (proxy_obj);
2363
_get_buffer_0D (PyObject *obj, Py_buffer *view_p, int flags)
2365
SDL_Surface *surface = PySurface_AsSurface (obj);
2368
if (_init_buffer (obj, view_p, flags)) {
2371
view_p->buf = surface->pixels;
2372
view_p->itemsize = 1;
2373
view_p->len = surface->pitch * surface->h;
2374
view_p->readonly = 0;
2375
if (PyBUF_HAS_FLAG(flags, PyBUF_FORMAT)) {
2376
view_p->format = FormatUint8;
2378
if (PyBUF_HAS_FLAG(flags, PyBUF_ND)) {
2380
view_p->shape[0] = view_p->len;
2381
if (PyBUF_HAS_FLAG(flags, PyBUF_STRIDES)) {
2382
view_p->strides[0] = view_p->itemsize;
2391
_get_buffer_1D (PyObject *obj, Py_buffer *view_p, int flags)
2393
SDL_Surface *surface = PySurface_AsSurface (obj);
2394
Py_ssize_t itemsize = surface->format->BytesPerPixel;
2397
if (itemsize == 1) {
2398
return _get_buffer_0D (obj, view_p, flags);
2400
if (_init_buffer (obj, view_p, flags)) {
2403
if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
2405
/* This switch statement is exhaustive over all remaining possible
2406
itemsize values, the valid pixel byte sizes of non color-mapped
2410
view_p->format = FormatUint16;
2413
view_p->format = FormatUint24;
2416
view_p->format = FormatUint32;
2420
/* Assert this switch statement is exhaustive */
2422
/* Should not be here */
2423
PyErr_Format (PyExc_SystemError,
2424
"Pygame bug caught at line %i in file %s: "
2425
"unknown pixel size %i. Please report",
2426
(int)__LINE__, __FILE__, itemsize);
2431
view_p->buf = surface->pixels;
2432
view_p->itemsize = itemsize;
2433
view_p->readonly = 0;
2434
view_p->len = surface->pitch * surface->h;
2435
if (PyBUF_HAS_FLAG (flags, PyBUF_ND)) {
2437
view_p->shape[0] = surface->w * surface->h;
2438
if (PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
2439
view_p->strides[0] = itemsize;
2442
view_p->suboffsets = 0;
2449
_get_buffer_2D (PyObject *obj, Py_buffer *view_p, int flags)
2451
SDL_Surface *surface = PySurface_AsSurface (obj);
2452
int itemsize = surface->format->BytesPerPixel;
2455
if (!PyBUF_HAS_FLAG (flags, PyBUF_ND)) {
2456
if (surface->pitch != surface->w * itemsize) {
2457
PyErr_SetString (PgExc_BufferError,
2458
"A 2D surface view is not C contiguous");
2461
return _get_buffer_1D (obj, view_p, flags);
2463
if (!PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
2464
PyErr_SetString (PgExc_BufferError,
2465
"A 2D surface view is not C contiguous: "
2469
if (PyBUF_HAS_FLAG (flags, PyBUF_C_CONTIGUOUS)) {
2470
PyErr_SetString (PgExc_BufferError,
2471
"A 2D surface view is not C contiguous");
2474
if (PyBUF_HAS_FLAG (flags, PyBUF_F_CONTIGUOUS) &&
2475
surface->pitch != surface->w * itemsize) {
2476
PyErr_SetString (PgExc_BufferError,
2477
"This 2D surface view is not F contiguous");
2480
if (PyBUF_HAS_FLAG (flags, PyBUF_ANY_CONTIGUOUS) &&
2481
surface->pitch != surface->w * itemsize) {
2482
PyErr_SetString (PgExc_BufferError,
2483
"This 2D surface view is not contiguous");
2486
if (_init_buffer (obj, view_p, flags)) {
2489
if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
2491
/* This switch statement is exhaustive over all possible itemsize
2492
values, valid pixel byte sizes */
2495
view_p->format = FormatUint8;
2498
view_p->format = FormatUint16;
2501
view_p->format = FormatUint24;
2504
view_p->format = FormatUint32;
2508
/* Assert this switch statement is exhaustive */
2510
/* Should not be here */
2511
PyErr_Format (PyExc_SystemError,
2512
"Pygame bug caught at line %i in file %s: "
2513
"unknown pixel size %i. Please report",
2514
(int)__LINE__, __FILE__, itemsize);
2519
view_p->buf = surface->pixels;
2520
view_p->itemsize = itemsize;
2522
view_p->readonly = 0;
2523
view_p->len = surface->w * surface->h * itemsize;
2524
view_p->shape[0] = surface->w;
2525
view_p->shape[1] = surface->h;
2526
view_p->strides[0] = itemsize;
2527
view_p->strides[1] = surface->pitch;
2528
view_p->suboffsets = 0;
2535
_get_buffer_3D (PyObject *obj, Py_buffer *view_p, int flags)
2537
const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
2538
SDL_Surface *surface = PySurface_AsSurface (obj);
2539
int pixelsize = surface->format->BytesPerPixel;
2540
char *startpixel = (char *)surface->pixels;
2543
if (!PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
2544
PyErr_SetString (PgExc_BufferError,
2545
"A 3D surface view is not contiguous: needs strides");
2548
if (PyBUF_HAS_FLAG (flags, PyBUF_C_CONTIGUOUS) ||
2549
PyBUF_HAS_FLAG (flags, PyBUF_F_CONTIGUOUS) ||
2550
PyBUF_HAS_FLAG (flags, PyBUF_ANY_CONTIGUOUS)) {
2551
PyErr_SetString (PgExc_BufferError,
2552
"A 3D surface view is not contiguous");
2555
if (_init_buffer (obj, view_p, flags)) {
2558
if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
2559
view_p->format = FormatUint8;
2561
view_p->itemsize = 1;
2563
view_p->readonly = 0;
2564
view_p->len = surface->w * surface->h * 3;
2565
view_p->shape[0] = surface->w;
2566
view_p->shape[1] = surface->h;
2567
view_p->shape[2] = 3;
2568
view_p->strides[0] = pixelsize;
2569
view_p->strides[1] = surface->pitch;
2570
switch (surface->format->Rmask) {
2573
view_p->strides[2] = lilendian ? 1 : -1;
2574
startpixel += lilendian ? 0 : pixelsize - 1;
2577
assert(pixelsize == 4);
2578
view_p->strides[2] = lilendian ? 1 : -1;
2579
startpixel += lilendian ? 1 : pixelsize - 2;
2582
view_p->strides[2] = lilendian ? -1 : 1;
2583
startpixel += lilendian ? 2 : pixelsize - 3;
2585
default: /* 0xff000000U */
2586
assert(pixelsize == 4);
2587
view_p->strides[2] = lilendian ? -1 : 1;
2588
startpixel += lilendian ? 3 : 0;
2590
view_p->buf = startpixel;
2597
_get_buffer_red (PyObject *obj, Py_buffer *view_p, int flags)
2599
return _get_buffer_colorplane(obj,
2603
PySurface_AsSurface (obj)->format->Rmask);
2607
_get_buffer_green (PyObject *obj, Py_buffer *view_p, int flags)
2609
return _get_buffer_colorplane(obj,
2613
PySurface_AsSurface (obj)->format->Gmask);
2617
_get_buffer_blue (PyObject *obj, Py_buffer *view_p, int flags)
2619
return _get_buffer_colorplane(obj,
2623
PySurface_AsSurface (obj)->format->Bmask);
2627
_get_buffer_alpha (PyObject *obj, Py_buffer *view_p, int flags)
2629
return _get_buffer_colorplane(obj,
2633
PySurface_AsSurface (obj)->format->Amask);
2637
_get_buffer_colorplane (PyObject *obj,
2643
const int lilendian = (SDL_BYTEORDER == SDL_LIL_ENDIAN);
2644
SDL_Surface *surface = PySurface_AsSurface (obj);
2645
int pixelsize = surface->format->BytesPerPixel;
2646
char *startpixel = (char *)surface->pixels;
2649
if (!PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
2650
PyErr_SetString (PgExc_BufferError,
2651
"A surface color plane view is not contiguous: "
2655
if (PyBUF_HAS_FLAG (flags, PyBUF_C_CONTIGUOUS) ||
2656
PyBUF_HAS_FLAG (flags, PyBUF_F_CONTIGUOUS) ||
2657
PyBUF_HAS_FLAG (flags, PyBUF_ANY_CONTIGUOUS)) {
2658
PyErr_SetString (PgExc_BufferError,
2659
"A surface color plane view is not contiguous");
2663
/* This switch statement is exhaustive over possible mask value,
2664
the allowable masks for 24 bit and 32 bit surfaces */
2667
startpixel += lilendian ? 0 : pixelsize - 1;
2670
startpixel += lilendian ? 1 : pixelsize - 2;
2673
startpixel += lilendian ? 2 : pixelsize - 3;
2676
startpixel += lilendian ? 3 : 0;
2680
/* Assert this switch statement is exhaustive */
2682
/* Should not be here */
2683
PyErr_Format (PyExc_SystemError,
2684
"Pygame bug caught at line %i in file %s: "
2685
"unknown mask value %p. Please report",
2686
(int)__LINE__, __FILE__, (void *)mask);
2690
if (_init_buffer (obj, view_p, flags)) {
2693
view_p->buf = startpixel;
2694
if (PyBUF_HAS_FLAG (flags, PyBUF_FORMAT)) {
2695
view_p->format = FormatUint8;
2697
view_p->itemsize = 1;
2699
view_p->readonly = 0;
2700
view_p->len = surface->w * surface->h;
2701
view_p->shape[0] = surface->w;
2702
view_p->shape[1] = surface->h;
2703
view_p->strides[0] = pixelsize;
2704
view_p->strides[1] = surface->pitch;
2711
_init_buffer (PyObject *surf, Py_buffer *view_p, int flags)
2714
Pg_bufferinternal *internal;
2718
assert (PyObject_IsInstance (surf, (PyObject *)&PySurface_Type));
2719
assert (PyBUF_HAS_FLAG (flags, PyBUF_PYGAME));
2720
consumer = ((Pg_buffer *)view_p)->consumer;
2722
internal = PyMem_New (Pg_bufferinternal, 1);
2727
internal->consumer_ref = PyWeakref_NewRef (consumer, 0);
2728
if (!internal->consumer_ref) {
2729
PyMem_Free (internal);
2732
if (!PySurface_LockBy (surf, consumer)) {
2733
PyErr_Format (PgExc_BufferError,
2734
"Unable to lock <%s at %p> by <%s at %p>",
2735
Py_TYPE(surf)->tp_name, (void *)surf,
2736
Py_TYPE(consumer)->tp_name, (void *)consumer);
2737
Py_DECREF (internal->consumer_ref);
2738
PyMem_Free (internal);
2741
if (PyBUF_HAS_FLAG (flags, PyBUF_ND)) {
2742
view_p->shape = internal->mem;
2743
if (PyBUF_HAS_FLAG (flags, PyBUF_STRIDES)) {
2744
view_p->strides = internal->mem + 3;
2747
view_p->strides = 0;
2752
view_p->strides = 0;
2756
view_p->suboffsets = 0;
2757
view_p->internal = internal;
2758
((Pg_buffer *)view_p)->release_buffer = _release_buffer;
2763
_release_buffer (Py_buffer *view_p)
2765
Pg_bufferinternal *internal;
2766
PyObject *consumer_ref;
2769
assert (view_p && view_p->obj && view_p->internal);
2770
internal = (Pg_bufferinternal *)view_p->internal;
2771
consumer_ref = internal->consumer_ref;
2772
assert (consumer_ref && PyWeakref_CheckRef (consumer_ref));
2773
consumer = PyWeakref_GetObject (consumer_ref);
2775
if (!PySurface_UnlockBy (view_p->obj, consumer)) {
2779
Py_DECREF (consumer_ref);
2780
PyMem_Free (internal);
2781
Py_DECREF (view_p->obj);
2786
_view_kind (PyObject *obj, void *view_kind_vptr)
2312
2788
unsigned long ch;
2313
2789
SurfViewKind *view_kind_ptr = (SurfViewKind *)view_kind_vptr;
2315
if (PyUnicode_Check(obj)) {
2316
if (PyUnicode_GET_SIZE(obj) != 1) {
2317
PyErr_SetString(PyExc_TypeError,
2318
"expected a length 1 string for argument 1");
2791
if (PyUnicode_Check (obj)) {
2792
if (PyUnicode_GET_SIZE (obj) != 1) {
2793
PyErr_SetString (PyExc_TypeError,
2794
"expected a length 1 string for argument 1");
2321
ch = *PyUnicode_AS_UNICODE(obj);
2797
ch = *PyUnicode_AS_UNICODE (obj);
2323
else if (Bytes_Check(obj)) {
2324
if (Bytes_GET_SIZE(obj) != 1) {
2325
PyErr_SetString(PyExc_TypeError,
2326
"expected a length 1 string for argument 1");
2799
else if (Bytes_Check (obj)) {
2800
if (Bytes_GET_SIZE (obj) != 1) {
2801
PyErr_SetString (PyExc_TypeError,
2802
"expected a length 1 string for argument 1");
2329
ch = *Bytes_AS_STRING(obj);
2805
ch = *Bytes_AS_STRING (obj);
2332
PyErr_Format(PyExc_TypeError,
2333
"expected a length one string for argument 1: got '%s'",
2334
Py_TYPE(obj)->tp_name);
2808
PyErr_Format (PyExc_TypeError,
2809
"expected a length one string for argument 1: got '%s'",
2810
Py_TYPE (obj)->tp_name);
2816
*view_kind_ptr = VIEWKIND_0D;
2819
*view_kind_ptr = VIEWKIND_1D;
2340
2822
*view_kind_ptr = VIEWKIND_2D;