123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379 |
- /*
- * SDL Graphics Extension
- * Pixel, surface and color functions
- *
- * Started 990815 (split from sge_draw 010611)
- *
- * License: LGPL v2+ (see the file LICENSE)
- * (c)1999-2003 Anders Lindström
- */
- /* MODIFIED: _PutPixelAlpha 02/27/2004 Janson
- * All changes are for 32bpp surfaces only (only ones we use right now)
- * 1) 32bit uses long long to prevent clipping of alpha
- * 2) alpha blend for RGB is scaled towards alpha of pixel, so that
- * the resulting pixel doesn't "double up" on alpha due to
- * both the color being shaded AND alpha being present
- * 3) drawing on fully transparent surface just blends alpha, but
- * doesn't have to scale it then (this is just an optimization)
- *
- * These modifications make all AA and alpha-blended functions graphic-program quality.
- *
- * MODIFIED: Prefix ++/-- instead of postfix (consistent with my other code)
- * Removed all 8/24 bit code
- *
- * REMOVED: _sge_update and all related functions
- * sge_CreateAlphaSurface
- * all palette, copy, block, fill functions
- */
- /*********************************************************************
- * 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. *
- *********************************************************************/
- /*
- * Some of this code is taken from the "Introduction to SDL" and
- * John Garrison's PowerPak
- */
- // (MODIFIED Janson - using std header)
- #include "all.h"
- /* Globals used for sge_Lock */
- Uint8 _sge_lock=1;
- /**********************************************************************************/
- /** Misc. functions **/
- /**********************************************************************************/
- //==================================================================================
- // Turns off automatic locking of surfaces
- //==================================================================================
- void sge_Lock_OFF(void)
- {
- _sge_lock=0;
- }
- //==================================================================================
- // Turns on automatic locking (default)
- //==================================================================================
- void sge_Lock_ON(void)
- {
- _sge_lock=1;
- }
- //==================================================================================
- // Returns locking mode (1-on and 0-off)
- //==================================================================================
- Uint8 sge_getLock(void)
- {
- return _sge_lock;
- }
- //==================================================================================
- // Returns the Uint32 color value for a 32bit (8/8/8/8) alpha surface
- //==================================================================================
- Uint32 sge_MapAlpha(Uint8 R, Uint8 G, Uint8 B, Uint8 A)
- {
- Uint32 color=0;
-
- color|=R<<24;
- color|=G<<16;
- color|=B<<8;
- color|=A;
-
- return color;
- }
- //==================================================================================
- // Sets an SDL error string
- // Accepts formated argument - like printf()
- // SDL_SetError() also does this, but it does not use standard syntax (why?)
- //==================================================================================
- void sge_SetError(const char *format, ...)
- {
- char buf[256];
- va_list ap;
-
- #ifdef __WIN32__
- va_start(ap, format); //Stupid w32 crosscompiler
- #else
- va_start(ap, format);
- #endif
-
- vsprintf(buf, format, ap);
- va_end(ap);
- SDL_SetError(buf);
- }
- /**********************************************************************************/
- /** Pixel functions **/
- /**********************************************************************************/
- //==================================================================================
- // Fast put pixel
- //==================================================================================
- void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
- {
- if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && y>=sge_clip_ymin(surface) && y<=sge_clip_ymax(surface)){
- switch (surface->format->BytesPerPixel) {
- case 2: { /* Probably 15-bpp or 16-bpp */
- *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
- }
- break;
- case 4: { /* Probably 32-bpp */
- *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
- }
- break;
- }
- }
- }
- //==================================================================================
- // Fast put pixel (RGB)
- //==================================================================================
- void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B)
- {
- _PutPixel(surface,x,y, SDL_MapRGB(surface->format, R, G, B));
- }
- //==================================================================================
- // Fastest put pixel functions (don't mess up indata, thank you)
- //==================================================================================
- void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
- {
- *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
- }
- void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
- {
- *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
- }
- void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
- {
- switch ( dest->format->BytesPerPixel ) {
- case 2:
- *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
- break;
- case 4:
- *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
- break;
- }
- }
- //==================================================================================
- // Safe put pixel
- //==================================================================================
- void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
- {
- if ( SDL_MUSTLOCK(surface) && _sge_lock ) {
- if ( SDL_LockSurface(surface) < 0 ) {
- return;
- }
- }
- _PutPixel(surface, x, y, color);
- if ( SDL_MUSTLOCK(surface) && _sge_lock ) {
- SDL_UnlockSurface(surface);
- }
- }
- //==================================================================================
- // Safe put pixel (RGB)
- //==================================================================================
- void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B)
- {
- sge_PutPixel(surface,x,y, SDL_MapRGB(surface->format, R, G, B));
- }
- //==================================================================================
- // Calculate y pitch offset
- // (the y pitch offset is constant for the same y coord and surface)
- //==================================================================================
- Sint32 sge_CalcYPitch(SDL_Surface *dest,Sint16 y)
- {
- if(y>=sge_clip_ymin(dest) && y<=sge_clip_ymax(dest)){
- switch ( dest->format->BytesPerPixel ) {
- case 2:
- return y*dest->pitch/2;
- break;
- case 4:
- return y*dest->pitch/4;
- break;
- }
- }
-
- return -1;
- }
- //==================================================================================
- // Put pixel with precalculated y pitch offset
- //==================================================================================
- void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
- {
- if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && ypitch>=0){
- switch (surface->format->BytesPerPixel) {
- case 2: { /* Probably 15-bpp or 16-bpp */
- *((Uint16 *)surface->pixels + ypitch + x) = color;
- }
- break;
- case 4: { /* Probably 32-bpp */
- *((Uint32 *)surface->pixels + ypitch + x) = color;
- }
- break;
- }
- }
- }
- //==================================================================================
- // Get pixel
- //==================================================================================
- Uint32 sge_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y)
- {
- if(x<0 || x>=surface->w || y<0 || y>=surface->h)
- return 0;
- switch (surface->format->BytesPerPixel) {
- case 2: { /* Probably 15-bpp or 16-bpp */
- return *((Uint16 *)surface->pixels + y*surface->pitch/2 + x);
- }
- break;
- case 4: { /* Probably 32-bpp */
- return *((Uint32 *)surface->pixels + y*surface->pitch/4 + x);
- }
- break;
- }
- return 0;
- }
- //==================================================================================
- // Put pixel with alpha blending
- //==================================================================================
- void _PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
- {
- if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && y>=sge_clip_ymin(surface) && y<=sge_clip_ymax(surface)){
- Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
- Uint32 R,G,B,A=0;
- switch (surface->format->BytesPerPixel) {
- case 2: { /* Probably 15-bpp or 16-bpp */
- if( alpha == 255 ){
- *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
- }else{
- Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
- Uint32 dc = *pixel;
-
- R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask;
- G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask;
- B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask;
- if( Amask )
- A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask;
- *pixel= R | G | B | A;
- }
- }
- break;
- case 4: { /* Probably 32-bpp */
- Uint32 *pixel = (Uint32 *)surface->pixels + y*surface->pitch/4 + x;
- // Special case 100% blend and 0% destination
- if( alpha == 255 ){
- *pixel = color;
- }else if ((Amask) && ((*pixel & Amask) == 0)) {
- // Destination is 100% transparent, so place our pixel normal with alpha scaled
- A = ((long long)(color & Amask) * alpha >> 8) & Amask;
- *pixel = (color & (Rmask | Gmask | Bmask)) | A;
- }else{
- Uint32 dc = *pixel;
-
- // Scale RGB blend based on alpha of destination
- int destAlpha = (dc & Amask) >> surface->format->Ashift;
- int rgbScale = alpha;
- if (destAlpha < alpha) rgbScale = alpha + (256 - alpha) * (alpha - destAlpha) / 255;
-
- // We have to ensure no unwanted clipping occurs, of both overflow and negatives
- // Our main() asserts that long long is at least 48 bits
- R = ((dc & Rmask) + (((long long)(color & Rmask) - (long long)(dc & Rmask) ) * rgbScale >> 8)) & Rmask;
- G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * rgbScale >> 8)) & Gmask;
- B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * rgbScale >> 8)) & Bmask;
- if (Amask)
- A = ((dc & Amask) + (((long long)(color & Amask) - (long long)(dc & Amask) ) * alpha >> 8)) & Amask;
- *pixel = R | G | B | A;
- }
- }
- break;
- }
- }
- }
- void sge_PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
- {
- if ( SDL_MUSTLOCK(surface) && _sge_lock )
- if ( SDL_LockSurface(surface) < 0 )
- return;
- _PutPixelAlpha(surface,x,y,color,alpha);
-
- /* unlock the display */
- if (SDL_MUSTLOCK(surface) && _sge_lock) {
- SDL_UnlockSurface(surface);
- }
- }
- void _PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
- {
- _PutPixelAlpha(surface,x,y, SDL_MapRGB(surface->format, R, G, B),alpha);
- }
- void sge_PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
- {
- sge_PutPixelAlpha(surface,x,y, SDL_MapRGB(surface->format, R, G, B), alpha);
- }
- /**********************************************************************************/
- /** Blitting/surface functions **/
- /**********************************************************************************/
- //==================================================================================
- // Clear surface to color
- //==================================================================================
- void sge_ClearSurface(SDL_Surface *Surface, Uint32 color)
- {
- SDL_FillRect(Surface, (SDL_Rect*)NULL, color);
- }
- //==================================================================================
- // Clear surface to color (RGB)
- //==================================================================================
- void sge_ClearSurface(SDL_Surface *Surface, Uint8 R, Uint8 G, Uint8 B)
- {
- sge_ClearSurface(Surface,SDL_MapRGB(Surface->format, R, G, B));
- }
|