📄 sdl_surface.c
字号:
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id: SDL_surface.c,v 1.4 2002/04/22 21:38:03 wmay Exp $";
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_sysvideo.h"
#include "SDL_cursor_c.h"
#include "SDL_blit.h"
#include "SDL_RLEaccel_c.h"
#include "SDL_pixels_c.h"
#include "SDL_memops.h"
#include "SDL_leaks.h"
/* Public routines */
/*
* Create an empty RGB surface of the appropriate depth
*/
SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
int width, int height, int depth,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
SDL_Surface *screen;
SDL_Surface *surface;
/* Check to see if we desire the surface in video memory */
if ( video ) {
screen = SDL_PublicSurface;
} else {
screen = NULL;
}
if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
flags |= SDL_HWSURFACE;
}
if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
if ( ! current_video->info.blit_hw_CC ) {
flags &= ~SDL_HWSURFACE;
}
}
if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
if ( ! current_video->info.blit_hw_A ) {
flags &= ~SDL_HWSURFACE;
}
}
} else {
flags &= ~SDL_HWSURFACE;
}
/* Allocate the surface */
surface = (SDL_Surface *)malloc(sizeof(*surface));
if ( surface == NULL ) {
SDL_OutOfMemory();
return(NULL);
}
surface->flags = SDL_SWSURFACE;
if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
depth = screen->format->BitsPerPixel;
Rmask = screen->format->Rmask;
Gmask = screen->format->Gmask;
Bmask = screen->format->Bmask;
Amask = screen->format->Amask;
}
surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
if ( surface->format == NULL ) {
free(surface);
return(NULL);
}
if ( Amask ) {
surface->flags |= SDL_SRCALPHA;
}
surface->w = width;
surface->h = height;
surface->pitch = SDL_CalculatePitch(surface);
surface->pixels = NULL;
surface->offset = 0;
surface->hwdata = NULL;
surface->locked = 0;
surface->map = NULL;
surface->format_version = 0;
SDL_SetClipRect(surface, NULL);
/* Get the pixels */
if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) ||
(video->AllocHWSurface(this, surface) < 0) ) {
if ( surface->w && surface->h ) {
surface->pixels = malloc(surface->h*surface->pitch);
if ( surface->pixels == NULL ) {
SDL_FreeSurface(surface);
SDL_OutOfMemory();
return(NULL);
}
/* This is important for bitmaps */
memset(surface->pixels, 0, surface->h*surface->pitch);
}
}
/* Allocate an empty mapping */
surface->map = SDL_AllocBlitMap();
if ( surface->map == NULL ) {
SDL_FreeSurface(surface);
return(NULL);
}
/* The surface is ready to go */
surface->refcount = 1;
#ifdef CHECK_LEAKS
++surfaces_allocated;
#endif
return(surface);
}
/*
* Create an RGB surface from an existing memory buffer
*/
SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
int width, int height, int depth, int pitch,
Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
SDL_Surface *surface;
surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
Rmask, Gmask, Bmask, Amask);
if ( surface != NULL ) {
surface->flags |= SDL_PREALLOC;
surface->pixels = pixels;
surface->w = width;
surface->h = height;
surface->pitch = pitch;
SDL_SetClipRect(surface, NULL);
}
return(surface);
}
/*
* Set the color key in a blittable surface
*/
int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
{
/* Sanity check the flag as it gets passed in */
if ( flag & SDL_SRCCOLORKEY ) {
if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
} else {
flag = SDL_SRCCOLORKEY;
}
} else {
flag = 0;
}
/* Optimize away operations that don't change anything */
if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) &&
(key == surface->format->colorkey) ) {
return(0);
}
/* UnRLE surfaces before we change the colorkey */
if ( surface->flags & SDL_RLEACCEL ) {
SDL_UnRLESurface(surface, 1);
}
if ( flag ) {
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
surface->flags |= SDL_SRCCOLORKEY;
surface->format->colorkey = key;
if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
if ( (video->SetHWColorKey == NULL) ||
(video->SetHWColorKey(this, surface, key) < 0) ) {
surface->flags &= ~SDL_HWACCEL;
}
}
if ( flag & SDL_RLEACCELOK ) {
surface->flags |= SDL_RLEACCELOK;
} else {
surface->flags &= ~SDL_RLEACCELOK;
}
} else {
surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
surface->format->colorkey = 0;
}
SDL_InvalidateMap(surface->map);
return(0);
}
int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
{
Uint32 oldflags = surface->flags;
Uint32 oldalpha = surface->format->alpha;
/* Sanity check the flag as it gets passed in */
if ( flag & SDL_SRCALPHA ) {
if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
} else {
flag = SDL_SRCALPHA;
}
} else {
flag = 0;
}
/* Optimize away operations that don't change anything */
if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) &&
(!flag || value == oldalpha) ) {
return(0);
}
if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
SDL_UnRLESurface(surface, 1);
if ( flag ) {
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
surface->flags |= SDL_SRCALPHA;
surface->format->alpha = value;
if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
if ( (video->SetHWAlpha == NULL) ||
(video->SetHWAlpha(this, surface, value) < 0) ) {
surface->flags &= ~SDL_HWACCEL;
}
}
if ( flag & SDL_RLEACCELOK ) {
surface->flags |= SDL_RLEACCELOK;
} else {
surface->flags &= ~SDL_RLEACCELOK;
}
} else {
surface->flags &= ~SDL_SRCALPHA;
surface->format->alpha = SDL_ALPHA_OPAQUE;
}
/*
* The representation for software surfaces is independent of
* per-surface alpha, so no need to invalidate the blit mapping
* if just the alpha value was changed. (If either is 255, we still
* need to invalidate.)
*/
if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL
|| oldflags != surface->flags
|| (((oldalpha + 1) ^ (value + 1)) & 0x100))
SDL_InvalidateMap(surface->map);
return(0);
}
/*
* A function to calculate the intersection of two rectangles:
* return true if the rectangles intersect, false otherwise
*/
static __inline__
SDL_bool SDL_IntersectRect(const SDL_Rect *A, const SDL_Rect *B, SDL_Rect *intersection)
{
int Amin, Amax, Bmin, Bmax;
/* Horizontal intersection */
Amin = A->x;
Amax = Amin + A->w;
Bmin = B->x;
Bmax = Bmin + B->w;
if(Bmin > Amin)
Amin = Bmin;
intersection->x = Amin;
if(Bmax < Amax)
Amax = Bmax;
intersection->w = Amax - Amin > 0 ? Amax - Amin : 0;
/* Vertical intersection */
Amin = A->y;
Amax = Amin + A->h;
Bmin = B->y;
Bmax = Bmin + B->h;
if(Bmin > Amin)
Amin = Bmin;
intersection->y = Amin;
if(Bmax < Amax)
Amax = Bmax;
intersection->h = Amax - Amin > 0 ? Amax - Amin : 0;
return (intersection->w && intersection->h);
}
/*
* Set the clipping rectangle for a blittable surface
*/
SDL_bool SDL_SetClipRect(SDL_Surface *surface, const SDL_Rect *rect)
{
SDL_Rect full_rect;
/* Don't do anything if there's no surface to act on */
if ( ! surface ) {
return SDL_FALSE;
}
/* Set up the full surface rectangle */
full_rect.x = 0;
full_rect.y = 0;
full_rect.w = surface->w;
full_rect.h = surface->h;
/* Set the clipping rectangle */
if ( ! rect ) {
surface->clip_rect = full_rect;
return 1;
}
return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
}
void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
{
if ( surface && rect ) {
*rect = surface->clip_rect;
}
}
/*
* Set up a blit between two surfaces -- split into three parts:
* The upper part, SDL_UpperBlit(), performs clipping and rectangle
* verification. The lower part is a pointer to a low level
* accelerated blitting function.
*
* These parts are separated out and each used internally by this
* library in the optimimum places. They are exported so that if
* you know exactly what you are doing, you can optimize your code
* by calling the one(s) you need.
*/
int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_blit do_blit;
/* Check to make sure the blit mapping is valid */
if ( (src->map->dst != dst) ||
(src->map->dst->format_version != src->map->format_version) ) {
if ( SDL_MapSurface(src, dst) < 0 ) {
return(-1);
}
}
/* Figure out which blitter to use */
if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
do_blit = src->map->hw_blit;
} else {
do_blit = src->map->sw_blit;
}
return(do_blit(src, srcrect, dst, dstrect));
}
int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect)
{
SDL_Rect fulldst;
int srcx, srcy, w, h;
/* Make sure the surfaces aren't locked */
if ( ! src || ! dst ) {
SDL_SetError("SDL_UpperBlit: passed a NULL surface");
return(-1);
}
if ( src->locked || dst->locked ) {
SDL_SetError("Surfaces must not be locked during blit");
return(-1);
}
/* If the destination rectangle is NULL, use the entire dest surface */
if ( dstrect == NULL ) {
fulldst.x = fulldst.y = 0;
dstrect = &fulldst;
}
/* clip the source rectangle to the source surface */
if(srcrect) {
int maxw, maxh;
srcx = srcrect->x;
w = srcrect->w;
if(srcx < 0) {
w += srcx;
dstrect->x -= srcx;
srcx = 0;
}
maxw = src->w - srcx;
if(maxw < w)
w = maxw;
srcy = srcrect->y;
h = srcrect->h;
if(srcy < 0) {
h += srcy;
dstrect->y -= srcy;
srcy = 0;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -