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