| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | { |
| | | int pitch; |
| | | |
| | | /* Surface should be 4-byte aligned for speed */ |
| | | pitch = width * SDL_BYTESPERPIXEL(format); |
| | | switch (SDL_BITSPERPIXEL(format)) { |
| | | case 1: |
| | | pitch = (pitch + 7) / 8; |
| | | break; |
| | | case 4: |
| | | pitch = (pitch + 1) / 2; |
| | | break; |
| | | default: |
| | | break; |
| | | if (SDL_ISPIXELFORMAT_FOURCC(format) || SDL_BITSPERPIXEL(format) >= 8) { |
| | | pitch = (width * SDL_BYTESPERPIXEL(format)); |
| | | } else { |
| | | pitch = ((width * SDL_BITSPERPIXEL(format)) + 7) / 8; |
| | | } |
| | | pitch = (pitch + 3) & ~3; /* 4-byte aligning */ |
| | | pitch = (pitch + 3) & ~3; /* 4-byte aligning for speed */ |
| | | return pitch; |
| | | } |
| | | |
| | |
| | | return NULL; |
| | | } |
| | | |
| | | surface->pixels = SDL_malloc((size_t)size); |
| | | surface->pixels = SDL_SIMDAlloc((size_t)size); |
| | | if (!surface->pixels) { |
| | | SDL_FreeSurface(surface); |
| | | SDL_OutOfMemory(); |
| | | return NULL; |
| | | } |
| | | surface->flags |= SDL_SIMD_ALIGNED; |
| | | /* This is important for bitmaps */ |
| | | SDL_memset(surface->pixels, 0, surface->h * surface->pitch); |
| | | } |
| | |
| | | if (flag) { |
| | | surface->map->info.flags |= SDL_COPY_COLORKEY; |
| | | surface->map->info.colorkey = key; |
| | | if (surface->format->palette) { |
| | | surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT; |
| | | ++surface->format->palette->version; |
| | | if (!surface->format->palette->version) { |
| | | surface->format->palette->version = 1; |
| | | } |
| | | } |
| | | } else { |
| | | if (surface->format->palette) { |
| | | surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_OPAQUE; |
| | | ++surface->format->palette->version; |
| | | if (!surface->format->palette->version) { |
| | | surface->format->palette->version = 1; |
| | | } |
| | | } |
| | | surface->map->info.flags &= ~SDL_COPY_COLORKEY; |
| | | } |
| | | if (surface->map->info.flags != flags) { |
| | |
| | | return SDL_FALSE; |
| | | } |
| | | |
| | | return SDL_TRUE; |
| | | return SDL_TRUE; |
| | | } |
| | | |
| | | int |
| | |
| | | |
| | | /* This is a fairly slow function to switch from colorkey to alpha */ |
| | | static void |
| | | SDL_ConvertColorkeyToAlpha(SDL_Surface * surface) |
| | | SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha) |
| | | { |
| | | int x, y; |
| | | |
| | |
| | | Uint16 ckey = (Uint16) surface->map->info.colorkey; |
| | | Uint16 mask = (Uint16) (~surface->format->Amask); |
| | | |
| | | /* Ignore alpha in colorkey comparison */ |
| | | ckey &= mask; |
| | | row = (Uint16 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if ((*spot & mask) == ckey) { |
| | | *spot &= mask; |
| | | /* Ignore, or not, alpha in colorkey comparison */ |
| | | if (ignore_alpha) { |
| | | ckey &= mask; |
| | | row = (Uint16 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if ((*spot & mask) == ckey) { |
| | | *spot &= mask; |
| | | } |
| | | ++spot; |
| | | } |
| | | ++spot; |
| | | row += surface->pitch / 2; |
| | | } |
| | | row += surface->pitch / 2; |
| | | } else { |
| | | row = (Uint16 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if (*spot == ckey) { |
| | | *spot &= mask; |
| | | } |
| | | ++spot; |
| | | } |
| | | row += surface->pitch / 2; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | |
| | | Uint32 ckey = surface->map->info.colorkey; |
| | | Uint32 mask = ~surface->format->Amask; |
| | | |
| | | /* Ignore alpha in colorkey comparison */ |
| | | ckey &= mask; |
| | | row = (Uint32 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if ((*spot & mask) == ckey) { |
| | | *spot &= mask; |
| | | /* Ignore, or not, alpha in colorkey comparison */ |
| | | if (ignore_alpha) { |
| | | ckey &= mask; |
| | | row = (Uint32 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if ((*spot & mask) == ckey) { |
| | | *spot &= mask; |
| | | } |
| | | ++spot; |
| | | } |
| | | ++spot; |
| | | row += surface->pitch / 4; |
| | | } |
| | | row += surface->pitch / 4; |
| | | } else { |
| | | row = (Uint32 *) surface->pixels; |
| | | for (y = surface->h; y--;) { |
| | | spot = row; |
| | | for (x = surface->w; x--;) { |
| | | if (*spot == ckey) { |
| | | *spot &= mask; |
| | | } |
| | | ++spot; |
| | | } |
| | | row += surface->pitch / 4; |
| | | } |
| | | } |
| | | } |
| | | break; |
| | |
| | | status = 0; |
| | | flags = surface->map->info.flags; |
| | | surface->map->info.flags &= |
| | | ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD); |
| | | ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL); |
| | | switch (blendMode) { |
| | | case SDL_BLENDMODE_NONE: |
| | | break; |
| | |
| | | break; |
| | | case SDL_BLENDMODE_MOD: |
| | | surface->map->info.flags |= SDL_COPY_MOD; |
| | | break; |
| | | case SDL_BLENDMODE_MUL: |
| | | surface->map->info.flags |= SDL_COPY_MUL; |
| | | break; |
| | | default: |
| | | status = SDL_Unsupported(); |
| | |
| | | } |
| | | |
| | | switch (surface->map-> |
| | | info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD)) { |
| | | info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) { |
| | | case SDL_COPY_BLEND: |
| | | *blendMode = SDL_BLENDMODE_BLEND; |
| | | break; |
| | |
| | | break; |
| | | case SDL_COPY_MOD: |
| | | *blendMode = SDL_BLENDMODE_MOD; |
| | | break; |
| | | case SDL_COPY_MUL: |
| | | *blendMode = SDL_BLENDMODE_MUL; |
| | | break; |
| | | default: |
| | | *blendMode = SDL_BLENDMODE_NONE; |
| | |
| | | { |
| | | static const Uint32 complex_copy_flags = ( |
| | | SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA | |
| | | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | |
| | | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL | |
| | | SDL_COPY_COLORKEY |
| | | ); |
| | | |
| | |
| | | SDL_LockSurface(SDL_Surface * surface) |
| | | { |
| | | if (!surface->locked) { |
| | | #if SDL_HAVE_RLE |
| | | /* Perform the lock */ |
| | | if (surface->flags & SDL_RLEACCEL) { |
| | | SDL_UnRLESurface(surface, 1); |
| | | surface->flags |= SDL_RLEACCEL; /* save accel'd state */ |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | /* Increment the surface lock count, for recursive locks */ |
| | |
| | | return; |
| | | } |
| | | |
| | | #if SDL_HAVE_RLE |
| | | /* Update RLE encoded surface with new data */ |
| | | if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { |
| | | surface->flags &= ~SDL_RLEACCEL; /* stop lying */ |
| | | SDL_RLESurface(surface); |
| | | } |
| | | #endif |
| | | } |
| | | |
| | | /* |
| | |
| | | Uint32 copy_flags; |
| | | SDL_Color copy_color; |
| | | SDL_Rect bounds; |
| | | int ret; |
| | | SDL_bool palette_ck_transform = SDL_FALSE; |
| | | int palette_ck_value = 0; |
| | | SDL_bool palette_has_alpha = SDL_FALSE; |
| | | Uint8 *palette_saved_alpha = NULL; |
| | | |
| | | if (!surface) { |
| | | SDL_InvalidParamError("surface"); |
| | |
| | | bounds.y = 0; |
| | | bounds.w = surface->w; |
| | | bounds.h = surface->h; |
| | | SDL_LowerBlit(surface, &bounds, convert, &bounds); |
| | | |
| | | /* Source surface has a palette with no real alpha (0 or OPAQUE). |
| | | * Destination format has alpha. |
| | | * -> set alpha channel to be opaque */ |
| | | if (surface->format->palette && format->Amask) { |
| | | SDL_bool set_opaque = SDL_FALSE; |
| | | { |
| | | int i; |
| | | for (i = 0; i < surface->format->palette->ncolors; i++) { |
| | | Uint8 alpha_value = surface->format->palette->colors[i].a; |
| | | |
| | | if (alpha_value != 0 && alpha_value != SDL_ALPHA_OPAQUE) { |
| | | /* Palette has at least one alpha value. Don't do anything */ |
| | | set_opaque = SDL_FALSE; |
| | | palette_has_alpha = SDL_TRUE; |
| | | break; |
| | | } |
| | | |
| | | if (alpha_value == 0) { |
| | | set_opaque = SDL_TRUE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* Set opaque and backup palette alpha values */ |
| | | if (set_opaque) { |
| | | int i; |
| | | palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors); |
| | | for (i = 0; i < surface->format->palette->ncolors; i++) { |
| | | palette_saved_alpha[i] = surface->format->palette->colors[i].a; |
| | | surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE; |
| | | } |
| | | } |
| | | } |
| | | |
| | | /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */ |
| | | if (copy_flags & SDL_COPY_COLORKEY) { |
| | | if (surface->format->palette && !format->palette) { |
| | | palette_ck_transform = SDL_TRUE; |
| | | palette_has_alpha = SDL_TRUE; |
| | | palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a; |
| | | surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT; |
| | | } |
| | | } |
| | | |
| | | ret = SDL_LowerBlit(surface, &bounds, convert, &bounds); |
| | | |
| | | /* Restore colorkey alpha value */ |
| | | if (palette_ck_transform) { |
| | | surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value; |
| | | } |
| | | |
| | | /* Restore palette alpha values */ |
| | | if (palette_saved_alpha) { |
| | | int i; |
| | | for (i = 0; i < surface->format->palette->ncolors; i++) { |
| | | surface->format->palette->colors[i].a = palette_saved_alpha[i]; |
| | | } |
| | | SDL_stack_free(palette_saved_alpha); |
| | | } |
| | | |
| | | /* Clean up the original surface, and update converted surface */ |
| | | convert->map->info.r = copy_color.r; |
| | |
| | | surface->map->info.a = copy_color.a; |
| | | surface->map->info.flags = copy_flags; |
| | | SDL_InvalidateMap(surface->map); |
| | | |
| | | /* SDL_LowerBlit failed, and so the conversion */ |
| | | if (ret < 0) { |
| | | SDL_FreeSurface(convert); |
| | | return NULL; |
| | | } |
| | | |
| | | if (copy_flags & SDL_COPY_COLORKEY) { |
| | | SDL_bool set_colorkey_by_color = SDL_FALSE; |
| | | |
| | |
| | | surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) { |
| | | /* The palette is identical, just set the same colorkey */ |
| | | SDL_SetColorKey(convert, 1, surface->map->info.colorkey); |
| | | } else if (format->Amask) { |
| | | /* The alpha was set in the destination from the palette */ |
| | | } else if (!format->palette) { |
| | | /* Was done by 'palette_ck_transform' */ |
| | | } else { |
| | | set_colorkey_by_color = SDL_TRUE; |
| | | } |
| | |
| | | if (surface->format->palette) { |
| | | SDL_SetSurfacePalette(tmp, surface->format->palette); |
| | | } |
| | | |
| | | |
| | | SDL_FillRect(tmp, NULL, surface->map->info.colorkey); |
| | | |
| | | tmp->map->info.flags &= ~SDL_COPY_COLORKEY; |
| | |
| | | SDL_SetColorKey(convert, 1, converted_colorkey); |
| | | |
| | | /* This is needed when converting for 3D texture upload */ |
| | | SDL_ConvertColorkeyToAlpha(convert); |
| | | SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE); |
| | | } |
| | | } |
| | | SDL_SetClipRect(convert, &surface->clip_rect); |
| | |
| | | /* Enable alpha blending by default if the new surface has an |
| | | * alpha channel or alpha modulation */ |
| | | if ((surface->format->Amask && format->Amask) || |
| | | (palette_has_alpha && format->Amask) || |
| | | (copy_flags & SDL_COPY_MODULATE_ALPHA)) { |
| | | SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND); |
| | | } |
| | |
| | | return SDL_InvalidParamError("dst_pitch"); |
| | | } |
| | | |
| | | #if SDL_HAVE_YUV |
| | | if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) { |
| | | return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); |
| | | } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) { |
| | |
| | | } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) { |
| | | return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch); |
| | | } |
| | | #else |
| | | if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) { |
| | | SDL_SetError("SDL not built with YUV support"); |
| | | return -1; |
| | | } |
| | | #endif |
| | | |
| | | /* Fast path for same format copy */ |
| | | if (src_format == dst_format) { |
| | |
| | | while (surface->locked > 0) { |
| | | SDL_UnlockSurface(surface); |
| | | } |
| | | #if SDL_HAVE_RLE |
| | | if (surface->flags & SDL_RLEACCEL) { |
| | | SDL_UnRLESurface(surface, 0); |
| | | } |
| | | #endif |
| | | if (surface->format) { |
| | | SDL_SetSurfacePalette(surface, NULL); |
| | | SDL_FreeFormat(surface->format); |
| | | surface->format = NULL; |
| | | } |
| | | if (!(surface->flags & SDL_PREALLOC)) { |
| | | if (surface->flags & SDL_PREALLOC) { |
| | | /* Don't free */ |
| | | } else if (surface->flags & SDL_SIMD_ALIGNED) { |
| | | /* Free aligned */ |
| | | SDL_SIMDFree(surface->pixels); |
| | | } else { |
| | | /* Normal */ |
| | | SDL_free(surface->pixels); |
| | | } |
| | | if (surface->map) { |