Mercurial > sdl-ios-xcode
comparison src/video/SDL_drawrect.c @ 3594:c8bed77b0386
Added SDL_DrawRect(), SDL_DrawRects(), SDL_BlendRect() and SDL_BlendRects()
Fixed line drawing so when blending a sequence of lines there are no overlapping pixels drawn.
author | Sam Lantinga <slouken@libsdl.org> |
---|---|
date | Fri, 18 Dec 2009 07:41:59 +0000 |
parents | b931bcfd94a0 |
children | f7b03b6838cb |
comparison
equal
deleted
inserted
replaced
3593:b931bcfd94a0 | 3594:c8bed77b0386 |
---|---|
20 slouken@libsdl.org | 20 slouken@libsdl.org |
21 */ | 21 */ |
22 #include "SDL_config.h" | 22 #include "SDL_config.h" |
23 | 23 |
24 #include "SDL_video.h" | 24 #include "SDL_video.h" |
25 #include "SDL_blit.h" | |
26 | 25 |
27 | 26 |
28 #ifdef __SSE__ | |
29 /* *INDENT-OFF* */ | |
30 | |
31 #ifdef _MSC_VER | |
32 #define SSE_BEGIN \ | |
33 __m128 c128; \ | |
34 c128.m128_u32[0] = color; \ | |
35 c128.m128_u32[1] = color; \ | |
36 c128.m128_u32[2] = color; \ | |
37 c128.m128_u32[3] = color; | |
38 #else | |
39 #define SSE_BEGIN \ | |
40 DECLARE_ALIGNED(Uint32, cccc[4], 16); \ | |
41 cccc[0] = color; \ | |
42 cccc[1] = color; \ | |
43 cccc[2] = color; \ | |
44 cccc[3] = color; \ | |
45 __m128 c128 = *(__m128 *)cccc; | |
46 #endif | |
47 | |
48 #define SSE_WORK \ | |
49 for (i = n / 64; i--;) { \ | |
50 _mm_stream_ps((float *)(p+0), c128); \ | |
51 _mm_stream_ps((float *)(p+16), c128); \ | |
52 _mm_stream_ps((float *)(p+32), c128); \ | |
53 _mm_stream_ps((float *)(p+48), c128); \ | |
54 p += 64; \ | |
55 } | |
56 | |
57 #define SSE_END | |
58 | |
59 #define DEFINE_SSE_FILLRECT(bpp, type) \ | |
60 static void \ | |
61 SDL_DrawRect##bpp##SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \ | |
62 { \ | |
63 SSE_BEGIN; \ | |
64 \ | |
65 while (h--) { \ | |
66 int i, n = w * bpp; \ | |
67 Uint8 *p = pixels; \ | |
68 \ | |
69 if (n > 63) { \ | |
70 int adjust = 16 - ((uintptr_t)p & 15); \ | |
71 if (adjust < 16) { \ | |
72 n -= adjust; \ | |
73 adjust /= bpp; \ | |
74 while (adjust--) { \ | |
75 *((type *)p) = (type)color; \ | |
76 p += bpp; \ | |
77 } \ | |
78 } \ | |
79 SSE_WORK; \ | |
80 } \ | |
81 if (n & 63) { \ | |
82 int remainder = (n & 63); \ | |
83 remainder /= bpp; \ | |
84 while (remainder--) { \ | |
85 *((type *)p) = (type)color; \ | |
86 p += bpp; \ | |
87 } \ | |
88 } \ | |
89 pixels += pitch; \ | |
90 } \ | |
91 \ | |
92 SSE_END; \ | |
93 } | |
94 | |
95 static void | |
96 SDL_DrawRect1SSE(Uint8 *pixels, int pitch, Uint32 color, int w, int h) | |
97 { | |
98 SSE_BEGIN; | |
99 | |
100 while (h--) { | |
101 int i, n = w; | |
102 Uint8 *p = pixels; | |
103 | |
104 if (n > 63) { | |
105 int adjust = 16 - ((uintptr_t)p & 15); | |
106 if (adjust) { | |
107 n -= adjust; | |
108 SDL_memset(p, color, adjust); | |
109 p += adjust; | |
110 } | |
111 SSE_WORK; | |
112 } | |
113 if (n & 63) { | |
114 int remainder = (n & 63); | |
115 SDL_memset(p, color, remainder); | |
116 p += remainder; | |
117 } | |
118 pixels += pitch; | |
119 } | |
120 | |
121 SSE_END; | |
122 } | |
123 /*DEFINE_SSE_FILLRECT(1, Uint8)*/ | |
124 DEFINE_SSE_FILLRECT(2, Uint16) | |
125 DEFINE_SSE_FILLRECT(4, Uint32) | |
126 | |
127 /* *INDENT-ON* */ | |
128 #endif /* __SSE__ */ | |
129 | |
130 #ifdef __MMX__ | |
131 /* *INDENT-OFF* */ | |
132 | |
133 #define MMX_BEGIN \ | |
134 __m64 c64 = _mm_set_pi32(color, color) | |
135 | |
136 #define MMX_WORK \ | |
137 for (i = n / 64; i--;) { \ | |
138 _mm_stream_pi((__m64 *)(p+0), c64); \ | |
139 _mm_stream_pi((__m64 *)(p+8), c64); \ | |
140 _mm_stream_pi((__m64 *)(p+16), c64); \ | |
141 _mm_stream_pi((__m64 *)(p+24), c64); \ | |
142 _mm_stream_pi((__m64 *)(p+32), c64); \ | |
143 _mm_stream_pi((__m64 *)(p+40), c64); \ | |
144 _mm_stream_pi((__m64 *)(p+48), c64); \ | |
145 _mm_stream_pi((__m64 *)(p+56), c64); \ | |
146 p += 64; \ | |
147 } | |
148 | |
149 #define MMX_END \ | |
150 _mm_empty() | |
151 | |
152 #define DEFINE_MMX_FILLRECT(bpp, type) \ | |
153 static void \ | |
154 SDL_DrawRect##bpp##MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) \ | |
155 { \ | |
156 MMX_BEGIN; \ | |
157 \ | |
158 while (h--) { \ | |
159 int i, n = w * bpp; \ | |
160 Uint8 *p = pixels; \ | |
161 \ | |
162 if (n > 63) { \ | |
163 int adjust = 8 - ((uintptr_t)p & 7); \ | |
164 if (adjust < 8) { \ | |
165 n -= adjust; \ | |
166 adjust /= bpp; \ | |
167 while (adjust--) { \ | |
168 *((type *)p) = (type)color; \ | |
169 p += bpp; \ | |
170 } \ | |
171 } \ | |
172 MMX_WORK; \ | |
173 } \ | |
174 if (n & 63) { \ | |
175 int remainder = (n & 63); \ | |
176 remainder /= bpp; \ | |
177 while (remainder--) { \ | |
178 *((type *)p) = (type)color; \ | |
179 p += bpp; \ | |
180 } \ | |
181 } \ | |
182 pixels += pitch; \ | |
183 } \ | |
184 \ | |
185 MMX_END; \ | |
186 } | |
187 | |
188 static void | |
189 SDL_DrawRect1MMX(Uint8 *pixels, int pitch, Uint32 color, int w, int h) | |
190 { | |
191 MMX_BEGIN; | |
192 | |
193 while (h--) { | |
194 int i, n = w; | |
195 Uint8 *p = pixels; | |
196 | |
197 if (n > 63) { | |
198 int adjust = 8 - ((uintptr_t)p & 7); | |
199 if (adjust) { | |
200 n -= adjust; | |
201 SDL_memset(p, color, adjust); | |
202 p += adjust; | |
203 } | |
204 MMX_WORK; | |
205 } | |
206 if (n & 63) { | |
207 int remainder = (n & 63); | |
208 SDL_memset(p, color, remainder); | |
209 p += remainder; | |
210 } | |
211 pixels += pitch; | |
212 } | |
213 | |
214 MMX_END; | |
215 } | |
216 /*DEFINE_MMX_FILLRECT(1, Uint8)*/ | |
217 DEFINE_MMX_FILLRECT(2, Uint16) | |
218 DEFINE_MMX_FILLRECT(4, Uint32) | |
219 | |
220 /* *INDENT-ON* */ | |
221 #endif /* __MMX__ */ | |
222 | |
223 static void | |
224 SDL_DrawRect1(Uint8 * pixels, int pitch, Uint32 color, int w, int h) | |
225 { | |
226 while (h--) { | |
227 int n = w; | |
228 Uint8 *p = pixels; | |
229 | |
230 if (n > 3) { | |
231 switch ((uintptr_t) p & 3) { | |
232 case 1: | |
233 *p++ = (Uint8) color; | |
234 --n; | |
235 case 2: | |
236 *p++ = (Uint8) color; | |
237 --n; | |
238 case 3: | |
239 *p++ = (Uint8) color; | |
240 --n; | |
241 } | |
242 SDL_memset4(p, color, (n >> 2)); | |
243 } | |
244 if (n & 3) { | |
245 p += (n & ~3); | |
246 switch (n & 3) { | |
247 case 3: | |
248 *p++ = (Uint8) color; | |
249 case 2: | |
250 *p++ = (Uint8) color; | |
251 case 1: | |
252 *p++ = (Uint8) color; | |
253 } | |
254 } | |
255 pixels += pitch; | |
256 } | |
257 } | |
258 | |
259 static void | |
260 SDL_DrawRect2(Uint8 * pixels, int pitch, Uint32 color, int w, int h) | |
261 { | |
262 while (h--) { | |
263 int n = w; | |
264 Uint16 *p = (Uint16 *) pixels; | |
265 | |
266 if (n > 1) { | |
267 if ((uintptr_t) p & 2) { | |
268 *p++ = (Uint16) color; | |
269 --n; | |
270 } | |
271 SDL_memset4(p, color, (n >> 1)); | |
272 } | |
273 if (n & 1) { | |
274 p[n - 1] = (Uint16) color; | |
275 } | |
276 pixels += pitch; | |
277 } | |
278 } | |
279 | |
280 static void | |
281 SDL_DrawRect3(Uint8 * pixels, int pitch, Uint32 color, int w, int h) | |
282 { | |
283 Uint8 r = (Uint8) ((color >> 16) & 0xFF); | |
284 Uint8 g = (Uint8) ((color >> 8) & 0xFF); | |
285 Uint8 b = (Uint8) (color & 0xFF); | |
286 | |
287 while (h--) { | |
288 int n = w; | |
289 Uint8 *p = pixels; | |
290 | |
291 while (n--) { | |
292 *p++ = r; | |
293 *p++ = g; | |
294 *p++ = b; | |
295 } | |
296 pixels += pitch; | |
297 } | |
298 } | |
299 | |
300 static void | |
301 SDL_DrawRect4(Uint8 * pixels, int pitch, Uint32 color, int w, int h) | |
302 { | |
303 while (h--) { | |
304 SDL_memset4(pixels, color, w); | |
305 pixels += pitch; | |
306 } | |
307 } | |
308 | |
309 /* | |
310 * This function performs a fast fill of the given rectangle with 'color' | |
311 */ | |
312 int | 27 int |
313 SDL_DrawRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color) | 28 SDL_DrawRect(SDL_Surface * dst, const SDL_Rect * rect, Uint32 color) |
314 { | 29 { |
315 SDL_Rect clipped; | 30 SDL_Rect full_rect; |
316 Uint8 *pixels; | 31 SDL_Point points[5]; |
317 | 32 |
318 if (!dst) { | 33 if (!dst) { |
319 SDL_SetError("Passed NULL destination surface"); | 34 SDL_SetError("Passed NULL destination surface"); |
320 return -1; | 35 return -1; |
321 } | 36 } |
322 | 37 |
323 /* This function doesn't work on surfaces < 8 bpp */ | 38 /* If 'rect' == NULL, then outline the whole surface */ |
324 if (dst->format->BitsPerPixel < 8) { | 39 if (!rect) { |
325 SDL_SetError("SDL_DrawRect(): Unsupported surface format"); | 40 full_rect.x = 0; |
326 return -1; | 41 full_rect.y = 0; |
42 full_rect.w = dst->w; | |
43 full_rect.h = dst->h; | |
44 rect = &full_rect; | |
327 } | 45 } |
328 | 46 |
329 /* If 'rect' == NULL, then fill the whole surface */ | 47 points[0].x = rect->x; |
330 if (rect) { | 48 points[0].y = rect->y; |
331 /* Perform clipping */ | 49 points[1].x = rect->x+rect->w-1; |
332 if (!SDL_IntersectRect(rect, &dst->clip_rect, &clipped)) { | 50 points[1].y = rect->y; |
333 return 0; | 51 points[2].x = rect->x+rect->w-1; |
334 } | 52 points[2].y = rect->y+rect->h-1; |
335 rect = &clipped; | 53 points[3].x = rect->x; |
336 } else { | 54 points[3].y = rect->y+rect->h-1; |
337 rect = &dst->clip_rect; | 55 points[4].x = rect->x; |
338 } | 56 points[4].y = rect->y; |
339 | 57 return SDL_DrawLines(dst, points, 5, color); |
340 /* Perform software fill */ | |
341 if (!dst->pixels) { | |
342 SDL_SetError("SDL_DrawRect(): You must lock the surface"); | |
343 return (-1); | |
344 } | |
345 | |
346 pixels = (Uint8 *) dst->pixels + rect->y * dst->pitch + | |
347 rect->x * dst->format->BytesPerPixel; | |
348 | |
349 switch (dst->format->BytesPerPixel) { | |
350 case 1: | |
351 { | |
352 color |= (color << 8); | |
353 color |= (color << 16); | |
354 #ifdef __SSE__ | |
355 if (SDL_HasSSE()) { | |
356 SDL_DrawRect1SSE(pixels, dst->pitch, color, rect->w, rect->h); | |
357 break; | |
358 } | |
359 #endif | |
360 #ifdef __MMX__ | |
361 if (SDL_HasMMX()) { | |
362 SDL_DrawRect1MMX(pixels, dst->pitch, color, rect->w, rect->h); | |
363 break; | |
364 } | |
365 #endif | |
366 SDL_DrawRect1(pixels, dst->pitch, color, rect->w, rect->h); | |
367 break; | |
368 } | |
369 | |
370 case 2: | |
371 { | |
372 color |= (color << 16); | |
373 #ifdef __SSE__ | |
374 if (SDL_HasSSE()) { | |
375 SDL_DrawRect2SSE(pixels, dst->pitch, color, rect->w, rect->h); | |
376 break; | |
377 } | |
378 #endif | |
379 #ifdef __MMX__ | |
380 if (SDL_HasMMX()) { | |
381 SDL_DrawRect2MMX(pixels, dst->pitch, color, rect->w, rect->h); | |
382 break; | |
383 } | |
384 #endif | |
385 SDL_DrawRect2(pixels, dst->pitch, color, rect->w, rect->h); | |
386 break; | |
387 } | |
388 | |
389 case 3: | |
390 /* 24-bit RGB is a slow path, at least for now. */ | |
391 { | |
392 SDL_DrawRect3(pixels, dst->pitch, color, rect->w, rect->h); | |
393 break; | |
394 } | |
395 | |
396 case 4: | |
397 { | |
398 #ifdef __SSE__ | |
399 if (SDL_HasSSE()) { | |
400 SDL_DrawRect4SSE(pixels, dst->pitch, color, rect->w, rect->h); | |
401 break; | |
402 } | |
403 #endif | |
404 #ifdef __MMX__ | |
405 if (SDL_HasMMX()) { | |
406 SDL_DrawRect4MMX(pixels, dst->pitch, color, rect->w, rect->h); | |
407 break; | |
408 } | |
409 #endif | |
410 SDL_DrawRect4(pixels, dst->pitch, color, rect->w, rect->h); | |
411 break; | |
412 } | |
413 } | |
414 | |
415 /* We're done! */ | |
416 return 0; | |
417 } | 58 } |
418 | 59 |
419 int | 60 int |
420 SDL_DrawRects(SDL_Surface * dst, const SDL_Rect ** rects, int count, | 61 SDL_DrawRects(SDL_Surface * dst, const SDL_Rect ** rects, int count, |
421 Uint32 color) | 62 Uint32 color) |
422 { | 63 { |
423 int i; | 64 int i; |
424 int status = 0; | |
425 | 65 |
426 for (i = 0; i < count; ++i) { | 66 for (i = 0; i < count; ++i) { |
427 status = SDL_DrawRect(dst, rects[i], color); | 67 if (SDL_DrawRect(dst, rects[i], color) < 0) { |
68 return -1; | |
69 } | |
428 } | 70 } |
429 return status; | 71 return 0; |
430 } | 72 } |
431 | 73 |
432 /* vi: set ts=4 sw=4 expandtab: */ | 74 /* vi: set ts=4 sw=4 expandtab: */ |