Mercurial > sdl-ios-xcode
annotate src/video/SDL_stretch.c @ 1643:51038e80ae59
More general fix for bug #189
The clipping is done at a higher level, and the low level functions are
passed clipped rectangles. Drivers which don't support source clipping
have not been changed, so the image will be squished instead of clipped,
but at least they will no longer crash when the destination rect was out
of bounds.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Mon, 17 Apr 2006 06:47:23 +0000 |
parents | e3242177fe4a |
children | 782fd950bd46 b5a4ac87b98c |
rev | line source |
---|---|
0 | 1 /* |
2 SDL - Simple DirectMedia Layer | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
3 Copyright (C) 1997-2006 Sam Lantinga |
0 | 4 |
5 This library is free software; you can redistribute it and/or | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
6 modify it under the terms of the GNU Lesser General Public |
0 | 7 License as published by the Free Software Foundation; either |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
8 version 2.1 of the License, or (at your option) any later version. |
0 | 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 | |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
13 Lesser General Public License for more details. |
0 | 14 |
1312
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
15 You should have received a copy of the GNU Lesser General Public |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
16 License along with this library; if not, write to the Free Software |
c9b51268668f
Updated copyright information and removed rcs id lines (problematic in branch merges)
Sam Lantinga <slouken@libsdl.org>
parents:
1234
diff
changeset
|
17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA |
0 | 18 |
19 Sam Lantinga | |
252
e8157fcb3114
Updated the source with the correct e-mail address
Sam Lantinga <slouken@libsdl.org>
parents:
0
diff
changeset
|
20 slouken@libsdl.org |
0 | 21 */ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
22 #include "SDL_config.h" |
0 | 23 |
24 /* This a stretch blit implementation based on ideas given to me by | |
25 Tomasz Cejner - thanks! :) | |
26 | |
27 April 27, 2000 - Sam Lantinga | |
28 */ | |
29 | |
30 #include "SDL_video.h" | |
31 #include "SDL_blit.h" | |
32 | |
33 /* This isn't ready for general consumption yet - it should be folded | |
34 into the general blitting mechanism. | |
35 */ | |
36 | |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
37 #if ((defined(_MFC_VER) && defined(_M_IX86)/* && !defined(_WIN32_WCE) still needed? */) || \ |
1442
e3242177fe4a
Updated OS/2 build, yay!
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
38 defined(__WATCOMC__) || \ |
1402
d910939febfa
Use consistent identifiers for the various platforms we support.
Sam Lantinga <slouken@libsdl.org>
parents:
1361
diff
changeset
|
39 (defined(__GNUC__) && defined(__i386__))) && SDL_ASSEMBLY_ROUTINES |
0 | 40 #define USE_ASM_STRETCH |
41 #endif | |
42 | |
43 #ifdef USE_ASM_STRETCH | |
44 | |
1361
19418e4422cb
New configure-based build system. Still work in progress, but much improved
Sam Lantinga <slouken@libsdl.org>
parents:
1358
diff
changeset
|
45 #if defined(_M_IX86) || defined(i386) |
0 | 46 #define PREFIX16 0x66 |
47 #define STORE_BYTE 0xAA | |
48 #define STORE_WORD 0xAB | |
49 #define LOAD_BYTE 0xAC | |
50 #define LOAD_WORD 0xAD | |
51 #define RETURN 0xC3 | |
52 #else | |
53 #error Need assembly opcodes for this architecture | |
54 #endif | |
55 | |
56 static unsigned char copy_row[4096]; | |
57 | |
58 static int generate_rowbytes(int src_w, int dst_w, int bpp) | |
59 { | |
60 static struct { | |
61 int bpp; | |
62 int src_w; | |
63 int dst_w; | |
64 } last; | |
65 | |
66 int i; | |
67 int pos, inc; | |
68 unsigned char *eip; | |
69 unsigned char load, store; | |
70 | |
71 /* See if we need to regenerate the copy buffer */ | |
72 if ( (src_w == last.src_w) && | |
1164
10b3fb28c86b
Date: Mon, 31 Oct 2005 14:23:34 +0100
Ryan C. Gordon <icculus@icculus.org>
parents:
894
diff
changeset
|
73 (dst_w == last.dst_w) && (bpp == last.bpp) ) { |
0 | 74 return(0); |
75 } | |
76 last.bpp = bpp; | |
77 last.src_w = src_w; | |
78 last.dst_w = dst_w; | |
79 | |
80 switch (bpp) { | |
81 case 1: | |
82 load = LOAD_BYTE; | |
83 store = STORE_BYTE; | |
84 break; | |
85 case 2: | |
86 case 4: | |
87 load = LOAD_WORD; | |
88 store = STORE_WORD; | |
89 break; | |
90 default: | |
91 SDL_SetError("ASM stretch of %d bytes isn't supported\n", bpp); | |
92 return(-1); | |
93 } | |
94 pos = 0x10000; | |
95 inc = (src_w << 16) / dst_w; | |
96 eip = copy_row; | |
97 for ( i=0; i<dst_w; ++i ) { | |
98 while ( pos >= 0x10000L ) { | |
99 if ( bpp == 2 ) { | |
100 *eip++ = PREFIX16; | |
101 } | |
102 *eip++ = load; | |
103 pos -= 0x10000L; | |
104 } | |
105 if ( bpp == 2 ) { | |
106 *eip++ = PREFIX16; | |
107 } | |
108 *eip++ = store; | |
109 pos += inc; | |
110 } | |
111 *eip++ = RETURN; | |
112 | |
113 /* Verify that we didn't overflow (too late) */ | |
114 if ( eip > (copy_row+sizeof(copy_row)) ) { | |
115 SDL_SetError("Copy buffer overflow"); | |
116 return(-1); | |
117 } | |
118 return(0); | |
119 } | |
120 | |
121 #else | |
122 | |
123 #define DEFINE_COPY_ROW(name, type) \ | |
124 void name(type *src, int src_w, type *dst, int dst_w) \ | |
125 { \ | |
126 int i; \ | |
127 int pos, inc; \ | |
128 type pixel = 0; \ | |
129 \ | |
130 pos = 0x10000; \ | |
131 inc = (src_w << 16) / dst_w; \ | |
132 for ( i=dst_w; i>0; --i ) { \ | |
133 while ( pos >= 0x10000L ) { \ | |
134 pixel = *src++; \ | |
135 pos -= 0x10000L; \ | |
136 } \ | |
137 *dst++ = pixel; \ | |
138 pos += inc; \ | |
139 } \ | |
140 } | |
141 DEFINE_COPY_ROW(copy_row1, Uint8) | |
142 DEFINE_COPY_ROW(copy_row2, Uint16) | |
143 DEFINE_COPY_ROW(copy_row4, Uint32) | |
144 | |
145 #endif /* USE_ASM_STRETCH */ | |
146 | |
147 /* The ASM code doesn't handle 24-bpp stretch blits */ | |
148 void copy_row3(Uint8 *src, int src_w, Uint8 *dst, int dst_w) | |
149 { | |
150 int i; | |
151 int pos, inc; | |
152 Uint8 pixel[3]; | |
153 | |
154 pos = 0x10000; | |
155 inc = (src_w << 16) / dst_w; | |
156 for ( i=dst_w; i>0; --i ) { | |
157 while ( pos >= 0x10000L ) { | |
158 pixel[0] = *src++; | |
159 pixel[1] = *src++; | |
160 pixel[2] = *src++; | |
161 pos -= 0x10000L; | |
162 } | |
163 *dst++ = pixel[0]; | |
164 *dst++ = pixel[1]; | |
165 *dst++ = pixel[2]; | |
166 pos += inc; | |
167 } | |
168 } | |
169 | |
170 /* Perform a stretch blit between two surfaces of the same format. | |
171 NOTE: This function is not safe to call from multiple threads! | |
172 */ | |
173 int SDL_SoftStretch(SDL_Surface *src, SDL_Rect *srcrect, | |
174 SDL_Surface *dst, SDL_Rect *dstrect) | |
175 { | |
894
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
176 int src_locked; |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
177 int dst_locked; |
0 | 178 int pos, inc; |
179 int dst_width; | |
180 int dst_maxrow; | |
181 int src_row, dst_row; | |
182 Uint8 *srcp = NULL; | |
183 Uint8 *dstp; | |
184 SDL_Rect full_src; | |
185 SDL_Rect full_dst; | |
186 #if defined(USE_ASM_STRETCH) && defined(__GNUC__) | |
187 int u1, u2; | |
188 #endif | |
189 const int bpp = dst->format->BytesPerPixel; | |
190 | |
191 if ( src->format->BitsPerPixel != dst->format->BitsPerPixel ) { | |
192 SDL_SetError("Only works with same format surfaces"); | |
193 return(-1); | |
194 } | |
195 | |
196 /* Verify the blit rectangles */ | |
197 if ( srcrect ) { | |
198 if ( (srcrect->x < 0) || (srcrect->y < 0) || | |
199 ((srcrect->x+srcrect->w) > src->w) || | |
200 ((srcrect->y+srcrect->h) > src->h) ) { | |
201 SDL_SetError("Invalid source blit rectangle"); | |
202 return(-1); | |
203 } | |
204 } else { | |
205 full_src.x = 0; | |
206 full_src.y = 0; | |
207 full_src.w = src->w; | |
208 full_src.h = src->h; | |
209 srcrect = &full_src; | |
210 } | |
211 if ( dstrect ) { | |
212 if ( (dstrect->x < 0) || (dstrect->y < 0) || | |
213 ((dstrect->x+dstrect->w) > dst->w) || | |
214 ((dstrect->y+dstrect->h) > dst->h) ) { | |
215 SDL_SetError("Invalid destination blit rectangle"); | |
216 return(-1); | |
217 } | |
218 } else { | |
219 full_dst.x = 0; | |
220 full_dst.y = 0; | |
221 full_dst.w = dst->w; | |
222 full_dst.h = dst->h; | |
223 dstrect = &full_dst; | |
224 } | |
225 | |
894
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
226 /* Lock the destination if it's in hardware */ |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
227 dst_locked = 0; |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
228 if ( SDL_MUSTLOCK(dst) ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
229 if ( SDL_LockSurface(dst) < 0 ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
230 SDL_SetError("Unable to lock destination surface"); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
231 return(-1); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
232 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
233 dst_locked = 1; |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
234 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
235 /* Lock the source if it's in hardware */ |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
236 src_locked = 0; |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
237 if ( SDL_MUSTLOCK(src) ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
238 if ( SDL_LockSurface(src) < 0 ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
239 if ( dst_locked ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
240 SDL_UnlockSurface(dst); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
241 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
242 SDL_SetError("Unable to lock source surface"); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
243 return(-1); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
244 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
245 src_locked = 1; |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
246 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
247 |
0 | 248 /* Set up the data... */ |
249 pos = 0x10000; | |
250 inc = (srcrect->h << 16) / dstrect->h; | |
251 src_row = srcrect->y; | |
252 dst_row = dstrect->y; | |
253 dst_width = dstrect->w*bpp; | |
254 | |
255 #ifdef USE_ASM_STRETCH | |
256 /* Write the opcodes for this stretch */ | |
257 if ( (bpp != 3) && | |
258 (generate_rowbytes(srcrect->w, dstrect->w, bpp) < 0) ) { | |
259 return(-1); | |
260 } | |
261 #endif | |
262 | |
263 /* Perform the stretch blit */ | |
264 for ( dst_maxrow = dst_row+dstrect->h; dst_row<dst_maxrow; ++dst_row ) { | |
265 dstp = (Uint8 *)dst->pixels + (dst_row*dst->pitch) | |
266 + (dstrect->x*bpp); | |
267 while ( pos >= 0x10000L ) { | |
268 srcp = (Uint8 *)src->pixels + (src_row*src->pitch) | |
269 + (srcrect->x*bpp); | |
270 ++src_row; | |
271 pos -= 0x10000L; | |
272 } | |
273 #ifdef USE_ASM_STRETCH | |
274 switch (bpp) { | |
275 case 3: | |
276 copy_row3(srcp, srcrect->w, dstp, dstrect->w); | |
277 break; | |
278 default: | |
279 #ifdef __GNUC__ | |
627
8b9ac38381d0
Fixed compile problem in SDL_stretch.c with gcc 3.3
Sam Lantinga <slouken@libsdl.org>
parents:
297
diff
changeset
|
280 __asm__ __volatile__ ( |
1228
f4a3a4129d04
From Mike Frysinger and/or Gentoo:
Ryan C. Gordon <icculus@icculus.org>
parents:
1164
diff
changeset
|
281 "call *%4" |
0 | 282 : "=&D" (u1), "=&S" (u2) |
1234
73676c1f56ee
For sanity's sake, removed the '&' when passing copy_row array to asm.
Ryan C. Gordon <icculus@icculus.org>
parents:
1233
diff
changeset
|
283 : "0" (dstp), "1" (srcp), "r" (copy_row) |
0 | 284 : "memory" ); |
1442
e3242177fe4a
Updated OS/2 build, yay!
Sam Lantinga <slouken@libsdl.org>
parents:
1402
diff
changeset
|
285 #elif defined(_MSC_VER) || defined(__WATCOMC__) |
1234
73676c1f56ee
For sanity's sake, removed the '&' when passing copy_row array to asm.
Ryan C. Gordon <icculus@icculus.org>
parents:
1233
diff
changeset
|
286 { void *code = copy_row; |
0 | 287 __asm { |
288 push edi | |
289 push esi | |
290 | |
291 mov edi, dstp | |
292 mov esi, srcp | |
293 call dword ptr code | |
294 | |
295 pop esi | |
296 pop edi | |
297 } | |
298 } | |
299 #else | |
300 #error Need inline assembly for this compiler | |
301 #endif | |
302 break; | |
303 } | |
304 #else | |
305 switch (bpp) { | |
306 case 1: | |
307 copy_row1(srcp, srcrect->w, dstp, dstrect->w); | |
308 break; | |
309 case 2: | |
310 copy_row2((Uint16 *)srcp, srcrect->w, | |
311 (Uint16 *)dstp, dstrect->w); | |
312 break; | |
313 case 3: | |
314 copy_row3(srcp, srcrect->w, dstp, dstrect->w); | |
315 break; | |
316 case 4: | |
317 copy_row4((Uint32 *)srcp, srcrect->w, | |
318 (Uint32 *)dstp, dstrect->w); | |
319 break; | |
320 } | |
321 #endif | |
322 pos += inc; | |
323 } | |
894
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
324 |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
325 /* We need to unlock the surfaces if they're locked */ |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
326 if ( dst_locked ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
327 SDL_UnlockSurface(dst); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
328 } |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
329 if ( src_locked ) { |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
330 SDL_UnlockSurface(src); |
1d1a823904d8
Don't crash if the stretch routines are used on hardware surfaces
Sam Lantinga <slouken@libsdl.org>
parents:
769
diff
changeset
|
331 } |
0 | 332 return(0); |
333 } | |
334 |