Mercurial > sdl-ios-xcode
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: */ |