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: */