sge_surface.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379
  1. /*
  2. * SDL Graphics Extension
  3. * Pixel, surface and color functions
  4. *
  5. * Started 990815 (split from sge_draw 010611)
  6. *
  7. * License: LGPL v2+ (see the file LICENSE)
  8. * (c)1999-2003 Anders Lindström
  9. */
  10. /* MODIFIED: _PutPixelAlpha 02/27/2004 Janson
  11. * All changes are for 32bpp surfaces only (only ones we use right now)
  12. * 1) 32bit uses long long to prevent clipping of alpha
  13. * 2) alpha blend for RGB is scaled towards alpha of pixel, so that
  14. * the resulting pixel doesn't "double up" on alpha due to
  15. * both the color being shaded AND alpha being present
  16. * 3) drawing on fully transparent surface just blends alpha, but
  17. * doesn't have to scale it then (this is just an optimization)
  18. *
  19. * These modifications make all AA and alpha-blended functions graphic-program quality.
  20. *
  21. * MODIFIED: Prefix ++/-- instead of postfix (consistent with my other code)
  22. * Removed all 8/24 bit code
  23. *
  24. * REMOVED: _sge_update and all related functions
  25. * sge_CreateAlphaSurface
  26. * all palette, copy, block, fill functions
  27. */
  28. /*********************************************************************
  29. * This library is free software; you can redistribute it and/or *
  30. * modify it under the terms of the GNU Library General Public *
  31. * License as published by the Free Software Foundation; either *
  32. * version 2 of the License, or (at your option) any later version. *
  33. *********************************************************************/
  34. /*
  35. * Some of this code is taken from the "Introduction to SDL" and
  36. * John Garrison's PowerPak
  37. */
  38. // (MODIFIED Janson - using std header)
  39. #include "all.h"
  40. /* Globals used for sge_Lock */
  41. Uint8 _sge_lock=1;
  42. /**********************************************************************************/
  43. /** Misc. functions **/
  44. /**********************************************************************************/
  45. //==================================================================================
  46. // Turns off automatic locking of surfaces
  47. //==================================================================================
  48. void sge_Lock_OFF(void)
  49. {
  50. _sge_lock=0;
  51. }
  52. //==================================================================================
  53. // Turns on automatic locking (default)
  54. //==================================================================================
  55. void sge_Lock_ON(void)
  56. {
  57. _sge_lock=1;
  58. }
  59. //==================================================================================
  60. // Returns locking mode (1-on and 0-off)
  61. //==================================================================================
  62. Uint8 sge_getLock(void)
  63. {
  64. return _sge_lock;
  65. }
  66. //==================================================================================
  67. // Returns the Uint32 color value for a 32bit (8/8/8/8) alpha surface
  68. //==================================================================================
  69. Uint32 sge_MapAlpha(Uint8 R, Uint8 G, Uint8 B, Uint8 A)
  70. {
  71. Uint32 color=0;
  72. color|=R<<24;
  73. color|=G<<16;
  74. color|=B<<8;
  75. color|=A;
  76. return color;
  77. }
  78. //==================================================================================
  79. // Sets an SDL error string
  80. // Accepts formated argument - like printf()
  81. // SDL_SetError() also does this, but it does not use standard syntax (why?)
  82. //==================================================================================
  83. void sge_SetError(const char *format, ...)
  84. {
  85. char buf[256];
  86. va_list ap;
  87. #ifdef __WIN32__
  88. va_start(ap, format); //Stupid w32 crosscompiler
  89. #else
  90. va_start(ap, format);
  91. #endif
  92. vsprintf(buf, format, ap);
  93. va_end(ap);
  94. SDL_SetError(buf);
  95. }
  96. /**********************************************************************************/
  97. /** Pixel functions **/
  98. /**********************************************************************************/
  99. //==================================================================================
  100. // Fast put pixel
  101. //==================================================================================
  102. void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
  103. {
  104. if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && y>=sge_clip_ymin(surface) && y<=sge_clip_ymax(surface)){
  105. switch (surface->format->BytesPerPixel) {
  106. case 2: { /* Probably 15-bpp or 16-bpp */
  107. *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
  108. }
  109. break;
  110. case 4: { /* Probably 32-bpp */
  111. *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
  112. }
  113. break;
  114. }
  115. }
  116. }
  117. //==================================================================================
  118. // Fast put pixel (RGB)
  119. //==================================================================================
  120. void _PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B)
  121. {
  122. _PutPixel(surface,x,y, SDL_MapRGB(surface->format, R, G, B));
  123. }
  124. //==================================================================================
  125. // Fastest put pixel functions (don't mess up indata, thank you)
  126. //==================================================================================
  127. void _PutPixel16(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
  128. {
  129. *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
  130. }
  131. void _PutPixel32(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
  132. {
  133. *((Uint32 *)surface->pixels + y*surface->pitch/4 + x) = color;
  134. }
  135. void _PutPixelX(SDL_Surface *dest,Sint16 x,Sint16 y,Uint32 color)
  136. {
  137. switch ( dest->format->BytesPerPixel ) {
  138. case 2:
  139. *((Uint16 *)dest->pixels + y*dest->pitch/2 + x) = color;
  140. break;
  141. case 4:
  142. *((Uint32 *)dest->pixels + y*dest->pitch/4 + x) = color;
  143. break;
  144. }
  145. }
  146. //==================================================================================
  147. // Safe put pixel
  148. //==================================================================================
  149. void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color)
  150. {
  151. if ( SDL_MUSTLOCK(surface) && _sge_lock ) {
  152. if ( SDL_LockSurface(surface) < 0 ) {
  153. return;
  154. }
  155. }
  156. _PutPixel(surface, x, y, color);
  157. if ( SDL_MUSTLOCK(surface) && _sge_lock ) {
  158. SDL_UnlockSurface(surface);
  159. }
  160. }
  161. //==================================================================================
  162. // Safe put pixel (RGB)
  163. //==================================================================================
  164. void sge_PutPixel(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B)
  165. {
  166. sge_PutPixel(surface,x,y, SDL_MapRGB(surface->format, R, G, B));
  167. }
  168. //==================================================================================
  169. // Calculate y pitch offset
  170. // (the y pitch offset is constant for the same y coord and surface)
  171. //==================================================================================
  172. Sint32 sge_CalcYPitch(SDL_Surface *dest,Sint16 y)
  173. {
  174. if(y>=sge_clip_ymin(dest) && y<=sge_clip_ymax(dest)){
  175. switch ( dest->format->BytesPerPixel ) {
  176. case 2:
  177. return y*dest->pitch/2;
  178. break;
  179. case 4:
  180. return y*dest->pitch/4;
  181. break;
  182. }
  183. }
  184. return -1;
  185. }
  186. //==================================================================================
  187. // Put pixel with precalculated y pitch offset
  188. //==================================================================================
  189. void sge_pPutPixel(SDL_Surface *surface, Sint16 x, Sint32 ypitch, Uint32 color)
  190. {
  191. if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && ypitch>=0){
  192. switch (surface->format->BytesPerPixel) {
  193. case 2: { /* Probably 15-bpp or 16-bpp */
  194. *((Uint16 *)surface->pixels + ypitch + x) = color;
  195. }
  196. break;
  197. case 4: { /* Probably 32-bpp */
  198. *((Uint32 *)surface->pixels + ypitch + x) = color;
  199. }
  200. break;
  201. }
  202. }
  203. }
  204. //==================================================================================
  205. // Get pixel
  206. //==================================================================================
  207. Uint32 sge_GetPixel(SDL_Surface *surface, Sint16 x, Sint16 y)
  208. {
  209. if(x<0 || x>=surface->w || y<0 || y>=surface->h)
  210. return 0;
  211. switch (surface->format->BytesPerPixel) {
  212. case 2: { /* Probably 15-bpp or 16-bpp */
  213. return *((Uint16 *)surface->pixels + y*surface->pitch/2 + x);
  214. }
  215. break;
  216. case 4: { /* Probably 32-bpp */
  217. return *((Uint32 *)surface->pixels + y*surface->pitch/4 + x);
  218. }
  219. break;
  220. }
  221. return 0;
  222. }
  223. //==================================================================================
  224. // Put pixel with alpha blending
  225. //==================================================================================
  226. void _PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
  227. {
  228. if(x>=sge_clip_xmin(surface) && x<=sge_clip_xmax(surface) && y>=sge_clip_ymin(surface) && y<=sge_clip_ymax(surface)){
  229. Uint32 Rmask = surface->format->Rmask, Gmask = surface->format->Gmask, Bmask = surface->format->Bmask, Amask = surface->format->Amask;
  230. Uint32 R,G,B,A=0;
  231. switch (surface->format->BytesPerPixel) {
  232. case 2: { /* Probably 15-bpp or 16-bpp */
  233. if( alpha == 255 ){
  234. *((Uint16 *)surface->pixels + y*surface->pitch/2 + x) = color;
  235. }else{
  236. Uint16 *pixel = (Uint16 *)surface->pixels + y*surface->pitch/2 + x;
  237. Uint32 dc = *pixel;
  238. R = ((dc & Rmask) + (( (color & Rmask) - (dc & Rmask) ) * alpha >> 8)) & Rmask;
  239. G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * alpha >> 8)) & Gmask;
  240. B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * alpha >> 8)) & Bmask;
  241. if( Amask )
  242. A = ((dc & Amask) + (( (color & Amask) - (dc & Amask) ) * alpha >> 8)) & Amask;
  243. *pixel= R | G | B | A;
  244. }
  245. }
  246. break;
  247. case 4: { /* Probably 32-bpp */
  248. Uint32 *pixel = (Uint32 *)surface->pixels + y*surface->pitch/4 + x;
  249. // Special case 100% blend and 0% destination
  250. if( alpha == 255 ){
  251. *pixel = color;
  252. }else if ((Amask) && ((*pixel & Amask) == 0)) {
  253. // Destination is 100% transparent, so place our pixel normal with alpha scaled
  254. A = ((long long)(color & Amask) * alpha >> 8) & Amask;
  255. *pixel = (color & (Rmask | Gmask | Bmask)) | A;
  256. }else{
  257. Uint32 dc = *pixel;
  258. // Scale RGB blend based on alpha of destination
  259. int destAlpha = (dc & Amask) >> surface->format->Ashift;
  260. int rgbScale = alpha;
  261. if (destAlpha < alpha) rgbScale = alpha + (256 - alpha) * (alpha - destAlpha) / 255;
  262. // We have to ensure no unwanted clipping occurs, of both overflow and negatives
  263. // Our main() asserts that long long is at least 48 bits
  264. R = ((dc & Rmask) + (((long long)(color & Rmask) - (long long)(dc & Rmask) ) * rgbScale >> 8)) & Rmask;
  265. G = ((dc & Gmask) + (( (color & Gmask) - (dc & Gmask) ) * rgbScale >> 8)) & Gmask;
  266. B = ((dc & Bmask) + (( (color & Bmask) - (dc & Bmask) ) * rgbScale >> 8)) & Bmask;
  267. if (Amask)
  268. A = ((dc & Amask) + (((long long)(color & Amask) - (long long)(dc & Amask) ) * alpha >> 8)) & Amask;
  269. *pixel = R | G | B | A;
  270. }
  271. }
  272. break;
  273. }
  274. }
  275. }
  276. void sge_PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint32 color, Uint8 alpha)
  277. {
  278. if ( SDL_MUSTLOCK(surface) && _sge_lock )
  279. if ( SDL_LockSurface(surface) < 0 )
  280. return;
  281. _PutPixelAlpha(surface,x,y,color,alpha);
  282. /* unlock the display */
  283. if (SDL_MUSTLOCK(surface) && _sge_lock) {
  284. SDL_UnlockSurface(surface);
  285. }
  286. }
  287. void _PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
  288. {
  289. _PutPixelAlpha(surface,x,y, SDL_MapRGB(surface->format, R, G, B),alpha);
  290. }
  291. void sge_PutPixelAlpha(SDL_Surface *surface, Sint16 x, Sint16 y, Uint8 R, Uint8 G, Uint8 B, Uint8 alpha)
  292. {
  293. sge_PutPixelAlpha(surface,x,y, SDL_MapRGB(surface->format, R, G, B), alpha);
  294. }
  295. /**********************************************************************************/
  296. /** Blitting/surface functions **/
  297. /**********************************************************************************/
  298. //==================================================================================
  299. // Clear surface to color
  300. //==================================================================================
  301. void sge_ClearSurface(SDL_Surface *Surface, Uint32 color)
  302. {
  303. SDL_FillRect(Surface, (SDL_Rect*)NULL, color);
  304. }
  305. //==================================================================================
  306. // Clear surface to color (RGB)
  307. //==================================================================================
  308. void sge_ClearSurface(SDL_Surface *Surface, Uint8 R, Uint8 G, Uint8 B)
  309. {
  310. sge_ClearSurface(Surface,SDL_MapRGB(Surface->format, R, G, B));
  311. }