slouken@0: /* slouken@0: SDL - Simple DirectMedia Layer slouken@1312: Copyright (C) 1997-2006 Sam Lantinga slouken@0: slouken@0: This library is free software; you can redistribute it and/or slouken@1312: modify it under the terms of the GNU Lesser General Public slouken@0: License as published by the Free Software Foundation; either slouken@1312: version 2.1 of the License, or (at your option) any later version. slouken@0: slouken@0: This library is distributed in the hope that it will be useful, slouken@0: but WITHOUT ANY WARRANTY; without even the implied warranty of slouken@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU slouken@1312: Lesser General Public License for more details. slouken@0: slouken@1312: You should have received a copy of the GNU Lesser General Public slouken@1312: License along with this library; if not, write to the Free Software slouken@1312: Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA slouken@0: slouken@0: Sam Lantinga slouken@252: slouken@libsdl.org slouken@0: */ slouken@1402: #include "SDL_config.h" slouken@0: slouken@0: #include "SDL_video.h" slouken@1895: #include "SDL_compat.h" slouken@0: #include "SDL_sysvideo.h" slouken@0: #include "SDL_blit.h" slouken@0: #include "SDL_RLEaccel_c.h" slouken@0: #include "SDL_pixels_c.h" slouken@0: #include "SDL_leaks.h" slouken@0: icculus@1251: slouken@0: /* Public routines */ slouken@0: /* slouken@0: * Create an empty RGB surface of the appropriate depth slouken@0: */ slouken@1895: SDL_Surface * slouken@1895: SDL_CreateRGBSurface(Uint32 flags, slouken@1895: int width, int height, int depth, slouken@1895: Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask) slouken@0: { slouken@1895: SDL_Surface *surface; slouken@0: slouken@2807: /* The flags are no longer used, make the compiler happy */ slouken@2807: flags; slouken@2807: slouken@1895: /* Allocate the surface */ slouken@1920: surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface)); slouken@1895: if (surface == NULL) { slouken@1895: SDL_OutOfMemory(); slouken@1895: return NULL; slouken@1895: } slouken@940: slouken@1895: surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask); slouken@1895: if (!surface->format) { slouken@1895: SDL_FreeSurface(surface); slouken@1895: return NULL; slouken@1895: } slouken@1895: surface->w = width; slouken@1895: surface->h = height; slouken@1895: surface->pitch = SDL_CalculatePitch(surface); slouken@1895: SDL_SetClipRect(surface, NULL); slouken@0: slouken@1895: if (surface->format->BitsPerPixel <= 8) { slouken@1895: SDL_Palette *palette = slouken@1895: SDL_AllocPalette((1 << surface->format->BitsPerPixel)); slouken@1895: if (!palette) { slouken@1895: SDL_FreeSurface(surface); slouken@1895: return NULL; slouken@1895: } slouken@1895: if (Rmask || Bmask || Gmask) { slouken@1895: const SDL_PixelFormat *format = surface->format; slouken@0: slouken@1895: /* create palette according to masks */ slouken@1895: int i; slouken@1895: int Rm = 0, Gm = 0, Bm = 0; slouken@1895: int Rw = 0, Gw = 0, Bw = 0; slouken@0: slouken@1895: if (Rmask) { slouken@1895: Rw = 8 - format->Rloss; slouken@1895: for (i = format->Rloss; i > 0; i -= Rw) slouken@1895: Rm |= 1 << i; slouken@1895: } slouken@1895: if (Gmask) { slouken@1895: Gw = 8 - format->Gloss; slouken@1895: for (i = format->Gloss; i > 0; i -= Gw) slouken@1895: Gm |= 1 << i; slouken@1895: } slouken@1895: if (Bmask) { slouken@1895: Bw = 8 - format->Bloss; slouken@1895: for (i = format->Bloss; i > 0; i -= Bw) slouken@1895: Bm |= 1 << i; slouken@1895: } slouken@1895: for (i = 0; i < palette->ncolors; ++i) { slouken@1895: int r, g, b; slouken@1895: r = (i & Rmask) >> format->Rshift; slouken@1895: r = (r << format->Rloss) | ((r * Rm) >> Rw); slouken@1895: palette->colors[i].r = r; slouken@0: slouken@1895: g = (i & Gmask) >> format->Gshift; slouken@1895: g = (g << format->Gloss) | ((g * Gm) >> Gw); slouken@1895: palette->colors[i].g = g; slouken@1895: slouken@1895: b = (i & Bmask) >> format->Bshift; slouken@1895: b = (b << format->Bloss) | ((b * Bm) >> Bw); slouken@1895: palette->colors[i].b = b; slouken@1895: } slouken@1895: } else if (palette->ncolors == 2) { slouken@1895: /* Create a black and white bitmap palette */ slouken@1895: palette->colors[0].r = 0xFF; slouken@1895: palette->colors[0].g = 0xFF; slouken@1895: palette->colors[0].b = 0xFF; slouken@1895: palette->colors[1].r = 0x00; slouken@1895: palette->colors[1].g = 0x00; slouken@1895: palette->colors[1].b = 0x00; slouken@1895: } slouken@1895: SDL_SetSurfacePalette(surface, palette); slouken@1895: SDL_FreePalette(palette); slouken@1895: } slouken@1895: slouken@1895: /* Get the pixels */ slouken@1895: if (surface->w && surface->h) { slouken@1895: surface->pixels = SDL_malloc(surface->h * surface->pitch); slouken@1895: if (!surface->pixels) { slouken@1895: SDL_FreeSurface(surface); slouken@1895: SDL_OutOfMemory(); slouken@1895: return NULL; slouken@1895: } slouken@1895: /* This is important for bitmaps */ slouken@1895: SDL_memset(surface->pixels, 0, surface->h * surface->pitch); slouken@1895: } slouken@1895: slouken@1895: /* Allocate an empty mapping */ slouken@1895: surface->map = SDL_AllocBlitMap(); slouken@1895: if (!surface->map) { slouken@1895: SDL_FreeSurface(surface); slouken@1895: return NULL; slouken@1895: } slouken@1895: SDL_FormatChanged(surface); slouken@1895: slouken@2267: /* By default surface with an alpha mask are set up for blending */ slouken@2267: if (Amask) { slouken@2267: SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND); slouken@2267: } slouken@2267: slouken@1895: /* The surface is ready to go */ slouken@1895: surface->refcount = 1; slouken@0: #ifdef CHECK_LEAKS slouken@1895: ++surfaces_allocated; slouken@0: #endif slouken@1895: return surface; slouken@0: } slouken@1895: slouken@0: /* slouken@0: * Create an RGB surface from an existing memory buffer slouken@0: */ slouken@1895: SDL_Surface * slouken@1895: SDL_CreateRGBSurfaceFrom(void *pixels, slouken@1895: int width, int height, int depth, int pitch, slouken@1895: Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, slouken@1895: Uint32 Amask) slouken@0: { slouken@1895: SDL_Surface *surface; slouken@0: slouken@1895: surface = slouken@1895: SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask); slouken@1895: if (surface != NULL) { slouken@1895: surface->flags |= SDL_PREALLOC; slouken@1895: surface->pixels = pixels; slouken@1895: surface->w = width; slouken@1895: surface->h = height; slouken@1895: surface->pitch = pitch; slouken@1895: SDL_SetClipRect(surface, NULL); slouken@1895: } slouken@1895: return surface; slouken@0: } slouken@1895: slouken@1895: static int slouken@1895: SDL_SurfacePaletteChanged(void *userdata, SDL_Palette * palette) slouken@1895: { slouken@1895: SDL_Surface *surface = (SDL_Surface *) userdata; slouken@1895: slouken@1895: SDL_FormatChanged(surface); slouken@1895: slouken@1895: return 0; slouken@1895: } slouken@1895: slouken@1895: int slouken@1895: SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette) slouken@1895: { slouken@1895: if (!surface || !surface->format) { slouken@1895: SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface"); slouken@1895: return -1; slouken@1895: } slouken@1895: slouken@1895: if (palette && palette->ncolors != (1 << surface->format->BitsPerPixel)) { slouken@1895: SDL_SetError slouken@1895: ("SDL_SetSurfacePalette() passed a palette that doesn't match the surface format"); slouken@1895: return -1; slouken@1895: } slouken@1895: slouken@1895: if (surface->format->palette == palette) { slouken@1895: return 0; slouken@1895: } slouken@1895: slouken@1895: if (surface->format->palette) { slouken@1895: SDL_DelPaletteWatch(surface->format->palette, slouken@1895: SDL_SurfacePaletteChanged, surface); slouken@1895: } slouken@1895: slouken@1895: surface->format->palette = palette; slouken@1895: slouken@1895: if (surface->format->palette) { slouken@1895: SDL_AddPaletteWatch(surface->format->palette, slouken@1895: SDL_SurfacePaletteChanged, surface); slouken@1895: } slouken@1895: return 0; slouken@1895: } slouken@1895: slouken@2267: int slouken@2267: SDL_SetSurfaceRLE(SDL_Surface * surface, int flag) slouken@0: { slouken@2267: int flags; slouken@0: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@1895: } slouken@0: slouken@2267: flags = surface->map->info.flags; slouken@1895: if (flag) { slouken@2267: surface->map->info.flags |= SDL_COPY_RLE_DESIRED; slouken@1895: } else { slouken@2267: surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED; slouken@1895: } slouken@2267: if (surface->map->info.flags != flags) { slouken@1895: SDL_InvalidateMap(surface->map); slouken@1895: } slouken@1895: return 0; slouken@431: } slouken@0: slouken@2267: int slouken@2267: SDL_SetColorKey(SDL_Surface * surface, Uint32 flag, Uint32 key) slouken@2266: { slouken@2266: int flags; slouken@2266: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: if (flag & SDL_RLEACCEL) { slouken@2266: SDL_SetSurfaceRLE(surface, 1); slouken@2266: } slouken@2266: slouken@2266: flags = surface->map->info.flags; slouken@2266: if (flag) { slouken@2266: surface->map->info.flags |= SDL_COPY_COLORKEY; slouken@2266: surface->map->info.colorkey = key; slouken@2266: } else { slouken@2266: surface->map->info.flags &= ~SDL_COPY_COLORKEY; slouken@2266: } slouken@2266: if (surface->map->info.flags != flags) { slouken@2266: SDL_InvalidateMap(surface->map); slouken@2266: } slouken@2267: slouken@2267: /* Compatibility mode */ slouken@2267: if (surface->map->info.flags & SDL_COPY_COLORKEY) { slouken@2267: surface->flags |= SDL_SRCCOLORKEY; slouken@2267: } else { slouken@2267: surface->flags &= ~SDL_SRCCOLORKEY; slouken@2267: } slouken@2267: slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2785: /* This is a fairly slow function to switch from colorkey to alpha */ slouken@2787: static void slouken@2786: SDL_ConvertColorkeyToAlpha(SDL_Surface * surface) slouken@2785: { slouken@2786: int x, y; slouken@2785: slouken@2786: if (!surface) { slouken@2786: return; slouken@2786: } slouken@2785: slouken@2786: if (!(surface->map->info.flags & SDL_COPY_COLORKEY) || slouken@2786: !surface->format->Amask) { slouken@2786: return; slouken@2786: } slouken@2785: slouken@2786: SDL_LockSurface(surface); slouken@2785: slouken@2786: switch (surface->format->BytesPerPixel) { slouken@2786: case 2: slouken@2786: { slouken@2786: Uint16 *row, *spot; slouken@2786: Uint16 ckey = (Uint16) surface->map->info.colorkey; slouken@2786: Uint16 mask = (Uint16) (~surface->format->Amask); slouken@2785: slouken@2786: row = (Uint16 *) surface->pixels; slouken@2786: for (y = surface->h; y--;) { slouken@2786: spot = row; slouken@2786: for (x = surface->w; x--;) { slouken@2786: if (*spot == ckey) { slouken@2786: *spot &= mask; slouken@2786: } slouken@2786: ++spot; slouken@2786: } slouken@2786: row += surface->pitch / 2; slouken@2786: } slouken@2786: } slouken@2786: break; slouken@2786: case 3: slouken@2786: /* FIXME */ slouken@2786: break; slouken@2786: case 4: slouken@2786: { slouken@2786: Uint32 *row, *spot; slouken@2786: Uint32 ckey = surface->map->info.colorkey; slouken@2786: Uint32 mask = ~surface->format->Amask; slouken@2785: slouken@2786: row = (Uint32 *) surface->pixels; slouken@2786: for (y = surface->h; y--;) { slouken@2786: spot = row; slouken@2786: for (x = surface->w; x--;) { slouken@2786: if (*spot == ckey) { slouken@2786: *spot &= mask; slouken@2786: } slouken@2786: ++spot; slouken@2786: } slouken@2786: row += surface->pitch / 4; slouken@2786: } slouken@2786: } slouken@2786: break; slouken@2786: } slouken@2785: slouken@2786: SDL_UnlockSurface(surface); slouken@2785: slouken@2786: SDL_SetColorKey(surface, 0, 0); slouken@2824: SDL_SetSurfaceBlendMode(surface, SDL_TEXTUREBLENDMODE_BLEND); slouken@2785: } slouken@2785: slouken@2267: int slouken@2267: SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b) slouken@2266: { slouken@2266: int flags; slouken@2266: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: surface->map->info.r = r; slouken@2266: surface->map->info.g = g; slouken@2266: surface->map->info.b = b; slouken@2266: slouken@2266: flags = surface->map->info.flags; slouken@2266: if (r != 0xFF || g != 0xFF || b != 0xFF) { slouken@2266: surface->map->info.flags |= SDL_COPY_MODULATE_COLOR; slouken@2266: } else { slouken@2266: surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR; slouken@2266: } slouken@2266: if (surface->map->info.flags != flags) { slouken@2266: SDL_InvalidateMap(surface->map); slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2266: slouken@2267: int slouken@2267: SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b) slouken@2266: { slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: if (r) { slouken@2266: *r = surface->map->info.r; slouken@2266: } slouken@2266: if (g) { slouken@2266: *g = surface->map->info.g; slouken@2266: } slouken@2266: if (b) { slouken@2266: *b = surface->map->info.b; slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha) slouken@2266: { slouken@2266: int flags; slouken@2266: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: surface->map->info.a = alpha; slouken@2266: slouken@2266: flags = surface->map->info.flags; slouken@2266: if (alpha != 0xFF) { slouken@2266: surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA; slouken@2266: } else { slouken@2266: surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA; slouken@2266: } slouken@2266: if (surface->map->info.flags != flags) { slouken@2266: SDL_InvalidateMap(surface->map); slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha) slouken@2266: { slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: if (alpha) { slouken@2266: *alpha = surface->map->info.a; slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_SetSurfaceBlendMode(SDL_Surface * surface, int blendMode) slouken@2266: { slouken@2266: int flags, status; slouken@2266: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: status = 0; slouken@2266: flags = surface->map->info.flags; slouken@2267: surface->map->info.flags &= slouken@2267: ~(SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD); slouken@2266: switch (blendMode) { slouken@2266: case SDL_TEXTUREBLENDMODE_NONE: slouken@2266: break; slouken@2266: case SDL_TEXTUREBLENDMODE_MASK: slouken@2266: surface->map->info.flags |= SDL_COPY_MASK; slouken@2266: break; slouken@2266: case SDL_TEXTUREBLENDMODE_BLEND: slouken@2266: surface->map->info.flags |= SDL_COPY_BLEND; slouken@2266: break; slouken@2266: case SDL_TEXTUREBLENDMODE_ADD: slouken@2266: surface->map->info.flags |= SDL_COPY_ADD; slouken@2266: break; slouken@2266: case SDL_TEXTUREBLENDMODE_MOD: slouken@2266: surface->map->info.flags |= SDL_COPY_MOD; slouken@2266: break; slouken@2266: default: slouken@2266: SDL_Unsupported(); slouken@2266: status = -1; slouken@2266: break; slouken@2266: } slouken@2266: slouken@2266: if (surface->map->info.flags != flags) { slouken@2266: SDL_InvalidateMap(surface->map); slouken@2266: } slouken@2267: slouken@2267: /* Compatibility mode */ slouken@2267: if (surface->map->info.flags & SDL_COPY_BLEND) { slouken@2267: surface->flags |= SDL_SRCALPHA; slouken@2267: } else { slouken@2267: surface->flags &= ~SDL_SRCALPHA; slouken@2267: } slouken@2267: slouken@2266: return status; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_GetSurfaceBlendMode(SDL_Surface * surface, int *blendMode) slouken@2266: { slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: if (!blendMode) { slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2735: switch (surface->map-> slouken@2735: info.flags & (SDL_COPY_MASK | SDL_COPY_BLEND | SDL_COPY_ADD | slouken@2735: SDL_COPY_MOD)) { slouken@2266: case SDL_COPY_MASK: slouken@2267: *blendMode = SDL_TEXTUREBLENDMODE_MASK; slouken@2266: break; slouken@2266: case SDL_COPY_BLEND: slouken@2267: *blendMode = SDL_TEXTUREBLENDMODE_BLEND; slouken@2266: break; slouken@2266: case SDL_COPY_ADD: slouken@2267: *blendMode = SDL_TEXTUREBLENDMODE_ADD; slouken@2266: break; slouken@2266: case SDL_COPY_MOD: slouken@2267: *blendMode = SDL_TEXTUREBLENDMODE_MOD; slouken@2266: break; slouken@2266: default: slouken@2267: *blendMode = SDL_TEXTUREBLENDMODE_NONE; slouken@2266: break; slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_SetSurfaceScaleMode(SDL_Surface * surface, int scaleMode) slouken@2266: { slouken@2266: int flags, status; slouken@2266: slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: status = 0; slouken@2266: flags = surface->map->info.flags; slouken@2266: surface->map->info.flags &= ~(SDL_COPY_NEAREST); slouken@2266: switch (scaleMode) { slouken@2266: case SDL_TEXTURESCALEMODE_NONE: slouken@2266: break; slouken@2266: case SDL_TEXTURESCALEMODE_FAST: slouken@2266: surface->map->info.flags |= SDL_COPY_NEAREST; slouken@2266: break; slouken@2266: case SDL_TEXTURESCALEMODE_SLOW: slouken@2266: case SDL_TEXTURESCALEMODE_BEST: slouken@2266: SDL_Unsupported(); slouken@2266: surface->map->info.flags |= SDL_COPY_NEAREST; slouken@2266: status = -1; slouken@2266: break; slouken@2266: default: slouken@2266: SDL_Unsupported(); slouken@2266: status = -1; slouken@2266: break; slouken@2266: } slouken@2266: slouken@2266: if (surface->map->info.flags != flags) { slouken@2266: SDL_InvalidateMap(surface->map); slouken@2266: } slouken@2266: return status; slouken@2266: } slouken@2266: slouken@2267: int slouken@2267: SDL_GetSurfaceScaleMode(SDL_Surface * surface, int *scaleMode) slouken@2266: { slouken@2266: if (!surface) { slouken@2266: return -1; slouken@2266: } slouken@2266: slouken@2266: if (!scaleMode) { slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@2267: switch (surface->map->info.flags & (SDL_COPY_NEAREST)) { slouken@2267: case SDL_COPY_NEAREST: slouken@2267: *scaleMode = SDL_TEXTURESCALEMODE_FAST; slouken@2266: break; slouken@2266: default: slouken@2267: *scaleMode = SDL_TEXTURESCALEMODE_NONE; slouken@2266: break; slouken@2266: } slouken@2266: return 0; slouken@2266: } slouken@2266: slouken@1895: SDL_bool slouken@1895: SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect) slouken@0: { slouken@1895: SDL_Rect full_rect; slouken@0: slouken@1895: /* Don't do anything if there's no surface to act on */ slouken@1895: if (!surface) { slouken@1895: return SDL_FALSE; slouken@1895: } slouken@0: slouken@1895: /* Set up the full surface rectangle */ slouken@1895: full_rect.x = 0; slouken@1895: full_rect.y = 0; slouken@1895: full_rect.w = surface->w; slouken@1895: full_rect.h = surface->h; slouken@0: slouken@1895: /* Set the clipping rectangle */ slouken@1895: if (!rect) { slouken@1895: surface->clip_rect = full_rect; slouken@1895: return 1; slouken@1895: } slouken@1895: return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect); slouken@0: } slouken@1895: slouken@1895: void slouken@1895: SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect) slouken@0: { slouken@1895: if (surface && rect) { slouken@1895: *rect = surface->clip_rect; slouken@1895: } slouken@0: } slouken@1895: slouken@0: /* slouken@0: * Set up a blit between two surfaces -- split into three parts: slouken@0: * The upper part, SDL_UpperBlit(), performs clipping and rectangle slouken@0: * verification. The lower part is a pointer to a low level slouken@0: * accelerated blitting function. slouken@0: * slouken@0: * These parts are separated out and each used internally by this slouken@0: * library in the optimimum places. They are exported so that if slouken@0: * you know exactly what you are doing, you can optimize your code slouken@0: * by calling the one(s) you need. slouken@0: */ slouken@1895: int slouken@1895: SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect, slouken@1895: SDL_Surface * dst, SDL_Rect * dstrect) slouken@0: { slouken@1895: /* Check to make sure the blit mapping is valid */ slouken@1895: if ((src->map->dst != dst) || slouken@1895: (src->map->dst->format_version != src->map->format_version)) { slouken@1895: if (SDL_MapSurface(src, dst) < 0) { slouken@1895: return (-1); slouken@1895: } bob@2328: /* just here for debugging */ bob@2329: /* printf */ bob@2329: /* ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */ bob@2329: /* src, dst->flags, src->map->info.flags, dst, dst->flags, */ bob@2329: /* dst->map->info.flags, src->map->blit); */ slouken@1895: } slouken@2257: return (src->map->blit(src, srcrect, dst, dstrect)); slouken@0: } slouken@0: slouken@0: slouken@1895: int slouken@1895: SDL_UpperBlit(SDL_Surface * src, SDL_Rect * srcrect, slouken@1895: SDL_Surface * dst, SDL_Rect * dstrect) slouken@0: { slouken@1895: SDL_Rect fulldst; slouken@1895: int srcx, srcy, w, h; slouken@0: slouken@1895: /* Make sure the surfaces aren't locked */ slouken@1895: if (!src || !dst) { slouken@1895: SDL_SetError("SDL_UpperBlit: passed a NULL surface"); slouken@1895: return (-1); slouken@1895: } slouken@1895: if (src->locked || dst->locked) { slouken@1895: SDL_SetError("Surfaces must not be locked during blit"); slouken@1895: return (-1); slouken@1895: } slouken@0: slouken@1895: /* If the destination rectangle is NULL, use the entire dest surface */ slouken@1895: if (dstrect == NULL) { slouken@1895: fulldst.x = fulldst.y = 0; slouken@1895: dstrect = &fulldst; slouken@1895: } slouken@0: slouken@1895: /* clip the source rectangle to the source surface */ slouken@1895: if (srcrect) { slouken@1895: int maxw, maxh; slouken@0: slouken@1895: srcx = srcrect->x; slouken@1895: w = srcrect->w; slouken@1895: if (srcx < 0) { slouken@1895: w += srcx; slouken@1895: dstrect->x -= srcx; slouken@1895: srcx = 0; slouken@1895: } slouken@1895: maxw = src->w - srcx; slouken@1895: if (maxw < w) slouken@1895: w = maxw; slouken@0: slouken@1895: srcy = srcrect->y; slouken@1895: h = srcrect->h; slouken@1895: if (srcy < 0) { slouken@1895: h += srcy; slouken@1895: dstrect->y -= srcy; slouken@1895: srcy = 0; slouken@1895: } slouken@1895: maxh = src->h - srcy; slouken@1895: if (maxh < h) slouken@1895: h = maxh; slouken@0: slouken@1895: } else { slouken@1895: srcx = srcy = 0; slouken@1895: w = src->w; slouken@1895: h = src->h; slouken@1895: } slouken@0: slouken@1895: /* clip the destination rectangle against the clip rectangle */ slouken@1895: { slouken@1895: SDL_Rect *clip = &dst->clip_rect; slouken@1895: int dx, dy; slouken@0: slouken@1895: dx = clip->x - dstrect->x; slouken@1895: if (dx > 0) { slouken@1895: w -= dx; slouken@1895: dstrect->x += dx; slouken@1895: srcx += dx; slouken@1895: } slouken@1895: dx = dstrect->x + w - clip->x - clip->w; slouken@1895: if (dx > 0) slouken@1895: w -= dx; slouken@1895: slouken@1895: dy = clip->y - dstrect->y; slouken@1895: if (dy > 0) { slouken@1895: h -= dy; slouken@1895: dstrect->y += dy; slouken@1895: srcy += dy; slouken@1895: } slouken@1895: dy = dstrect->y + h - clip->y - clip->h; slouken@1895: if (dy > 0) slouken@1895: h -= dy; slouken@1895: } slouken@1895: slouken@1895: if (w > 0 && h > 0) { slouken@1895: SDL_Rect sr; slouken@1895: sr.x = srcx; slouken@1895: sr.y = srcy; slouken@1895: sr.w = dstrect->w = w; slouken@1895: sr.h = dstrect->h = h; slouken@1895: return SDL_LowerBlit(src, &sr, dst, dstrect); slouken@1895: } slouken@1895: dstrect->w = dstrect->h = 0; slouken@1895: return 0; slouken@0: } slouken@0: slouken@0: /* slouken@0: * Lock a surface to directly access the pixels slouken@0: */ slouken@1895: int slouken@1895: SDL_LockSurface(SDL_Surface * surface) slouken@0: { slouken@1895: if (!surface->locked) { slouken@1895: /* Perform the lock */ slouken@1895: if (surface->flags & SDL_RLEACCEL) { slouken@1895: SDL_UnRLESurface(surface, 1); slouken@1895: surface->flags |= SDL_RLEACCEL; /* save accel'd state */ slouken@1895: } slouken@1895: } slouken@0: slouken@1895: /* Increment the surface lock count, for recursive locks */ slouken@1895: ++surface->locked; slouken@0: slouken@1895: /* Ready to go.. */ slouken@1895: return (0); slouken@0: } slouken@1895: slouken@0: /* slouken@0: * Unlock a previously locked surface slouken@0: */ slouken@1895: void slouken@1895: SDL_UnlockSurface(SDL_Surface * surface) slouken@0: { slouken@1895: /* Only perform an unlock if we are locked */ slouken@1895: if (!surface->locked || (--surface->locked > 0)) { slouken@1895: return; slouken@1895: } slouken@0: slouken@1895: /* Update RLE encoded surface with new data */ slouken@1895: if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) { slouken@1895: surface->flags &= ~SDL_RLEACCEL; /* stop lying */ slouken@1895: SDL_RLESurface(surface); slouken@1895: } slouken@0: } slouken@0: slouken@0: /* slouken@0: * Convert a surface into the specified pixel format. slouken@0: */ slouken@1895: SDL_Surface * slouken@2807: SDL_ConvertSurface(SDL_Surface * surface, SDL_PixelFormat * format, slouken@2807: Uint32 flags) slouken@0: { slouken@1895: SDL_Surface *convert; slouken@2266: Uint32 copy_flags; slouken@1895: SDL_Rect bounds; slouken@0: slouken@1895: /* Check for empty destination palette! (results in empty image) */ slouken@1895: if (format->palette != NULL) { slouken@1895: int i; slouken@1895: for (i = 0; i < format->palette->ncolors; ++i) { slouken@1895: if ((format->palette->colors[i].r != 0xFF) || slouken@1895: (format->palette->colors[i].g != 0xFF) || slouken@1895: (format->palette->colors[i].b != 0xFF)) slouken@1895: break; slouken@1895: } slouken@1895: if (i == format->palette->ncolors) { slouken@1895: SDL_SetError("Empty destination palette"); slouken@1895: return (NULL); slouken@1895: } slouken@1895: } slouken@0: slouken@1895: /* Create a new surface with the desired format */ slouken@2807: convert = SDL_CreateRGBSurface(flags, surface->w, surface->h, slouken@1895: format->BitsPerPixel, format->Rmask, slouken@1895: format->Gmask, format->Bmask, slouken@1895: format->Amask); slouken@1895: if (convert == NULL) { slouken@1895: return (NULL); slouken@1895: } slouken@264: slouken@1895: /* Copy the palette if any */ slouken@1895: if (format->palette && convert->format->palette) { slouken@1895: SDL_memcpy(convert->format->palette->colors, slouken@1895: format->palette->colors, slouken@1895: format->palette->ncolors * sizeof(SDL_Color)); slouken@1895: convert->format->palette->ncolors = format->palette->ncolors; slouken@1895: } slouken@0: slouken@2266: /* Save the original copy flags */ slouken@2266: copy_flags = surface->map->info.flags; slouken@2266: surface->map->info.flags = 0; slouken@0: slouken@1895: /* Copy over the image data */ slouken@1895: bounds.x = 0; slouken@1895: bounds.y = 0; slouken@1895: bounds.w = surface->w; slouken@1895: bounds.h = surface->h; slouken@1895: SDL_LowerBlit(surface, &bounds, convert, &bounds); slouken@0: slouken@1895: /* Clean up the original surface, and update converted surface */ slouken@2824: convert->map->info.r = surface->map->info.r; slouken@2824: convert->map->info.g = surface->map->info.g; slouken@2824: convert->map->info.b = surface->map->info.b; slouken@2824: convert->map->info.a = surface->map->info.a; slouken@2824: convert->map->info.flags = slouken@2824: (copy_flags & slouken@2824: ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND slouken@2824: | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY | slouken@2824: SDL_COPY_RLE_ALPHAKEY)); slouken@2824: surface->map->info.flags = copy_flags; slouken@2266: if (copy_flags & SDL_COPY_COLORKEY) { slouken@2266: Uint8 keyR, keyG, keyB, keyA; slouken@2266: slouken@2267: SDL_GetRGBA(surface->map->info.colorkey, surface->format, &keyR, slouken@2267: &keyG, &keyB, &keyA); slouken@2266: SDL_SetColorKey(convert, 1, slouken@2266: SDL_MapRGBA(convert->format, keyR, keyG, keyB, keyA)); slouken@2824: /* This is needed when converting for 3D texture upload */ slouken@2787: SDL_ConvertColorkeyToAlpha(convert); slouken@1895: } slouken@2824: SDL_SetClipRect(convert, &surface->clip_rect); slouken@0: slouken@2266: /* Enable alpha blending by default if the new surface has an slouken@2266: * alpha channel or alpha modulation */ slouken@2824: if ((surface->format->Amask && format->Amask) || slouken@2824: (copy_flags & SDL_COPY_MODULATE_ALPHA)) { slouken@2266: SDL_SetSurfaceBlendMode(convert, SDL_TEXTUREBLENDMODE_BLEND); slouken@1895: } slouken@2824: if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) { slouken@2824: SDL_SetSurfaceRLE(convert, SDL_RLEACCEL); slouken@2824: } slouken@0: slouken@1895: /* We're ready to go! */ slouken@1895: return (convert); slouken@0: } slouken@0: slouken@0: /* slouken@0: * Free a surface created by the above function. slouken@0: */ slouken@1895: void slouken@1895: SDL_FreeSurface(SDL_Surface * surface) slouken@0: { slouken@1895: if (surface == NULL) { slouken@1895: return; slouken@1895: } slouken@1895: if (--surface->refcount > 0) { slouken@1895: return; slouken@1895: } slouken@1895: while (surface->locked > 0) { slouken@1895: SDL_UnlockSurface(surface); slouken@1895: } slouken@1895: if (surface->flags & SDL_RLEACCEL) { slouken@1895: SDL_UnRLESurface(surface, 0); slouken@1895: } slouken@1895: if (surface->format) { slouken@1895: SDL_SetSurfacePalette(surface, NULL); slouken@1895: SDL_FreeFormat(surface->format); slouken@1895: surface->format = NULL; slouken@1895: } slouken@1895: if (surface->map != NULL) { slouken@1895: SDL_FreeBlitMap(surface->map); slouken@1895: surface->map = NULL; slouken@1895: } slouken@1895: if (surface->pixels && ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC)) { slouken@1895: SDL_free(surface->pixels); slouken@1895: } slouken@1895: SDL_free(surface); slouken@0: #ifdef CHECK_LEAKS slouken@1895: --surfaces_allocated; slouken@0: #endif slouken@0: } slouken@1895: slouken@1895: /* vi: set ts=4 sw=4 expandtab: */