Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /*
  2.     SDL - Simple DirectMedia Layer
  3.     Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
  4.  
  5.     This library is free software; you can redistribute it and/or
  6.     modify it under the terms of the GNU Library General Public
  7.     License as published by the Free Software Foundation; either
  8.     version 2 of the License, or (at your option) any later version.
  9.  
  10.     This library is distributed in the hope that it will be useful,
  11.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  13.     Library General Public License for more details.
  14.  
  15.     You should have received a copy of the GNU Library General Public
  16.     License along with this library; if not, write to the Free
  17.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18.  
  19.     Sam Lantinga
  20.     slouken@devolution.com
  21. */
  22.  
  23.  
  24. #include <stdio.h>
  25. #include <stdlib.h>
  26. #include <string.h>
  27.  
  28. #include "SDL_error.h"
  29. #include "SDL_video.h"
  30. #include "SDL_sysvideo.h"
  31. #include "SDL_cursor_c.h"
  32. #include "SDL_blit.h"
  33. #include "SDL_RLEaccel_c.h"
  34. #include "SDL_pixels_c.h"
  35. #include "SDL_memops.h"
  36. #include "SDL_leaks.h"
  37.  
  38. /* Public routines */
  39. /*
  40.  * Create an empty RGB surface of the appropriate depth
  41.  */
  42. SDL_Surface * SDL_CreateRGBSurface (Uint32 flags,
  43.                         int width, int height, int depth,
  44.                         Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  45. {
  46.         SDL_VideoDevice *video = current_video;
  47.         SDL_VideoDevice *this  = current_video;
  48.         SDL_Surface *screen;
  49.         SDL_Surface *surface;
  50.  
  51.         /* Check to see if we desire the surface in video memory */
  52.         if ( video ) {
  53.                 screen = SDL_PublicSurface;
  54.         } else {
  55.                 screen = NULL;
  56.         }
  57.         if ( screen && ((screen->flags&SDL_HWSURFACE) == SDL_HWSURFACE) ) {
  58.                 if ( (flags&(SDL_SRCCOLORKEY|SDL_SRCALPHA)) != 0 ) {
  59.                         flags |= SDL_HWSURFACE;
  60.                 }
  61.                 if ( (flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  62.                         if ( ! current_video->info.blit_hw_CC ) {
  63.                                 flags &= ~SDL_HWSURFACE;
  64.                         }
  65.                 }
  66.                 if ( (flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  67.                         if ( ! current_video->info.blit_hw_A ) {
  68.                                 flags &= ~SDL_HWSURFACE;
  69.                         }
  70.                 }
  71.         } else {
  72.                 flags &= ~SDL_HWSURFACE;
  73.         }
  74.  
  75.         /* Allocate the surface */
  76.         surface = (SDL_Surface *)malloc(sizeof(*surface));
  77.         if ( surface == NULL ) {
  78.                 SDL_OutOfMemory();
  79.                 return(NULL);
  80.         }
  81.         surface->flags = SDL_SWSURFACE;
  82.         if ( (flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  83.                 depth = screen->format->BitsPerPixel;
  84.                 Rmask = screen->format->Rmask;
  85.                 Gmask = screen->format->Gmask;
  86.                 Bmask = screen->format->Bmask;
  87.                 Amask = screen->format->Amask;
  88.         }
  89.         surface->format = SDL_AllocFormat(depth, Rmask, Gmask, Bmask, Amask);
  90.         if ( surface->format == NULL ) {
  91.                 free(surface);
  92.                 return(NULL);
  93.         }
  94.         if ( Amask ) {
  95.                 surface->flags |= SDL_SRCALPHA;
  96.         }
  97.         surface->w = width;
  98.         surface->h = height;
  99.         surface->pitch = SDL_CalculatePitch(surface);
  100.         surface->pixels = NULL;
  101.         surface->offset = 0;
  102.         surface->hwdata = NULL;
  103.         surface->locked = 0;
  104.         surface->map = NULL;
  105.         surface->format_version = 0;
  106.         SDL_SetClipRect(surface, NULL);
  107.  
  108.         /* Get the pixels */
  109.         if ( ((flags&SDL_HWSURFACE) == SDL_SWSURFACE) ||
  110.                                 (video->AllocHWSurface(this, surface) < 0) ) {
  111.                 if ( surface->w && surface->h ) {
  112.                         surface->pixels = malloc(surface->h*surface->pitch);
  113.                         if ( surface->pixels == NULL ) {
  114.                                 SDL_FreeSurface(surface);
  115.                                 SDL_OutOfMemory();
  116.                                 return(NULL);
  117.                         }
  118.                         /* This is important for bitmaps */
  119.                         memset(surface->pixels, 0, surface->h*surface->pitch);
  120.                 }
  121.         }
  122.  
  123.         /* Allocate an empty mapping */
  124.         surface->map = SDL_AllocBlitMap();
  125.         if ( surface->map == NULL ) {
  126.                 SDL_FreeSurface(surface);
  127.                 return(NULL);
  128.         }
  129.  
  130.         /* The surface is ready to go */
  131.         surface->refcount = 1;
  132. #ifdef CHECK_LEAKS
  133.         ++surfaces_allocated;
  134. #endif
  135.         return(surface);
  136. }
  137. /*
  138.  * Create an RGB surface from an existing memory buffer
  139.  */
  140. SDL_Surface * SDL_CreateRGBSurfaceFrom (void *pixels,
  141.                         int width, int height, int depth, int pitch,
  142.                         Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
  143. {
  144.         SDL_Surface *surface;
  145.  
  146.         surface = SDL_CreateRGBSurface(SDL_SWSURFACE, 0, 0, depth,
  147.                                        Rmask, Gmask, Bmask, Amask);
  148.         if ( surface != NULL ) {
  149.                 surface->flags |= SDL_PREALLOC;
  150.                 surface->pixels = pixels;
  151.                 surface->w = width;
  152.                 surface->h = height;
  153.                 surface->pitch = pitch;
  154.                 SDL_SetClipRect(surface, NULL);
  155.         }
  156.         return(surface);
  157. }
  158. /*
  159.  * Set the color key in a blittable surface
  160.  */
  161. int SDL_SetColorKey (SDL_Surface *surface, Uint32 flag, Uint32 key)
  162. {
  163.         /* Sanity check the flag as it gets passed in */
  164.         if ( flag & SDL_SRCCOLORKEY ) {
  165.                 if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
  166.                         flag = (SDL_SRCCOLORKEY | SDL_RLEACCELOK);
  167.                 } else {
  168.                         flag = SDL_SRCCOLORKEY;
  169.                 }
  170.         } else {
  171.                 flag = 0;
  172.         }
  173.  
  174.         /* Optimize away operations that don't change anything */
  175.         if ( (flag == (surface->flags & (SDL_SRCCOLORKEY|SDL_RLEACCELOK))) &&
  176.              (key == surface->format->colorkey) ) {
  177.                 return(0);
  178.         }
  179.  
  180.         /* UnRLE surfaces before we change the colorkey */
  181.         if ( surface->flags & SDL_RLEACCEL ) {
  182.                 SDL_UnRLESurface(surface, 1);
  183.         }
  184.  
  185.         if ( flag ) {
  186.                 SDL_VideoDevice *video = current_video;
  187.                 SDL_VideoDevice *this  = current_video;
  188.  
  189.  
  190.                 surface->flags |= SDL_SRCCOLORKEY;
  191.                 surface->format->colorkey = key;
  192.                 if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  193.                         if ( (video->SetHWColorKey == NULL) ||
  194.                              (video->SetHWColorKey(this, surface, key) < 0) ) {
  195.                                 surface->flags &= ~SDL_HWACCEL;
  196.                         }
  197.                 }
  198.                 if ( flag & SDL_RLEACCELOK ) {
  199.                         surface->flags |= SDL_RLEACCELOK;
  200.                 } else {
  201.                         surface->flags &= ~SDL_RLEACCELOK;
  202.                 }
  203.         } else {
  204.                 surface->flags &= ~(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
  205.                 surface->format->colorkey = 0;
  206.         }
  207.         SDL_InvalidateMap(surface->map);
  208.         return(0);
  209. }
  210. int SDL_SetAlpha (SDL_Surface *surface, Uint32 flag, Uint8 value)
  211. {
  212.         Uint32 oldflags = surface->flags;
  213.         Uint32 oldalpha = surface->format->alpha;
  214.  
  215.         /* Sanity check the flag as it gets passed in */
  216.         if ( flag & SDL_SRCALPHA ) {
  217.                 if ( flag & (SDL_RLEACCEL|SDL_RLEACCELOK) ) {
  218.                         flag = (SDL_SRCALPHA | SDL_RLEACCELOK);
  219.                 } else {
  220.                         flag = SDL_SRCALPHA;
  221.                 }
  222.         } else {
  223.                 flag = 0;
  224.         }
  225.  
  226.         /* Optimize away operations that don't change anything */
  227.         if ( (flag == (surface->flags & (SDL_SRCALPHA|SDL_RLEACCELOK))) &&
  228.              (!flag || value == oldalpha) ) {
  229.                 return(0);
  230.         }
  231.  
  232.         if(!(flag & SDL_RLEACCELOK) && (surface->flags & SDL_RLEACCEL))
  233.                 SDL_UnRLESurface(surface, 1);
  234.  
  235.         if ( flag ) {
  236.                 SDL_VideoDevice *video = current_video;
  237.                 SDL_VideoDevice *this  = current_video;
  238.  
  239.                 surface->flags |= SDL_SRCALPHA;
  240.                 surface->format->alpha = value;
  241.                 if ( (surface->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  242.                         if ( (video->SetHWAlpha == NULL) ||
  243.                              (video->SetHWAlpha(this, surface, value) < 0) ) {
  244.                                 surface->flags &= ~SDL_HWACCEL;
  245.                         }
  246.                 }
  247.                 if ( flag & SDL_RLEACCELOK ) {
  248.                         surface->flags |= SDL_RLEACCELOK;
  249.                 } else {
  250.                         surface->flags &= ~SDL_RLEACCELOK;
  251.                 }
  252.         } else {
  253.                 surface->flags &= ~SDL_SRCALPHA;
  254.                 surface->format->alpha = SDL_ALPHA_OPAQUE;
  255.         }
  256.         /*
  257.          * The representation for software surfaces is independent of
  258.          * per-surface alpha, so no need to invalidate the blit mapping
  259.          * if just the alpha value was changed. (If either is 255, we still
  260.          * need to invalidate.)
  261.          */
  262.         if((surface->flags & SDL_HWACCEL) == SDL_HWACCEL
  263.            || oldflags != surface->flags
  264.            || (((oldalpha + 1) ^ (value + 1)) & 0x100))
  265.                 SDL_InvalidateMap(surface->map);
  266.         return(0);
  267. }
  268.  
  269. /*
  270.  * A function to calculate the intersection of two rectangles:
  271.  * return true if the rectangles intersect, false otherwise
  272.  */
  273. static __inline__
  274. SDL_bool SDL_IntersectRect(SDL_Rect *A, SDL_Rect *B, SDL_Rect *intersection)
  275. {
  276.         int Amin, Amax, Bmin, Bmax;
  277.  
  278.         /* Horizontal intersection */
  279.         Amin = A->x;
  280.         Amax = Amin + A->w;
  281.         Bmin = B->x;
  282.         Bmax = Bmin + B->w;
  283.         if(Bmin > Amin)
  284.                 Amin = Bmin;
  285.         intersection->x = Amin;
  286.         if(Bmax < Amax)
  287.                 Amax = Bmax;
  288.         intersection->w = Amax - Amin > 0 ? Amax - Amin : 0;
  289.  
  290.         /* Vertical intersection */
  291.         Amin = A->y;
  292.         Amax = Amin + A->h;
  293.         Bmin = B->y;
  294.         Bmax = Bmin + B->h;
  295.         if(Bmin > Amin)
  296.                 Amin = Bmin;
  297.         intersection->y = Amin;
  298.         if(Bmax < Amax)
  299.                 Amax = Bmax;
  300.         intersection->h = Amax - Amin > 0 ? Amax - Amin : 0;
  301.  
  302.         return (intersection->w && intersection->h);
  303. }
  304. /*
  305.  * Set the clipping rectangle for a blittable surface
  306.  */
  307. SDL_bool SDL_SetClipRect(SDL_Surface *surface, SDL_Rect *rect)
  308. {
  309.         SDL_Rect full_rect;
  310.  
  311.         /* Don't do anything if there's no surface to act on */
  312.         if ( ! surface ) {
  313.                 return SDL_FALSE;
  314.         }
  315.  
  316.         /* Set up the full surface rectangle */
  317.         full_rect.x = 0;
  318.         full_rect.y = 0;
  319.         full_rect.w = surface->w;
  320.         full_rect.h = surface->h;
  321.  
  322.         /* Set the clipping rectangle */
  323.         if ( ! rect ) {
  324.                 surface->clip_rect = full_rect;
  325.                 return 1;
  326.         }
  327.         return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
  328. }
  329. void SDL_GetClipRect(SDL_Surface *surface, SDL_Rect *rect)
  330. {
  331.         if ( surface && rect ) {
  332.                 *rect = surface->clip_rect;
  333.         }
  334. }
  335. /*
  336.  * Set up a blit between two surfaces -- split into three parts:
  337.  * The upper part, SDL_UpperBlit(), performs clipping and rectangle
  338.  * verification.  The lower part is a pointer to a low level
  339.  * accelerated blitting function.
  340.  *
  341.  * These parts are separated out and each used internally by this
  342.  * library in the optimimum places.  They are exported so that if
  343.  * you know exactly what you are doing, you can optimize your code
  344.  * by calling the one(s) you need.
  345.  */
  346. int SDL_LowerBlit (SDL_Surface *src, SDL_Rect *srcrect,
  347.                                 SDL_Surface *dst, SDL_Rect *dstrect)
  348. {
  349.         SDL_blit do_blit;
  350.  
  351.         /* Check to make sure the blit mapping is valid */
  352.         if ( (src->map->dst != dst) ||
  353.              (src->map->dst->format_version != src->map->format_version) ) {
  354.                 if ( SDL_MapSurface(src, dst) < 0 ) {
  355.                         return(-1);
  356.                 }
  357.         }
  358.  
  359.         /* Figure out which blitter to use */
  360.         if ( (src->flags & SDL_HWACCEL) == SDL_HWACCEL ) {
  361.                 do_blit = src->map->hw_blit;
  362.         } else {
  363.                 do_blit = src->map->sw_blit;
  364.         }
  365.         return(do_blit(src, srcrect, dst, dstrect));
  366. }
  367.  
  368.  
  369. int SDL_UpperBlit (SDL_Surface *src, SDL_Rect *srcrect,
  370.                    SDL_Surface *dst, SDL_Rect *dstrect)
  371. {
  372.         SDL_Rect fulldst;
  373.         int srcx, srcy, w, h;
  374.  
  375.         /* Make sure the surfaces aren't locked */
  376.         if ( ! src || ! dst ) {
  377.                 SDL_SetError("SDL_UpperBlit: passed a NULL surface");
  378.                 return(-1);
  379.         }
  380.         if ( src->locked || dst->locked ) {
  381.                 SDL_SetError("Surfaces must not be locked during blit");
  382.                 return(-1);
  383.         }
  384.  
  385.         /* If the destination rectangle is NULL, use the entire dest surface */
  386.         if ( dstrect == NULL ) {
  387.                 fulldst.x = fulldst.y = 0;
  388.                 dstrect = &fulldst;
  389.         }
  390.  
  391.         /* clip the source rectangle to the source surface */
  392.         if(srcrect) {
  393.                 int maxw, maxh;
  394.        
  395.                 srcx = srcrect->x;
  396.                 w = srcrect->w;
  397.                 if(srcx < 0) {
  398.                         w += srcx;
  399.                         dstrect->x -= srcx;
  400.                         srcx = 0;
  401.                 }
  402.                 maxw = src->w - srcx;
  403.                 if(maxw < w)
  404.                         w = maxw;
  405.  
  406.                 srcy = srcrect->y;
  407.                 h = srcrect->h;
  408.                 if(srcy < 0) {
  409.                         h += srcy;
  410.                         dstrect->y -= srcy;
  411.                         srcy = 0;
  412.                 }
  413.                 maxh = src->h - srcy;
  414.                 if(maxh < h)
  415.                         h = maxh;
  416.            
  417.         } else {
  418.                 srcx = srcy = 0;
  419.                 w = src->w;
  420.                 h = src->h;
  421.         }
  422.  
  423.         /* clip the destination rectangle against the clip rectangle */
  424.         {
  425.                 SDL_Rect *clip = &dst->clip_rect;
  426.                 int dx, dy;
  427.  
  428.                 dx = clip->x - dstrect->x;
  429.                 if(dx > 0) {
  430.                         w -= dx;
  431.                         dstrect->x += dx;
  432.                         srcx += dx;
  433.                 }
  434.                 dx = dstrect->x + w - clip->x - clip->w;
  435.                 if(dx > 0)
  436.                         w -= dx;
  437.  
  438.                 dy = clip->y - dstrect->y;
  439.                 if(dy > 0) {
  440.                         h -= dy;
  441.                         dstrect->y += dy;
  442.                         srcy += dy;
  443.                 }
  444.                 dy = dstrect->y + h - clip->y - clip->h;
  445.                 if(dy > 0)
  446.                         h -= dy;
  447.         }
  448.  
  449.         if(w > 0 && h > 0) {
  450.                 SDL_Rect sr;
  451.                 sr.x = srcx;
  452.                 sr.y = srcy;
  453.                 sr.w = dstrect->w = w;
  454.                 sr.h = dstrect->h = h;
  455.                 return SDL_LowerBlit(src, &sr, dst, dstrect);
  456.         }
  457.         dstrect->w = dstrect->h = 0;
  458.         return 0;
  459. }
  460.  
  461. /*
  462.  * This function performs a fast fill of the given rectangle with 'color'
  463.  */
  464. int SDL_FillRect(SDL_Surface *dst, SDL_Rect *dstrect, Uint32 color)
  465. {
  466.         SDL_VideoDevice *video = current_video;
  467.         SDL_VideoDevice *this  = current_video;
  468.         int x, y;
  469.         Uint8 *row;
  470.  
  471.         /* If 'dstrect' == NULL, then fill the whole surface */
  472.         if ( dstrect ) {
  473.                 /* Perform clipping */
  474.                 if ( !SDL_IntersectRect(dstrect, &dst->clip_rect, dstrect) ) {
  475.                         return(0);
  476.                 }
  477.         } else {
  478.                 dstrect = &dst->clip_rect;
  479.         }
  480.  
  481.         /* Check for hardware acceleration */
  482.         if ( ((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) &&
  483.                                         video->info.blit_fill ) {
  484.                 return(video->FillHWRect(this, dst, dstrect, color));
  485.         }
  486.  
  487.         /* Perform software fill */
  488.         if ( SDL_LockSurface(dst) != 0 ) {
  489.                 return(-1);
  490.         }
  491.         row = (Uint8 *)dst->pixels+dstrect->y*dst->pitch+
  492.                         dstrect->x*dst->format->BytesPerPixel;
  493.         if ( dst->format->palette || (color == 0) ) {
  494.                 x = dstrect->w*dst->format->BytesPerPixel;
  495.                 if ( !color && !((long)row&3) && !(x&3) && !(dst->pitch&3) ) {
  496.                         int n = x >> 2;
  497.                         for ( y=dstrect->h; y; --y ) {
  498.                                 SDL_memset4(row, 0, n);
  499.                                 row += dst->pitch;
  500.                         }
  501.                 } else {
  502. #ifdef __powerpc__
  503.                         /*
  504.                          * memset() on PPC (both glibc and codewarrior) uses
  505.                          * the dcbz (Data Cache Block Zero) instruction, which
  506.                          * causes an alignment exception if the destination is
  507.                          * uncachable, so only use it on software surfaces
  508.                          */
  509.                         if((dst->flags & SDL_HWSURFACE) == SDL_HWSURFACE) {
  510.                                 if(dstrect->w >= 8) {
  511.                                         /*
  512.                                          * 64-bit stores are probably most
  513.                                          * efficient to uncached video memory
  514.                                          */
  515.                                         double fill;
  516.                                         memset(&fill, color, (sizeof fill));
  517.                                         for(y = dstrect->h; y; y--) {
  518.                                                 Uint8 *d = row;
  519.                                                 unsigned n = x;
  520.                                                 unsigned nn;
  521.                                                 Uint8 c = color;
  522.                                                 double f = fill;
  523.                                                 while((unsigned long)d
  524.                                                       & (sizeof(double) - 1)) {
  525.                                                         *d++ = c;
  526.                                                         n--;
  527.                                                 }
  528.                                                 nn = n / (sizeof(double) * 4);
  529.                                                 while(nn) {
  530.                                                         ((double *)d)[0] = f;
  531.                                                         ((double *)d)[1] = f;
  532.                                                         ((double *)d)[2] = f;
  533.                                                         ((double *)d)[3] = f;
  534.                                                         d += 4*sizeof(double);
  535.                                                         nn--;
  536.                                                 }
  537.                                                 n &= ~(sizeof(double) * 4 - 1);
  538.                                                 nn = n / sizeof(double);
  539.                                                 while(nn) {
  540.                                                         *(double *)d = f;
  541.                                                         d += sizeof(double);
  542.                                                         nn--;
  543.                                                 }
  544.                                                 n &= ~(sizeof(double) - 1);
  545.                                                 while(n) {
  546.                                                         *d++ = c;
  547.                                                         n--;
  548.                                                 }
  549.                                                 row += dst->pitch;
  550.                                         }
  551.                                 } else {
  552.                                         /* narrow boxes */
  553.                                         for(y = dstrect->h; y; y--) {
  554.                                                 Uint8 *d = row;
  555.                                                 Uint8 c = color;
  556.                                                 int n = x;
  557.                                                 while(n) {
  558.                                                         *d++ = c;
  559.                                                         n--;
  560.                                                 }
  561.                                                 row += dst->pitch;
  562.                                         }
  563.                                 }
  564.                         } else
  565. #endif /* __powerpc__ */
  566.                         {
  567.                                 for(y = dstrect->h; y; y--) {
  568.                                         memset(row, color, x);
  569.                                         row += dst->pitch;
  570.                                 }
  571.                         }
  572.                 }
  573.         } else {
  574.                 switch (dst->format->BytesPerPixel) {
  575.                     case 2:
  576.                         for ( y=dstrect->h; y; --y ) {
  577.                                 Uint16 *pixels = (Uint16 *)row;
  578.                                 Uint16 c = color;
  579.                                 Uint32 cc = (Uint32)c << 16 | c;
  580.                                 int n = dstrect->w;
  581.                                 if((unsigned long)pixels & 3) {
  582.                                         *pixels++ = c;
  583.                                         n--;
  584.                                 }
  585.                                 if(n >> 1)
  586.                                         SDL_memset4(pixels, cc, n >> 1);
  587.                                 if(n & 1)
  588.                                         pixels[n - 1] = c;
  589.                                 row += dst->pitch;
  590.                         }
  591.                         break;
  592.  
  593.                     case 3:
  594.                         if(SDL_BYTEORDER == SDL_BIG_ENDIAN)
  595.                                 color <<= 8;
  596.                         for ( y=dstrect->h; y; --y ) {
  597.                                 Uint8 *pixels = row;
  598.                                 for ( x=dstrect->w; x; --x ) {
  599.                                         memcpy(pixels, &color, 3);
  600.                                         pixels += 3;
  601.                                 }
  602.                                 row += dst->pitch;
  603.                         }
  604.                         break;
  605.  
  606.                     case 4:
  607.                         for(y = dstrect->h; y; --y) {
  608.                                 SDL_memset4(row, color, dstrect->w);
  609.                                 row += dst->pitch;
  610.                         }
  611.                         break;
  612.                 }
  613.         }
  614.         SDL_UnlockSurface(dst);
  615.  
  616.         /* We're done! */
  617.         return(0);
  618. }
  619.  
  620. /*
  621.  * Lock a surface to directly access the pixels
  622.  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
  623.  *    Instead, use:
  624.  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
  625.  *               video->LockHWSurface(video, surface);
  626.  */
  627. int SDL_LockSurface (SDL_Surface *surface)
  628. {
  629.         if ( ! surface->locked ) {
  630.                 /* Perform the lock */
  631.                 if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  632.                         SDL_VideoDevice *video = current_video;
  633.                         SDL_VideoDevice *this  = current_video;
  634.                         if ( video->LockHWSurface(this, surface) < 0 ) {
  635.                                 return(-1);
  636.                         }
  637.                 }
  638.                 if ( surface->flags & SDL_RLEACCEL ) {
  639.                         SDL_UnRLESurface(surface, 1);
  640.                         surface->flags |= SDL_RLEACCEL; /* save accel'd state */
  641.                 }
  642.                 /* This needs to be done here in case pixels changes value */
  643.                 surface->pixels = (Uint8 *)surface->pixels + surface->offset;
  644.         }
  645.  
  646.         /* Increment the surface lock count, for recursive locks */
  647.         ++surface->locked;
  648.  
  649.         /* Ready to go.. */
  650.         return(0);
  651. }
  652. /*
  653.  * Unlock a previously locked surface
  654.  * -- Do not call this from any blit function, as SDL_DrawCursor() may recurse
  655.  *    Instead, use:
  656.  *    if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE )
  657.  *               video->UnlockHWSurface(video, surface);
  658.  */
  659. void SDL_UnlockSurface (SDL_Surface *surface)
  660. {
  661.         /* Only perform an unlock if we are locked */
  662.         if ( ! surface->locked || (--surface->locked > 0) ) {
  663.                 return;
  664.         }
  665.  
  666.         /* Perform the unlock */
  667.         surface->pixels = (Uint8 *)surface->pixels - surface->offset;
  668.  
  669.         /* Unlock hardware or accelerated surfaces */
  670.         if ( surface->flags & (SDL_HWSURFACE|SDL_ASYNCBLIT) ) {
  671.                 SDL_VideoDevice *video = current_video;
  672.                 SDL_VideoDevice *this  = current_video;
  673.                 video->UnlockHWSurface(this, surface);
  674.         } else {
  675.                 /* Update RLE encoded surface with new data */
  676.                 if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  677.                         surface->flags &= ~SDL_RLEACCEL; /* stop lying */
  678.                         SDL_RLESurface(surface);
  679.                 }
  680.         }
  681. }
  682.  
  683. /*
  684.  * Convert a surface into the specified pixel format.
  685.  */
  686. SDL_Surface * SDL_ConvertSurface (SDL_Surface *surface,
  687.                                         SDL_PixelFormat *format, Uint32 flags)
  688. {
  689.         SDL_Surface *convert;
  690.         Uint32 colorkey = 0;
  691.         Uint8 alpha = 0;
  692.         Uint32 surface_flags;
  693.         SDL_Rect bounds;
  694.  
  695.         /* Check for empty destination palette! (results in empty image) */
  696.         if ( format->palette != NULL ) {
  697.                 int i;
  698.                 for ( i=0; i<format->palette->ncolors; ++i ) {
  699.                         if ( (format->palette->colors[i].r != 0) ||
  700.                              (format->palette->colors[i].g != 0) ||
  701.                              (format->palette->colors[i].b != 0) )
  702.                                 break;
  703.                 }
  704.                 if ( i == format->palette->ncolors ) {
  705.                         SDL_SetError("Empty destination palette");
  706.                         return(NULL);
  707.                 }
  708.         }
  709.  
  710.         /* Create a new surface with the desired format */
  711.         convert = SDL_CreateRGBSurface(flags,
  712.                                 surface->w, surface->h, format->BitsPerPixel,
  713.                 format->Rmask, format->Gmask, format->Bmask, format->Amask);
  714.         if ( convert == NULL ) {
  715.                 return(NULL);
  716.         }
  717.  
  718.         /* Copy the palette if any */
  719.         if ( format->palette && convert->format->palette ) {
  720.                 memcpy(convert->format->palette->colors,
  721.                                 format->palette->colors,
  722.                                 format->palette->ncolors*sizeof(SDL_Color));
  723.                 convert->format->palette->ncolors = format->palette->ncolors;
  724.         }
  725.  
  726.         /* Save the original surface color key and alpha */
  727.         surface_flags = surface->flags;
  728.         if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  729.                 /* Convert colourkeyed surfaces to RGBA if requested */
  730.                 if((flags & SDL_SRCCOLORKEY) != SDL_SRCCOLORKEY
  731.                    && format->Amask) {
  732.                         surface_flags &= ~SDL_SRCCOLORKEY;
  733.                 } else {
  734.                         colorkey = surface->format->colorkey;
  735.                         SDL_SetColorKey(surface, 0, 0);
  736.                 }
  737.         }
  738.         if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  739.                 alpha = surface->format->alpha;
  740.                 SDL_SetAlpha(surface, 0, 0);
  741.         }
  742.  
  743.         /* Copy over the image data */
  744.         bounds.x = 0;
  745.         bounds.y = 0;
  746.         bounds.w = surface->w;
  747.         bounds.h = surface->h;
  748.         SDL_LowerBlit(surface, &bounds, convert, &bounds);
  749.  
  750.         /* Clean up the original surface, and update converted surface */
  751.         if ( convert != NULL ) {
  752.                 SDL_SetClipRect(convert, &surface->clip_rect);
  753.         }
  754.         if ( (surface_flags & SDL_SRCCOLORKEY) == SDL_SRCCOLORKEY ) {
  755.                 Uint32 cflags = surface_flags&(SDL_SRCCOLORKEY|SDL_RLEACCELOK);
  756.                 if ( convert != NULL ) {
  757.                         Uint8 keyR, keyG, keyB;
  758.  
  759.                         SDL_GetRGB(colorkey,surface->format,&keyR,&keyG,&keyB);
  760.                         SDL_SetColorKey(convert, cflags|(flags&SDL_RLEACCELOK),
  761.                                 SDL_MapRGB(convert->format, keyR, keyG, keyB));
  762.                 }
  763.                 SDL_SetColorKey(surface, cflags, colorkey);
  764.         }
  765.         if ( (surface_flags & SDL_SRCALPHA) == SDL_SRCALPHA ) {
  766.                 Uint32 aflags = surface_flags&(SDL_SRCALPHA|SDL_RLEACCELOK);
  767.                 if ( convert != NULL ) {
  768.                         SDL_SetAlpha(convert, aflags|(flags&SDL_RLEACCELOK),
  769.                                 alpha);
  770.                 }
  771.                 SDL_SetAlpha(surface, aflags, alpha);
  772.         }
  773.  
  774.         /* We're ready to go! */
  775.         return(convert);
  776. }
  777.  
  778. /*
  779.  * Free a surface created by the above function.
  780.  */
  781. void SDL_FreeSurface (SDL_Surface *surface)
  782. {
  783.         /* Free anything that's not NULL, and not the screen surface */
  784.         if ((surface == NULL) ||
  785.             (current_video &&
  786.             ((surface == SDL_ShadowSurface)||(surface == SDL_VideoSurface)))) {
  787.                 return;
  788.         }
  789.         if ( --surface->refcount > 0 ) {
  790.                 return;
  791.         }
  792.         if ( (surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL ) {
  793.                 SDL_UnRLESurface(surface, 0);
  794.         }
  795.         if ( surface->format ) {
  796.                 SDL_FreeFormat(surface->format);
  797.                 surface->format = NULL;
  798.         }
  799.         if ( surface->map != NULL ) {
  800.                 SDL_FreeBlitMap(surface->map);
  801.                 surface->map = NULL;
  802.         }
  803.         if ( (surface->flags & SDL_HWSURFACE) == SDL_HWSURFACE ) {
  804.                 SDL_VideoDevice *video = current_video;
  805.                 SDL_VideoDevice *this  = current_video;
  806.                 video->FreeHWSurface(this, surface);
  807.         }
  808.         if ( surface->pixels &&
  809.              ((surface->flags & SDL_PREALLOC) != SDL_PREALLOC) ) {
  810.                 free(surface->pixels);
  811.         }
  812.         free(surface);
  813. #ifdef CHECK_LEAKS
  814.         --surfaces_allocated;
  815. #endif
  816. }
  817.