comparison src/render/SDL_render.c @ 5157:fb424691cfc7

Moved the rendering code out to a separate directory in the hope that it can someday be completely decoupled from the rest of the library and be expanded to an awesome 2D on 3D library.
author Sam Lantinga <slouken@libsdl.org>
date Wed, 02 Feb 2011 14:34:54 -0800
parents
children 307ccc9c135e
comparison
equal deleted inserted replaced
5156:3e4086b3bcd2 5157:fb424691cfc7
1 /*
2 SDL - Simple DirectMedia Layer
3 Copyright (C) 1997-2010 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 /* The SDL 2D rendering system */
25
26 #include "SDL_render.h"
27 #include "SDL_sysrender.h"
28 #include "../video/SDL_pixels_c.h"
29
30
31 #define CHECK_RENDERER_MAGIC(renderer, retval) \
32 if (!renderer || renderer->magic != &renderer_magic) { \
33 SDL_SetError("Invalid renderer"); \
34 return retval; \
35 }
36
37 #define CHECK_TEXTURE_MAGIC(texture, retval) \
38 if (!texture || texture->magic != &texture_magic) { \
39 SDL_SetError("Invalid texture"); \
40 return retval; \
41 }
42
43
44 static const SDL_RenderDriver *render_drivers[] = {
45 #if SDL_VIDEO_RENDER_D3D
46 &D3D_RenderDriver,
47 #endif
48 #if SDL_VIDEO_RENDER_OGL
49 &GL_RenderDriver,
50 #endif
51 #if SDL_VIDEO_RENDER_OGL_ES
52 &GL_ES_RenderDriver,
53 #endif
54 &SW_RenderDriver
55 };
56 static char renderer_magic;
57 static char texture_magic;
58
59 int
60 SDL_GetNumRenderDrivers(void)
61 {
62 return SDL_arraysize(render_drivers);
63 }
64
65 int
66 SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info)
67 {
68 if (index < 0 || index >= SDL_GetNumRenderDrivers()) {
69 SDL_SetError("index must be in the range of 0 - %d",
70 SDL_GetNumRenderDrivers() - 1);
71 return -1;
72 }
73 *info = render_drivers[index]->info;
74 return 0;
75 }
76
77 static int
78 SDL_RendererEventWatch(void *userdata, SDL_Event *event)
79 {
80 SDL_Renderer *renderer = (SDL_Renderer *)userdata;
81
82 if (event->type == SDL_WINDOWEVENT && renderer->WindowEvent) {
83 SDL_Window *window = SDL_GetWindowFromID(event->window.windowID);
84 if (window == renderer->window) {
85 renderer->WindowEvent(renderer, &event->window);
86 }
87 }
88 return 0;
89 }
90
91 SDL_Renderer *
92 SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags)
93 {
94 SDL_Renderer *renderer = NULL;
95 int n = SDL_GetNumRenderDrivers();
96
97 if (index < 0) {
98 char *override = SDL_getenv("SDL_VIDEO_RENDERER");
99
100 if (override) {
101 for (index = 0; index < n; ++index) {
102 const SDL_RenderDriver *driver = render_drivers[index];
103
104 if (SDL_strcasecmp(override, driver->info.name) == 0) {
105 /* Create a new renderer instance */
106 renderer = driver->CreateRenderer(window, flags);
107 break;
108 }
109 }
110 } else {
111 for (index = 0; index < n; ++index) {
112 const SDL_RenderDriver *driver = render_drivers[index];
113
114 if ((driver->info.flags & flags) == flags) {
115 /* Create a new renderer instance */
116 renderer = driver->CreateRenderer(window, flags);
117 if (renderer) {
118 /* Yay, we got one! */
119 break;
120 }
121 }
122 }
123 }
124 if (index == n) {
125 SDL_SetError("Couldn't find matching render driver");
126 return NULL;
127 }
128 } else {
129 if (index >= SDL_GetNumRenderDrivers()) {
130 SDL_SetError("index must be -1 or in the range of 0 - %d",
131 SDL_GetNumRenderDrivers() - 1);
132 return NULL;
133 }
134 /* Create a new renderer instance */
135 renderer = render_drivers[index]->CreateRenderer(window, flags);
136 }
137
138 if (renderer) {
139 renderer->magic = &renderer_magic;
140
141 SDL_AddEventWatch(SDL_RendererEventWatch, renderer);
142 }
143 return renderer;
144 }
145
146 int
147 SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info)
148 {
149 CHECK_RENDERER_MAGIC(renderer, -1);
150
151 *info = renderer->info;
152 return 0;
153 }
154
155 SDL_Texture *
156 SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h)
157 {
158 SDL_Texture *texture;
159
160 CHECK_RENDERER_MAGIC(renderer, NULL);
161
162 if (w <= 0 || h <= 0) {
163 SDL_SetError("Texture dimensions can't be 0");
164 return 0;
165 }
166 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture));
167 if (!texture) {
168 SDL_OutOfMemory();
169 return 0;
170 }
171 texture->magic = &texture_magic;
172 texture->format = format;
173 texture->access = access;
174 texture->w = w;
175 texture->h = h;
176 texture->r = 255;
177 texture->g = 255;
178 texture->b = 255;
179 texture->a = 255;
180 texture->renderer = renderer;
181 texture->next = renderer->textures;
182 if (renderer->textures) {
183 renderer->textures->prev = texture;
184 }
185 renderer->textures = texture;
186
187 if (renderer->CreateTexture(renderer, texture) < 0) {
188 SDL_DestroyTexture(texture);
189 return 0;
190 }
191 return texture;
192 }
193
194 SDL_Texture *
195 SDL_CreateTextureFromSurface(SDL_Renderer * renderer, Uint32 format, SDL_Surface * surface)
196 {
197 SDL_Texture *texture;
198 Uint32 requested_format = format;
199 SDL_PixelFormat *fmt;
200 int bpp;
201 Uint32 Rmask, Gmask, Bmask, Amask;
202
203 CHECK_RENDERER_MAGIC(renderer, NULL);
204
205 if (!surface) {
206 SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface");
207 return NULL;
208 }
209 fmt = surface->format;
210
211 if (format) {
212 if (!SDL_PixelFormatEnumToMasks
213 (format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) {
214 SDL_SetError("Unknown pixel format");
215 return 0;
216 }
217 } else {
218 SDL_bool hasColorkey;
219 SDL_BlendMode blendMode;
220 SDL_bool hasBlending;
221
222 hasColorkey = (SDL_GetColorKey(surface, NULL) == 0);
223
224 SDL_GetSurfaceBlendMode(surface, &blendMode);
225 hasBlending = (blendMode == SDL_BLENDMODE_BLEND);
226
227 if (surface->format->Amask || (!hasColorkey && !hasBlending)) {
228 Uint32 it;
229 int pfmt;
230
231 /* Pixel formats, sorted by best first */
232 static const Uint32 sdl_pformats[] = {
233 SDL_PIXELFORMAT_ARGB8888,
234 SDL_PIXELFORMAT_RGBA8888,
235 SDL_PIXELFORMAT_ABGR8888,
236 SDL_PIXELFORMAT_BGRA8888,
237 SDL_PIXELFORMAT_RGB888,
238 SDL_PIXELFORMAT_BGR888,
239 SDL_PIXELFORMAT_RGB24,
240 SDL_PIXELFORMAT_BGR24,
241 SDL_PIXELFORMAT_RGB565,
242 SDL_PIXELFORMAT_BGR565,
243 SDL_PIXELFORMAT_ARGB1555,
244 SDL_PIXELFORMAT_RGBA5551,
245 SDL_PIXELFORMAT_ABGR1555,
246 SDL_PIXELFORMAT_BGRA5551,
247 SDL_PIXELFORMAT_RGB555,
248 SDL_PIXELFORMAT_BGR555,
249 SDL_PIXELFORMAT_ARGB4444,
250 SDL_PIXELFORMAT_RGBA4444,
251 SDL_PIXELFORMAT_ABGR4444,
252 SDL_PIXELFORMAT_BGRA4444,
253 SDL_PIXELFORMAT_RGB444,
254 SDL_PIXELFORMAT_ARGB2101010,
255 SDL_PIXELFORMAT_RGB332,
256 SDL_PIXELFORMAT_UNKNOWN
257 };
258
259 bpp = fmt->BitsPerPixel;
260 Rmask = fmt->Rmask;
261 Gmask = fmt->Gmask;
262 Bmask = fmt->Bmask;
263 Amask = fmt->Amask;
264
265 format =
266 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
267 if (!format) {
268 SDL_SetError("Unknown pixel format");
269 return 0;
270 }
271
272 /* Search requested format in the supported texture */
273 /* formats by current renderer */
274 for (it = 0; it < renderer->info.num_texture_formats; it++) {
275 if (renderer->info.texture_formats[it] == format) {
276 break;
277 }
278 }
279
280 /* If requested format can't be found, search any best */
281 /* format which renderer provides */
282 if (it == renderer->info.num_texture_formats) {
283 pfmt = 0;
284 for (;;) {
285 if (sdl_pformats[pfmt] == SDL_PIXELFORMAT_UNKNOWN) {
286 break;
287 }
288
289 for (it = 0; it < renderer->info.num_texture_formats;
290 it++) {
291 if (renderer->info.texture_formats[it] ==
292 sdl_pformats[pfmt]) {
293 break;
294 }
295 }
296
297 if (it != renderer->info.num_texture_formats) {
298 /* The best format has been found */
299 break;
300 }
301 pfmt++;
302 }
303
304 /* If any format can't be found, then return an error */
305 if (it == renderer->info.num_texture_formats) {
306 SDL_SetError
307 ("Any of the supported pixel formats can't be found");
308 return 0;
309 }
310
311 /* Convert found pixel format back to color masks */
312 if (SDL_PixelFormatEnumToMasks
313 (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
314 &Bmask, &Amask) != SDL_TRUE) {
315 SDL_SetError("Unknown pixel format");
316 return 0;
317 }
318 }
319 } else {
320 /* Need a format with alpha */
321 Uint32 it;
322 int apfmt;
323
324 /* Pixel formats with alpha, sorted by best first */
325 static const Uint32 sdl_alpha_pformats[] = {
326 SDL_PIXELFORMAT_ARGB8888,
327 SDL_PIXELFORMAT_RGBA8888,
328 SDL_PIXELFORMAT_ABGR8888,
329 SDL_PIXELFORMAT_BGRA8888,
330 SDL_PIXELFORMAT_ARGB1555,
331 SDL_PIXELFORMAT_RGBA5551,
332 SDL_PIXELFORMAT_ABGR1555,
333 SDL_PIXELFORMAT_BGRA5551,
334 SDL_PIXELFORMAT_ARGB4444,
335 SDL_PIXELFORMAT_RGBA4444,
336 SDL_PIXELFORMAT_ABGR4444,
337 SDL_PIXELFORMAT_BGRA4444,
338 SDL_PIXELFORMAT_ARGB2101010,
339 SDL_PIXELFORMAT_UNKNOWN
340 };
341
342 if (surface->format->Amask) {
343 /* If surface already has alpha, then try an original */
344 /* surface format first */
345 bpp = fmt->BitsPerPixel;
346 Rmask = fmt->Rmask;
347 Gmask = fmt->Gmask;
348 Bmask = fmt->Bmask;
349 Amask = fmt->Amask;
350 } else {
351 bpp = 32;
352 Rmask = 0x00FF0000;
353 Gmask = 0x0000FF00;
354 Bmask = 0x000000FF;
355 Amask = 0xFF000000;
356 }
357
358 format =
359 SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
360 if (!format) {
361 SDL_SetError("Unknown pixel format");
362 return 0;
363 }
364
365 /* Search this format in the supported texture formats */
366 /* by current renderer */
367 for (it = 0; it < renderer->info.num_texture_formats; it++) {
368 if (renderer->info.texture_formats[it] == format) {
369 break;
370 }
371 }
372
373 /* If this format can't be found, search any best */
374 /* compatible format with alpha which renderer provides */
375 if (it == renderer->info.num_texture_formats) {
376 apfmt = 0;
377 for (;;) {
378 if (sdl_alpha_pformats[apfmt] == SDL_PIXELFORMAT_UNKNOWN) {
379 break;
380 }
381
382 for (it = 0; it < renderer->info.num_texture_formats;
383 it++) {
384 if (renderer->info.texture_formats[it] ==
385 sdl_alpha_pformats[apfmt]) {
386 break;
387 }
388 }
389
390 if (it != renderer->info.num_texture_formats) {
391 /* Compatible format has been found */
392 break;
393 }
394 apfmt++;
395 }
396
397 /* If compatible format can't be found, then return an error */
398 if (it == renderer->info.num_texture_formats) {
399 SDL_SetError("Compatible pixel format can't be found");
400 return 0;
401 }
402
403 /* Convert found pixel format back to color masks */
404 if (SDL_PixelFormatEnumToMasks
405 (renderer->info.texture_formats[it], &bpp, &Rmask, &Gmask,
406 &Bmask, &Amask) != SDL_TRUE) {
407 SDL_SetError("Unknown pixel format");
408 return 0;
409 }
410 }
411 }
412
413 format = SDL_MasksToPixelFormatEnum(bpp, Rmask, Gmask, Bmask, Amask);
414 if (!format) {
415 SDL_SetError("Unknown pixel format");
416 return 0;
417 }
418 }
419
420 texture =
421 SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
422 surface->w, surface->h);
423 if (!texture && !requested_format) {
424 SDL_DisplayMode desktop_mode;
425 SDL_GetDesktopDisplayMode(&desktop_mode);
426 format = desktop_mode.format;
427 texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC,
428 surface->w, surface->h);
429 }
430 if (!texture) {
431 return 0;
432 }
433 if (bpp == fmt->BitsPerPixel && Rmask == fmt->Rmask && Gmask == fmt->Gmask
434 && Bmask == fmt->Bmask && Amask == fmt->Amask) {
435 if (SDL_MUSTLOCK(surface)) {
436 SDL_LockSurface(surface);
437 SDL_UpdateTexture(texture, NULL, surface->pixels,
438 surface->pitch);
439 SDL_UnlockSurface(surface);
440 } else {
441 SDL_UpdateTexture(texture, NULL, surface->pixels,
442 surface->pitch);
443 }
444 } else {
445 SDL_PixelFormat dst_fmt;
446 SDL_Surface *dst = NULL;
447
448 /* Set up a destination surface for the texture update */
449 SDL_InitFormat(&dst_fmt, bpp, Rmask, Gmask, Bmask, Amask);
450 dst = SDL_ConvertSurface(surface, &dst_fmt, 0);
451 if (dst) {
452 SDL_UpdateTexture(texture, NULL, dst->pixels, dst->pitch);
453 SDL_FreeSurface(dst);
454 }
455 if (!dst) {
456 SDL_DestroyTexture(texture);
457 return 0;
458 }
459 }
460
461 {
462 Uint8 r, g, b, a;
463 SDL_BlendMode blendMode;
464
465 SDL_GetSurfaceColorMod(surface, &r, &g, &b);
466 SDL_SetTextureColorMod(texture, r, g, b);
467
468 SDL_GetSurfaceAlphaMod(surface, &a);
469 SDL_SetTextureAlphaMod(texture, a);
470
471 if (SDL_GetColorKey(surface, NULL) == 0) {
472 /* We converted to a texture with alpha format */
473 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND);
474 } else {
475 SDL_GetSurfaceBlendMode(surface, &blendMode);
476 SDL_SetTextureBlendMode(texture, blendMode);
477 }
478 }
479 return texture;
480 }
481
482 int
483 SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access,
484 int *w, int *h)
485 {
486 CHECK_TEXTURE_MAGIC(texture, -1);
487
488 if (format) {
489 *format = texture->format;
490 }
491 if (access) {
492 *access = texture->access;
493 }
494 if (w) {
495 *w = texture->w;
496 }
497 if (h) {
498 *h = texture->h;
499 }
500 return 0;
501 }
502
503 int
504 SDL_QueryTexturePixels(SDL_Texture * texture, void **pixels, int *pitch)
505 {
506 SDL_Renderer *renderer;
507
508 CHECK_TEXTURE_MAGIC(texture, -1);
509
510 renderer = texture->renderer;
511 if (!renderer->QueryTexturePixels) {
512 SDL_Unsupported();
513 return -1;
514 }
515 return renderer->QueryTexturePixels(renderer, texture, pixels, pitch);
516 }
517
518 int
519 SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b)
520 {
521 SDL_Renderer *renderer;
522
523 CHECK_TEXTURE_MAGIC(texture, -1);
524
525 renderer = texture->renderer;
526 if (r < 255 || g < 255 || b < 255) {
527 texture->modMode |= SDL_TEXTUREMODULATE_COLOR;
528 } else {
529 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR;
530 }
531 texture->r = r;
532 texture->g = g;
533 texture->b = b;
534 if (renderer->SetTextureColorMod) {
535 return renderer->SetTextureColorMod(renderer, texture);
536 } else {
537 return 0;
538 }
539 }
540
541 int
542 SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g,
543 Uint8 * b)
544 {
545 SDL_Renderer *renderer;
546
547 CHECK_TEXTURE_MAGIC(texture, -1);
548
549 renderer = texture->renderer;
550 if (r) {
551 *r = texture->r;
552 }
553 if (g) {
554 *g = texture->g;
555 }
556 if (b) {
557 *b = texture->b;
558 }
559 return 0;
560 }
561
562 int
563 SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha)
564 {
565 SDL_Renderer *renderer;
566
567 CHECK_TEXTURE_MAGIC(texture, -1);
568
569 renderer = texture->renderer;
570 if (alpha < 255) {
571 texture->modMode |= SDL_TEXTUREMODULATE_ALPHA;
572 } else {
573 texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA;
574 }
575 texture->a = alpha;
576 if (renderer->SetTextureAlphaMod) {
577 return renderer->SetTextureAlphaMod(renderer, texture);
578 } else {
579 return 0;
580 }
581 }
582
583 int
584 SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha)
585 {
586 CHECK_TEXTURE_MAGIC(texture, -1);
587
588 if (alpha) {
589 *alpha = texture->a;
590 }
591 return 0;
592 }
593
594 int
595 SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode)
596 {
597 SDL_Renderer *renderer;
598
599 CHECK_TEXTURE_MAGIC(texture, -1);
600
601 renderer = texture->renderer;
602 texture->blendMode = blendMode;
603 if (renderer->SetTextureBlendMode) {
604 return renderer->SetTextureBlendMode(renderer, texture);
605 } else {
606 return 0;
607 }
608 }
609
610 int
611 SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode)
612 {
613 CHECK_TEXTURE_MAGIC(texture, -1);
614
615 if (blendMode) {
616 *blendMode = texture->blendMode;
617 }
618 return 0;
619 }
620
621 int
622 SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect,
623 const void *pixels, int pitch)
624 {
625 SDL_Renderer *renderer;
626 SDL_Rect full_rect;
627
628 CHECK_TEXTURE_MAGIC(texture, -1);
629
630 renderer = texture->renderer;
631 if (!renderer->UpdateTexture) {
632 SDL_Unsupported();
633 return -1;
634 }
635 if (!rect) {
636 full_rect.x = 0;
637 full_rect.y = 0;
638 full_rect.w = texture->w;
639 full_rect.h = texture->h;
640 rect = &full_rect;
641 }
642 return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch);
643 }
644
645 int
646 SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, int markDirty,
647 void **pixels, int *pitch)
648 {
649 SDL_Renderer *renderer;
650 SDL_Rect full_rect;
651
652 CHECK_TEXTURE_MAGIC(texture, -1);
653
654 if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
655 SDL_SetError("SDL_LockTexture(): texture must be streaming");
656 return -1;
657 }
658 renderer = texture->renderer;
659 if (!renderer->LockTexture) {
660 SDL_Unsupported();
661 return -1;
662 }
663 if (!rect) {
664 full_rect.x = 0;
665 full_rect.y = 0;
666 full_rect.w = texture->w;
667 full_rect.h = texture->h;
668 rect = &full_rect;
669 }
670 return renderer->LockTexture(renderer, texture, rect, markDirty, pixels,
671 pitch);
672 }
673
674 void
675 SDL_UnlockTexture(SDL_Texture * texture)
676 {
677 SDL_Renderer *renderer;
678
679 CHECK_TEXTURE_MAGIC(texture, );
680
681 if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
682 return;
683 }
684 renderer = texture->renderer;
685 if (!renderer->UnlockTexture) {
686 return;
687 }
688 renderer->UnlockTexture(renderer, texture);
689 }
690
691 void
692 SDL_DirtyTexture(SDL_Texture * texture, int numrects,
693 const SDL_Rect * rects)
694 {
695 SDL_Renderer *renderer;
696
697 CHECK_TEXTURE_MAGIC(texture, );
698
699 if (texture->access != SDL_TEXTUREACCESS_STREAMING) {
700 return;
701 }
702 renderer = texture->renderer;
703 if (!renderer->DirtyTexture) {
704 return;
705 }
706 renderer->DirtyTexture(renderer, texture, numrects, rects);
707 }
708
709 int
710 SDL_SetRenderDrawColor(SDL_Renderer * renderer,
711 Uint8 r, Uint8 g, Uint8 b, Uint8 a)
712 {
713 CHECK_RENDERER_MAGIC(renderer, -1);
714
715 renderer->r = r;
716 renderer->g = g;
717 renderer->b = b;
718 renderer->a = a;
719 return 0;
720 }
721
722 int
723 SDL_GetRenderDrawColor(SDL_Renderer * renderer,
724 Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a)
725 {
726 CHECK_RENDERER_MAGIC(renderer, -1);
727
728 if (r) {
729 *r = renderer->r;
730 }
731 if (g) {
732 *g = renderer->g;
733 }
734 if (b) {
735 *b = renderer->b;
736 }
737 if (a) {
738 *a = renderer->a;
739 }
740 return 0;
741 }
742
743 int
744 SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
745 {
746 CHECK_RENDERER_MAGIC(renderer, -1);
747
748 renderer->blendMode = blendMode;
749 return 0;
750 }
751
752 int
753 SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode)
754 {
755 CHECK_RENDERER_MAGIC(renderer, -1);
756
757 *blendMode = renderer->blendMode;
758 return 0;
759 }
760
761 int
762 SDL_RenderClear(SDL_Renderer * renderer)
763 {
764 CHECK_RENDERER_MAGIC(renderer, -1);
765
766 if (!renderer->RenderClear) {
767 SDL_BlendMode blendMode = renderer->blendMode;
768 int status;
769
770 if (blendMode >= SDL_BLENDMODE_BLEND) {
771 SDL_SetRenderDrawBlendMode(renderer, SDL_BLENDMODE_NONE);
772 }
773
774 status = SDL_RenderFillRect(renderer, NULL);
775
776 if (blendMode >= SDL_BLENDMODE_BLEND) {
777 SDL_SetRenderDrawBlendMode(renderer, blendMode);
778 }
779 return status;
780 }
781 return renderer->RenderClear(renderer);
782 }
783
784 int
785 SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y)
786 {
787 SDL_Point point;
788
789 point.x = x;
790 point.y = y;
791 return SDL_RenderDrawPoints(renderer, &point, 1);
792 }
793
794 int
795 SDL_RenderDrawPoints(SDL_Renderer * renderer,
796 const SDL_Point * points, int count)
797 {
798 CHECK_RENDERER_MAGIC(renderer, -1);
799
800 if (!points) {
801 SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points");
802 return -1;
803 }
804 if (count < 1) {
805 return 0;
806 }
807 return renderer->RenderDrawPoints(renderer, points, count);
808 }
809
810 int
811 SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2)
812 {
813 SDL_Point points[2];
814
815 points[0].x = x1;
816 points[0].y = y1;
817 points[1].x = x2;
818 points[1].y = y2;
819 return SDL_RenderDrawLines(renderer, points, 2);
820 }
821
822 int
823 SDL_RenderDrawLines(SDL_Renderer * renderer,
824 const SDL_Point * points, int count)
825 {
826 CHECK_RENDERER_MAGIC(renderer, -1);
827
828 if (!points) {
829 SDL_SetError("SDL_RenderDrawLines(): Passed NULL points");
830 return -1;
831 }
832 if (count < 2) {
833 return 0;
834 }
835 return renderer->RenderDrawLines(renderer, points, count);
836 }
837
838 int
839 SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect)
840 {
841 SDL_Rect full_rect;
842 SDL_Point points[5];
843
844 CHECK_RENDERER_MAGIC(renderer, -1);
845
846 /* If 'rect' == NULL, then outline the whole surface */
847 if (!rect) {
848 SDL_Window *window = renderer->window;
849
850 full_rect.x = 0;
851 full_rect.y = 0;
852 SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
853 rect = &full_rect;
854 }
855
856 points[0].x = rect->x;
857 points[0].y = rect->y;
858 points[1].x = rect->x+rect->w-1;
859 points[1].y = rect->y;
860 points[2].x = rect->x+rect->w-1;
861 points[2].y = rect->y+rect->h-1;
862 points[3].x = rect->x;
863 points[3].y = rect->y+rect->h-1;
864 points[4].x = rect->x;
865 points[4].y = rect->y;
866 return SDL_RenderDrawLines(renderer, points, 5);
867 }
868
869 int
870 SDL_RenderDrawRects(SDL_Renderer * renderer,
871 const SDL_Rect ** rects, int count)
872 {
873 int i;
874
875 CHECK_RENDERER_MAGIC(renderer, -1);
876
877 if (!rects) {
878 SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects");
879 return -1;
880 }
881 if (count < 1) {
882 return 0;
883 }
884
885 /* Check for NULL rect, which means fill entire window */
886 for (i = 0; i < count; ++i) {
887 if (SDL_RenderDrawRect(renderer, rects[i]) < 0) {
888 return -1;
889 }
890 }
891 return 0;
892 }
893
894 int
895 SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect)
896 {
897 return SDL_RenderFillRects(renderer, &rect, 1);
898 }
899
900 int
901 SDL_RenderFillRects(SDL_Renderer * renderer,
902 const SDL_Rect ** rects, int count)
903 {
904 int i;
905
906 CHECK_RENDERER_MAGIC(renderer, -1);
907
908 if (!rects) {
909 SDL_SetError("SDL_RenderFillRects(): Passed NULL rects");
910 return -1;
911 }
912 if (count < 1) {
913 return 0;
914 }
915
916 /* Check for NULL rect, which means fill entire window */
917 for (i = 0; i < count; ++i) {
918 if (rects[i] == NULL) {
919 SDL_Window *window = renderer->window;
920 SDL_Rect full_rect;
921 const SDL_Rect *rect;
922
923 full_rect.x = 0;
924 full_rect.y = 0;
925 SDL_GetWindowSize(window, &full_rect.w, &full_rect.h);
926 rect = &full_rect;
927 return renderer->RenderFillRects(renderer, &rect, 1);
928 }
929 }
930 return renderer->RenderFillRects(renderer, rects, count);
931 }
932
933 int
934 SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
935 const SDL_Rect * srcrect, const SDL_Rect * dstrect)
936 {
937 SDL_Window *window;
938 SDL_Rect real_srcrect;
939 SDL_Rect real_dstrect;
940
941 CHECK_RENDERER_MAGIC(renderer, -1);
942 CHECK_TEXTURE_MAGIC(texture, -1);
943
944 if (renderer != texture->renderer) {
945 SDL_SetError("Texture was not created with this renderer");
946 return -1;
947 }
948 window = renderer->window;
949
950 real_srcrect.x = 0;
951 real_srcrect.y = 0;
952 real_srcrect.w = texture->w;
953 real_srcrect.h = texture->h;
954 if (srcrect) {
955 if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) {
956 return 0;
957 }
958 }
959
960 real_dstrect.x = 0;
961 real_dstrect.y = 0;
962 SDL_GetWindowSize(window, &real_dstrect.w, &real_dstrect.h);
963 if (dstrect) {
964 if (!SDL_IntersectRect(dstrect, &real_dstrect, &real_dstrect)) {
965 return 0;
966 }
967 /* Clip srcrect by the same amount as dstrect was clipped */
968 if (dstrect->w != real_dstrect.w) {
969 int deltax = (real_dstrect.x - dstrect->x);
970 int deltaw = (real_dstrect.w - dstrect->w);
971 real_srcrect.x += (deltax * real_srcrect.w) / dstrect->w;
972 real_srcrect.w += (deltaw * real_srcrect.w) / dstrect->w;
973 }
974 if (dstrect->h != real_dstrect.h) {
975 int deltay = (real_dstrect.y - dstrect->y);
976 int deltah = (real_dstrect.h - dstrect->h);
977 real_srcrect.y += (deltay * real_srcrect.h) / dstrect->h;
978 real_srcrect.h += (deltah * real_srcrect.h) / dstrect->h;
979 }
980 }
981
982 return renderer->RenderCopy(renderer, texture, &real_srcrect,
983 &real_dstrect);
984 }
985
986 int
987 SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
988 Uint32 format, void * pixels, int pitch)
989 {
990 SDL_Window *window;
991 SDL_Rect real_rect;
992
993 CHECK_RENDERER_MAGIC(renderer, -1);
994
995 if (!renderer->RenderReadPixels) {
996 SDL_Unsupported();
997 return -1;
998 }
999 window = renderer->window;
1000
1001 if (!format) {
1002 format = SDL_GetWindowPixelFormat(window);
1003 }
1004
1005 real_rect.x = 0;
1006 real_rect.y = 0;
1007 SDL_GetWindowSize(window, &real_rect.w, &real_rect.h);
1008 if (rect) {
1009 if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
1010 return 0;
1011 }
1012 if (real_rect.y > rect->y) {
1013 pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y);
1014 }
1015 if (real_rect.x > rect->x) {
1016 int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window));
1017 pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x);
1018 }
1019 }
1020
1021 return renderer->RenderReadPixels(renderer, &real_rect,
1022 format, pixels, pitch);
1023 }
1024
1025 int
1026 SDL_RenderWritePixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1027 Uint32 format, const void * pixels, int pitch)
1028 {
1029 SDL_Window *window;
1030 SDL_Rect real_rect;
1031
1032 CHECK_RENDERER_MAGIC(renderer, -1);
1033
1034 if (!renderer->RenderWritePixels) {
1035 SDL_Unsupported();
1036 return -1;
1037 }
1038 window = renderer->window;
1039
1040 if (!format) {
1041 format = SDL_GetWindowPixelFormat(window);
1042 }
1043
1044 real_rect.x = 0;
1045 real_rect.y = 0;
1046 SDL_GetWindowSize(window, &real_rect.w, &real_rect.h);
1047 if (rect) {
1048 if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) {
1049 return 0;
1050 }
1051 if (real_rect.y > rect->y) {
1052 pixels = (const Uint8 *)pixels + pitch * (real_rect.y - rect->y);
1053 }
1054 if (real_rect.x > rect->x) {
1055 int bpp = SDL_BYTESPERPIXEL(SDL_GetWindowPixelFormat(window));
1056 pixels = (const Uint8 *)pixels + bpp * (real_rect.x - rect->x);
1057 }
1058 }
1059
1060 return renderer->RenderWritePixels(renderer, &real_rect,
1061 format, pixels, pitch);
1062 }
1063
1064 void
1065 SDL_RenderPresent(SDL_Renderer * renderer)
1066 {
1067 CHECK_RENDERER_MAGIC(renderer, );
1068
1069 renderer->RenderPresent(renderer);
1070 }
1071
1072 void
1073 SDL_DestroyTexture(SDL_Texture * texture)
1074 {
1075 SDL_Renderer *renderer;
1076
1077 CHECK_TEXTURE_MAGIC(texture, );
1078 texture->magic = NULL;
1079
1080 renderer = texture->renderer;
1081 if (texture->next) {
1082 texture->next->prev = texture->prev;
1083 }
1084 if (texture->prev) {
1085 texture->prev->next = texture->next;
1086 } else {
1087 renderer->textures = texture->next;
1088 }
1089
1090 renderer->DestroyTexture(renderer, texture);
1091 SDL_free(texture);
1092 }
1093
1094 void
1095 SDL_DestroyRenderer(SDL_Renderer * renderer)
1096 {
1097 CHECK_RENDERER_MAGIC(renderer, );
1098
1099 SDL_DelEventWatch(SDL_RendererEventWatch, renderer);
1100
1101 /* Free existing textures for this renderer */
1102 while (renderer->textures) {
1103 SDL_DestroyTexture(renderer->textures);
1104 }
1105
1106 /* It's no longer magical... */
1107 renderer->magic = NULL;
1108
1109 /* Free the renderer instance */
1110 renderer->DestroyRenderer(renderer);
1111 }
1112
1113 /* vi: set ts=4 sw=4 expandtab: */