@@ -2215,6 +2215,227 @@ surf_grayscale(PyObject *self, PyObject *args, PyObject *kwargs)
2215
2215
}
2216
2216
}
2217
2217
2218
+ SDL_Surface *
2219
+ solid_overlay (pgSurfaceObject * srcobj , Uint32 color , pgSurfaceObject * dstobj ,
2220
+ const int keep_alpha )
2221
+ {
2222
+ SDL_Surface * src = pgSurface_AsSurface (srcobj );
2223
+ SDL_Surface * newsurf ;
2224
+ SDL_PixelFormat * fmt = src -> format ;
2225
+ Uint8 a ;
2226
+
2227
+ if (!dstobj ) {
2228
+ newsurf = newsurf_fromsurf (src , srcobj -> surf -> w , srcobj -> surf -> h );
2229
+ if (!newsurf )
2230
+ return NULL ;
2231
+ }
2232
+ else {
2233
+ newsurf = pgSurface_AsSurface (dstobj );
2234
+ }
2235
+
2236
+ if (newsurf -> w != src -> w || newsurf -> h != src -> h ) {
2237
+ return (SDL_Surface * )(RAISE (
2238
+ PyExc_ValueError ,
2239
+ "Destination surface must be the same size as source surface." ));
2240
+ }
2241
+
2242
+ if (fmt -> BytesPerPixel != newsurf -> format -> BytesPerPixel ||
2243
+ fmt -> format != newsurf -> format -> format ) {
2244
+ return (SDL_Surface * )(RAISE (
2245
+ PyExc_ValueError ,
2246
+ "Source and destination surfaces need the same format." ));
2247
+ }
2248
+
2249
+ /* If the source surface has no alpha channel, we can't overlay with alpha
2250
+ * blending. */
2251
+ if (!SDL_ISPIXELFORMAT_ALPHA (fmt -> format ))
2252
+ return newsurf ;
2253
+
2254
+ /* If we are keeping the src alpha, then we need to remove the alpha from
2255
+ * the color so it's easier to add the base pixel alpha back in */
2256
+ if (keep_alpha ) {
2257
+ color &= ~fmt -> Amask ;
2258
+ }
2259
+
2260
+ int src_lock = SDL_MUSTLOCK (src );
2261
+ int dst_lock = src != newsurf && SDL_MUSTLOCK (newsurf );
2262
+
2263
+ if (src_lock && SDL_LockSurface (src ) < 0 ) {
2264
+ return NULL ;
2265
+ }
2266
+ if (dst_lock && SDL_LockSurface (newsurf ) < 0 ) {
2267
+ if (src_lock ) {
2268
+ SDL_UnlockSurface (src );
2269
+ }
2270
+ return NULL ;
2271
+ }
2272
+
2273
+ /* optimized path for 32 bit surfaces */
2274
+ if (fmt -> BytesPerPixel == 4 ) {
2275
+ /* This algorithm iterates over each pixel's alpha channel. If it's not
2276
+ * zero, the pixel is set to the desired color. If the keep_alpha flag
2277
+ * is set, the original alpha value is retained, allowing the overlay
2278
+ * color to inherit the surface pixel's alpha value. */
2279
+ #if SDL_BYTEORDER == SDL_LIL_ENDIAN
2280
+ const int dst_ashift = fmt -> Ashift ;
2281
+ const char _a_off = fmt -> Ashift >> 3 ;
2282
+ #else
2283
+ const int dst_ashift = 24 - newsurf -> format -> Ashift ;
2284
+ const char _a_off = 3 - (newsurf -> format -> Ashift >> 3 );
2285
+ #endif
2286
+
2287
+ Uint8 * srcp = (Uint8 * )src -> pixels + _a_off ;
2288
+ Uint32 * dstp = (Uint32 * )newsurf -> pixels ;
2289
+
2290
+ const int src_skip = src -> pitch - src -> w * 4 ;
2291
+ const int dst_skip = newsurf -> pitch / 4 - newsurf -> w ;
2292
+ int n , height = src -> h ;
2293
+
2294
+ if (srcobj == dstobj ) {
2295
+ if (!keep_alpha ) {
2296
+ while (height -- ) {
2297
+ LOOP_UNROLLED4 (
2298
+ {
2299
+ if (* srcp )
2300
+ * dstp = color ;
2301
+ srcp += 4 ;
2302
+ dstp ++ ;
2303
+ },
2304
+ n , src -> w );
2305
+ srcp += src_skip ;
2306
+ dstp += dst_skip ;
2307
+ }
2308
+ }
2309
+ else {
2310
+ while (height -- ) {
2311
+ LOOP_UNROLLED4 (
2312
+ {
2313
+ if ((a = * srcp )) {
2314
+ * dstp = color | (a << dst_ashift );
2315
+ }
2316
+ srcp += 4 ;
2317
+ dstp ++ ;
2318
+ },
2319
+ n , src -> w );
2320
+ srcp += src_skip ;
2321
+ dstp += dst_skip ;
2322
+ }
2323
+ }
2324
+ }
2325
+ else {
2326
+ if (!keep_alpha ) {
2327
+ while (height -- ) {
2328
+ LOOP_UNROLLED4 (
2329
+ {
2330
+ if (* srcp )
2331
+ * dstp = color ;
2332
+ srcp += 4 ;
2333
+ dstp ++ ;
2334
+ },
2335
+ n , src -> w );
2336
+ srcp += src_skip ;
2337
+ dstp += dst_skip ;
2338
+ }
2339
+ }
2340
+ else {
2341
+ while (height -- ) {
2342
+ LOOP_UNROLLED4 (
2343
+ {
2344
+ if ((a = * srcp )) {
2345
+ * dstp = color | (a << dst_ashift );
2346
+ }
2347
+ srcp += 4 ;
2348
+ dstp ++ ;
2349
+ },
2350
+ n , src -> w );
2351
+ srcp += src_skip ;
2352
+ dstp += dst_skip ;
2353
+ }
2354
+ }
2355
+ }
2356
+ }
2357
+ else /* path for 16 bit surfaces */
2358
+ {
2359
+ int x , y ;
2360
+ Uint8 r , g , b ;
2361
+ Uint16 * src_row = (Uint16 * )src -> pixels ;
2362
+ Uint16 * dst_row = (Uint16 * )newsurf -> pixels ;
2363
+ const int src_skip = src -> pitch / 2 - src -> w ;
2364
+ const int dst_skip = newsurf -> pitch / 2 - newsurf -> w ;
2365
+
2366
+ Uint8 Cr , Cg , Cb , Ca ;
2367
+ SDL_GetRGBA (color , fmt , & Cr , & Cg , & Cb , & Ca );
2368
+ const Uint16 color16 = (Uint16 )SDL_MapRGBA (fmt , Cr , Cg , Cb , Ca );
2369
+
2370
+ for (y = 0 ; y < src -> h ; y ++ ) {
2371
+ for (x = 0 ; x < src -> w ; x ++ ) {
2372
+ SDL_GetRGBA ((Uint32 )* src_row , fmt , & r , & g , & b , & a );
2373
+
2374
+ if (a ) {
2375
+ if (keep_alpha )
2376
+ * dst_row = (Uint16 )SDL_MapRGBA (fmt , Cr , Cg , Cb , a );
2377
+ else
2378
+ * dst_row = color16 ;
2379
+ }
2380
+
2381
+ src_row ++ ;
2382
+ dst_row ++ ;
2383
+ }
2384
+ src_row += src_skip ;
2385
+ dst_row += dst_skip ;
2386
+ }
2387
+ }
2388
+
2389
+ if (src_lock )
2390
+ SDL_UnlockSurface (src );
2391
+ if (dst_lock )
2392
+ SDL_UnlockSurface (newsurf );
2393
+
2394
+ return newsurf ;
2395
+ }
2396
+
2397
+ static PyObject *
2398
+ surf_solid_overlay (PyObject * self , PyObject * args , PyObject * kwargs )
2399
+ {
2400
+ pgSurfaceObject * surfobj ;
2401
+ PyObject * colorobj ;
2402
+ Uint32 color ;
2403
+
2404
+ pgSurfaceObject * surfobj2 = NULL ;
2405
+ SDL_Surface * newsurf ;
2406
+ SDL_Surface * surf ;
2407
+ int keep_alpha = 0 ;
2408
+
2409
+ static char * keywords [] = {"surface" , "color" , "dest_surface" ,
2410
+ "keep_alpha" , NULL };
2411
+
2412
+ if (!PyArg_ParseTupleAndKeywords (args , kwargs , "O!O|O!i" , keywords ,
2413
+ & pgSurface_Type , & surfobj , & colorobj ,
2414
+ & pgSurface_Type , & surfobj2 , & keep_alpha ))
2415
+ return NULL ;
2416
+
2417
+ surf = pgSurface_AsSurface (surfobj );
2418
+
2419
+ if (!pg_MappedColorFromObj (colorobj , surf -> format , & color ,
2420
+ PG_COLOR_HANDLE_ALL )) {
2421
+ return RAISE (PyExc_TypeError , "invalid color argument" );
2422
+ }
2423
+
2424
+ newsurf = solid_overlay (surfobj , color , surfobj2 , keep_alpha );
2425
+
2426
+ if (!newsurf ) {
2427
+ return NULL ;
2428
+ }
2429
+
2430
+ if (surfobj2 ) {
2431
+ Py_INCREF (surfobj2 );
2432
+ return (PyObject * )surfobj2 ;
2433
+ }
2434
+ else {
2435
+ return (PyObject * )pgSurface_New (newsurf );
2436
+ }
2437
+ }
2438
+
2218
2439
#define MIN3 (a , b , c ) MIN(MIN(a, b), c)
2219
2440
#define MAX3 (a , b , c ) MAX(MAX(a, b), c)
2220
2441
@@ -3793,6 +4014,8 @@ static PyMethodDef _transform_methods[] = {
3793
4014
DOC_TRANSFORM_INVERT },
3794
4015
{"grayscale" , (PyCFunction )surf_grayscale , METH_VARARGS | METH_KEYWORDS ,
3795
4016
DOC_TRANSFORM_GRAYSCALE },
4017
+ {"solid_overlay" , (PyCFunction )surf_solid_overlay ,
4018
+ METH_VARARGS | METH_KEYWORDS , DOC_TRANSFORM_SOLIDOVERLAY },
3796
4019
{"hsl" , (PyCFunction )surf_hsl , METH_VARARGS | METH_KEYWORDS ,
3797
4020
DOC_TRANSFORM_HSL },
3798
4021
{NULL , NULL , 0 , NULL }};
0 commit comments