SDL_render.c (54178B)
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org> 4 5 This software is provided 'as-is', without any express or implied 6 warranty. In no event will the authors be held liable for any damages 7 arising from the use of this software. 8 9 Permission is granted to anyone to use this software for any purpose, 10 including commercial applications, and to alter it and redistribute it 11 freely, subject to the following restrictions: 12 13 1. The origin of this software must not be misrepresented; you must not 14 claim that you wrote the original software. If you use this software 15 in a product, an acknowledgment in the product documentation would be 16 appreciated but is not required. 17 2. Altered source versions must be plainly marked as such, and must not be 18 misrepresented as being the original software. 19 3. This notice may not be removed or altered from any source distribution. 20*/ 21#include "../SDL_internal.h" 22 23/* The SDL 2D rendering system */ 24 25#include "SDL_assert.h" 26#include "SDL_hints.h" 27#include "SDL_log.h" 28#include "SDL_render.h" 29#include "SDL_sysrender.h" 30#include "software/SDL_render_sw_c.h" 31 32 33#define SDL_WINDOWRENDERDATA "_SDL_WindowRenderData" 34 35#define CHECK_RENDERER_MAGIC(renderer, retval) \ 36 if (!renderer || renderer->magic != &renderer_magic) { \ 37 SDL_SetError("Invalid renderer"); \ 38 return retval; \ 39 } 40 41#define CHECK_TEXTURE_MAGIC(texture, retval) \ 42 if (!texture || texture->magic != &texture_magic) { \ 43 SDL_SetError("Invalid texture"); \ 44 return retval; \ 45 } 46 47 48#if !SDL_RENDER_DISABLED 49static const SDL_RenderDriver *render_drivers[] = { 50#if SDL_VIDEO_RENDER_D3D 51 &D3D_RenderDriver, 52#endif 53#if SDL_VIDEO_RENDER_D3D11 54 &D3D11_RenderDriver, 55#endif 56#if SDL_VIDEO_RENDER_OGL 57 &GL_RenderDriver, 58#endif 59#if SDL_VIDEO_RENDER_OGL_ES2 60 &GLES2_RenderDriver, 61#endif 62#if SDL_VIDEO_RENDER_OGL_ES 63 &GLES_RenderDriver, 64#endif 65#if SDL_VIDEO_RENDER_DIRECTFB 66 &DirectFB_RenderDriver, 67#endif 68#if SDL_VIDEO_RENDER_PSP 69 &PSP_RenderDriver, 70#endif 71 &SW_RenderDriver 72}; 73#endif /* !SDL_RENDER_DISABLED */ 74 75static char renderer_magic; 76static char texture_magic; 77 78static int UpdateLogicalSize(SDL_Renderer *renderer); 79 80int 81SDL_GetNumRenderDrivers(void) 82{ 83#if !SDL_RENDER_DISABLED 84 return SDL_arraysize(render_drivers); 85#else 86 return 0; 87#endif 88} 89 90int 91SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info) 92{ 93#if !SDL_RENDER_DISABLED 94 if (index < 0 || index >= SDL_GetNumRenderDrivers()) { 95 return SDL_SetError("index must be in the range of 0 - %d", 96 SDL_GetNumRenderDrivers() - 1); 97 } 98 *info = render_drivers[index]->info; 99 return 0; 100#else 101 return SDL_SetError("SDL not built with rendering support"); 102#endif 103} 104 105static int 106SDL_RendererEventWatch(void *userdata, SDL_Event *event) 107{ 108 SDL_Renderer *renderer = (SDL_Renderer *)userdata; 109 110 if (event->type == SDL_WINDOWEVENT) { 111 SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); 112 if (window == renderer->window) { 113 if (renderer->WindowEvent) { 114 renderer->WindowEvent(renderer, &event->window); 115 } 116 117 if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { 118 /* Make sure we're operating on the default render target */ 119 SDL_Texture *saved_target = SDL_GetRenderTarget(renderer); 120 if (saved_target) { 121 SDL_SetRenderTarget(renderer, NULL); 122 } 123 124 if (renderer->logical_w) { 125 UpdateLogicalSize(renderer); 126 } else { 127 /* Window was resized, reset viewport */ 128 int w, h; 129 130 if (renderer->GetOutputSize) { 131 renderer->GetOutputSize(renderer, &w, &h); 132 } else { 133 SDL_GetWindowSize(renderer->window, &w, &h); 134 } 135 136 if (renderer->target) { 137 renderer->viewport_backup.x = 0; 138 renderer->viewport_backup.y = 0; 139 renderer->viewport_backup.w = w; 140 renderer->viewport_backup.h = h; 141 } else { 142 renderer->viewport.x = 0; 143 renderer->viewport.y = 0; 144 renderer->viewport.w = w; 145 renderer->viewport.h = h; 146 renderer->UpdateViewport(renderer); 147 } 148 } 149 150 if (saved_target) { 151 SDL_SetRenderTarget(renderer, saved_target); 152 } 153 } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) { 154 renderer->hidden = SDL_TRUE; 155 } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) { 156 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) { 157 renderer->hidden = SDL_FALSE; 158 } 159 } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) { 160 renderer->hidden = SDL_TRUE; 161 } else if (event->window.event == SDL_WINDOWEVENT_RESTORED) { 162 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) { 163 renderer->hidden = SDL_FALSE; 164 } 165 } 166 } 167 } else if (event->type == SDL_MOUSEMOTION) { 168 if (renderer->logical_w) { 169 event->motion.x -= renderer->viewport.x; 170 event->motion.y -= renderer->viewport.y; 171 event->motion.x = (int)(event->motion.x / renderer->scale.x); 172 event->motion.y = (int)(event->motion.y / renderer->scale.y); 173 if (event->motion.xrel > 0) { 174 event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / renderer->scale.x)); 175 } else if (event->motion.xrel < 0) { 176 event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / renderer->scale.x)); 177 } 178 if (event->motion.yrel > 0) { 179 event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / renderer->scale.y)); 180 } else if (event->motion.yrel < 0) { 181 event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / renderer->scale.y)); 182 } 183 } 184 } else if (event->type == SDL_MOUSEBUTTONDOWN || 185 event->type == SDL_MOUSEBUTTONUP) { 186 if (renderer->logical_w) { 187 event->button.x -= renderer->viewport.x; 188 event->button.y -= renderer->viewport.y; 189 event->button.x = (int)(event->button.x / renderer->scale.x); 190 event->button.y = (int)(event->button.y / renderer->scale.y); 191 } 192 } 193 return 0; 194} 195 196int 197SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags, 198 SDL_Window **window, SDL_Renderer **renderer) 199{ 200 *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, 201 SDL_WINDOWPOS_UNDEFINED, 202 width, height, window_flags); 203 if (!*window) { 204 *renderer = NULL; 205 return -1; 206 } 207 208 *renderer = SDL_CreateRenderer(*window, -1, 0); 209 if (!*renderer) { 210 return -1; 211 } 212 213 return 0; 214} 215 216SDL_Renderer * 217SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) 218{ 219#if !SDL_RENDER_DISABLED 220 SDL_Renderer *renderer = NULL; 221 int n = SDL_GetNumRenderDrivers(); 222 const char *hint; 223 224 if (!window) { 225 SDL_SetError("Invalid window"); 226 return NULL; 227 } 228 229 if (SDL_GetRenderer(window)) { 230 SDL_SetError("Renderer already associated with window"); 231 return NULL; 232 } 233 234 hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); 235 if (hint) { 236 if (*hint == '0') { 237 flags &= ~SDL_RENDERER_PRESENTVSYNC; 238 } else { 239 flags |= SDL_RENDERER_PRESENTVSYNC; 240 } 241 } 242 243 if (index < 0) { 244 hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); 245 if (hint) { 246 for (index = 0; index < n; ++index) { 247 const SDL_RenderDriver *driver = render_drivers[index]; 248 249 if (SDL_strcasecmp(hint, driver->info.name) == 0) { 250 /* Create a new renderer instance */ 251 renderer = driver->CreateRenderer(window, flags); 252 break; 253 } 254 } 255 } 256 257 if (!renderer) { 258 for (index = 0; index < n; ++index) { 259 const SDL_RenderDriver *driver = render_drivers[index]; 260 261 if ((driver->info.flags & flags) == flags) { 262 /* Create a new renderer instance */ 263 renderer = driver->CreateRenderer(window, flags); 264 if (renderer) { 265 /* Yay, we got one! */ 266 break; 267 } 268 } 269 } 270 } 271 if (index == n) { 272 SDL_SetError("Couldn't find matching render driver"); 273 return NULL; 274 } 275 } else { 276 if (index >= SDL_GetNumRenderDrivers()) { 277 SDL_SetError("index must be -1 or in the range of 0 - %d", 278 SDL_GetNumRenderDrivers() - 1); 279 return NULL; 280 } 281 /* Create a new renderer instance */ 282 renderer = render_drivers[index]->CreateRenderer(window, flags); 283 } 284 285 if (renderer) { 286 renderer->magic = &renderer_magic; 287 renderer->window = window; 288 renderer->scale.x = 1.0f; 289 renderer->scale.y = 1.0f; 290 291 if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) { 292 renderer->hidden = SDL_TRUE; 293 } else { 294 renderer->hidden = SDL_FALSE; 295 } 296 297 SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer); 298 299 SDL_RenderSetViewport(renderer, NULL); 300 301 SDL_AddEventWatch(SDL_RendererEventWatch, renderer); 302 303 SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, 304 "Created renderer: %s", renderer->info.name); 305 } 306 return renderer; 307#else 308 SDL_SetError("SDL not built with rendering support"); 309 return NULL; 310#endif 311} 312 313SDL_Renderer * 314SDL_CreateSoftwareRenderer(SDL_Surface * surface) 315{ 316#if !SDL_RENDER_DISABLED 317 SDL_Renderer *renderer; 318 319 renderer = SW_CreateRendererForSurface(surface); 320 321 if (renderer) { 322 renderer->magic = &renderer_magic; 323 renderer->scale.x = 1.0f; 324 renderer->scale.y = 1.0f; 325 326 SDL_RenderSetViewport(renderer, NULL); 327 } 328 return renderer; 329#else 330 SDL_SetError("SDL not built with rendering support"); 331 return NULL; 332#endif /* !SDL_RENDER_DISABLED */ 333} 334 335SDL_Renderer * 336SDL_GetRenderer(SDL_Window * window) 337{ 338 return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA); 339} 340 341int 342SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) 343{ 344 CHECK_RENDERER_MAGIC(renderer, -1); 345 346 *info = renderer->info; 347 return 0; 348} 349 350int 351SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h) 352{ 353 CHECK_RENDERER_MAGIC(renderer, -1); 354 355 if (renderer->target) { 356 return SDL_QueryTexture(renderer->target, NULL, NULL, w, h); 357 } else if (renderer->GetOutputSize) { 358 return renderer->GetOutputSize(renderer, w, h); 359 } else if (renderer->window) { 360 SDL_GetWindowSize(renderer->window, w, h); 361 return 0; 362 } else { 363 SDL_assert(0 && "This should never happen"); 364 return SDL_SetError("Renderer doesn't support querying output size"); 365 } 366} 367 368static SDL_bool 369IsSupportedFormat(SDL_Renderer * renderer, Uint32 format) 370{ 371 Uint32 i; 372 373 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 374 if (renderer->info.texture_formats[i] == format) { 375 return SDL_TRUE; 376 } 377 } 378 return SDL_FALSE; 379} 380 381static Uint32 382GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format) 383{ 384 Uint32 i; 385 386 if (SDL_ISPIXELFORMAT_FOURCC(format)) { 387 /* Look for an exact match */ 388 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 389 if (renderer->info.texture_formats[i] == format) { 390 return renderer->info.texture_formats[i]; 391 } 392 } 393 } else { 394 SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format); 395 396 /* We just want to match the first format that has the same channels */ 397 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 398 if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && 399 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) { 400 return renderer->info.texture_formats[i]; 401 } 402 } 403 } 404 return renderer->info.texture_formats[0]; 405} 406 407SDL_Texture * 408SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) 409{ 410 SDL_Texture *texture; 411 412 CHECK_RENDERER_MAGIC(renderer, NULL); 413 414 if (!format) { 415 format = renderer->info.texture_formats[0]; 416 } 417 if (SDL_BYTESPERPIXEL(format) == 0) { 418 SDL_SetError("Invalid texture format"); 419 return NULL; 420 } 421 if (SDL_ISPIXELFORMAT_INDEXED(format)) { 422 SDL_SetError("Palettized textures are not supported"); 423 return NULL; 424 } 425 if (w <= 0 || h <= 0) { 426 SDL_SetError("Texture dimensions can't be 0"); 427 return NULL; 428 } 429 if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) || 430 (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) { 431 SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height); 432 return NULL; 433 } 434 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); 435 if (!texture) { 436 SDL_OutOfMemory(); 437 return NULL; 438 } 439 texture->magic = &texture_magic; 440 texture->format = format; 441 texture->access = access; 442 texture->w = w; 443 texture->h = h; 444 texture->r = 255; 445 texture->g = 255; 446 texture->b = 255; 447 texture->a = 255; 448 texture->renderer = renderer; 449 texture->next = renderer->textures; 450 if (renderer->textures) { 451 renderer->textures->prev = texture; 452 } 453 renderer->textures = texture; 454 455 if (IsSupportedFormat(renderer, format)) { 456 if (renderer->CreateTexture(renderer, texture) < 0) { 457 SDL_DestroyTexture(texture); 458 return 0; 459 } 460 } else { 461 texture->native = SDL_CreateTexture(renderer, 462 GetClosestSupportedFormat(renderer, format), 463 access, w, h); 464 if (!texture->native) { 465 SDL_DestroyTexture(texture); 466 return NULL; 467 } 468 469 /* Swap textures to have texture before texture->native in the list */ 470 texture->native->next = texture->next; 471 if (texture->native->next) { 472 texture->native->next->prev = texture->native; 473 } 474 texture->prev = texture->native->prev; 475 if (texture->prev) { 476 texture->prev->next = texture; 477 } 478 texture->native->prev = texture; 479 texture->next = texture->native; 480 renderer->textures = texture; 481 482 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { 483 texture->yuv = SDL_SW_CreateYUVTexture(format, w, h); 484 if (!texture->yuv) { 485 SDL_DestroyTexture(texture); 486 return NULL; 487 } 488 } else if (access == SDL_TEXTUREACCESS_STREAMING) { 489 /* The pitch is 4 byte aligned */ 490 texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); 491 texture->pixels = SDL_calloc(1, texture->pitch * h); 492 if (!texture->pixels) { 493 SDL_DestroyTexture(texture); 494 return NULL; 495 } 496 } 497 } 498 return texture; 499} 500 501SDL_Texture * 502SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface) 503{ 504 const SDL_PixelFormat *fmt; 505 SDL_bool needAlpha; 506 Uint32 i; 507 Uint32 format; 508 SDL_Texture *texture; 509 510 CHECK_RENDERER_MAGIC(renderer, NULL); 511 512 if (!surface) { 513 SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); 514 return NULL; 515 } 516 517 /* See what the best texture format is */ 518 fmt = surface->format; 519 if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) { 520 needAlpha = SDL_TRUE; 521 } else { 522 needAlpha = SDL_FALSE; 523 } 524 format = renderer->info.texture_formats[0]; 525 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 526 if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && 527 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) { 528 format = renderer->info.texture_formats[i]; 529 break; 530 } 531 } 532 533 texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, 534 surface->w, surface->h); 535 if (!texture) { 536 return NULL; 537 } 538 539 if (format == surface->format->format) { 540 if (SDL_MUSTLOCK(surface)) { 541 SDL_LockSurface(surface); 542 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); 543 SDL_UnlockSurface(surface); 544 } else { 545 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); 546 } 547 } else { 548 SDL_PixelFormat *dst_fmt; 549 SDL_Surface *temp = NULL; 550 551 /* Set up a destination surface for the texture update */ 552 dst_fmt = SDL_AllocFormat(format); 553 if (!dst_fmt) { 554 SDL_DestroyTexture(texture); 555 return NULL; 556 } 557 temp = SDL_ConvertSurface(surface, dst_fmt, 0); 558 SDL_FreeFormat(dst_fmt); 559 if (temp) { 560 SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); 561 SDL_FreeSurface(temp); 562 } else { 563 SDL_DestroyTexture(texture); 564 return NULL; 565 } 566 } 567 568 { 569 Uint8 r, g, b, a; 570 SDL_BlendMode blendMode; 571 572 SDL_GetSurfaceColorMod(surface, &r, &g, &b); 573 SDL_SetTextureColorMod(texture, r, g, b); 574 575 SDL_GetSurfaceAlphaMod(surface, &a); 576 SDL_SetTextureAlphaMod(texture, a); 577 578 if (SDL_GetColorKey(surface, NULL) == 0) { 579 /* We converted to a texture with alpha format */ 580 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 581 } else { 582 SDL_GetSurfaceBlendMode(surface, &blendMode); 583 SDL_SetTextureBlendMode(texture, blendMode); 584 } 585 } 586 return texture; 587} 588 589int 590SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access, 591 int *w, int *h) 592{ 593 CHECK_TEXTURE_MAGIC(texture, -1); 594 595 if (format) { 596 *format = texture->format; 597 } 598 if (access) { 599 *access = texture->access; 600 } 601 if (w) { 602 *w = texture->w; 603 } 604 if (h) { 605 *h = texture->h; 606 } 607 return 0; 608} 609 610int 611SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b) 612{ 613 SDL_Renderer *renderer; 614 615 CHECK_TEXTURE_MAGIC(texture, -1); 616 617 renderer = texture->renderer; 618 if (r < 255 || g < 255 || b < 255) { 619 texture->modMode |= SDL_TEXTUREMODULATE_COLOR; 620 } else { 621 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR; 622 } 623 texture->r = r; 624 texture->g = g; 625 texture->b = b; 626 if (texture->native) { 627 return SDL_SetTextureColorMod(texture->native, r, g, b); 628 } else if (renderer->SetTextureColorMod) { 629 return renderer->SetTextureColorMod(renderer, texture); 630 } else { 631 return 0; 632 } 633} 634 635int 636SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g, 637 Uint8 * b) 638{ 639 CHECK_TEXTURE_MAGIC(texture, -1); 640 641 if (r) { 642 *r = texture->r; 643 } 644 if (g) { 645 *g = texture->g; 646 } 647 if (b) { 648 *b = texture->b; 649 } 650 return 0; 651} 652 653int 654SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha) 655{ 656 SDL_Renderer *renderer; 657 658 CHECK_TEXTURE_MAGIC(texture, -1); 659 660 renderer = texture->renderer; 661 if (alpha < 255) { 662 texture->modMode |= SDL_TEXTUREMODULATE_ALPHA; 663 } else { 664 texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA; 665 } 666 texture->a = alpha; 667 if (texture->native) { 668 return SDL_SetTextureAlphaMod(texture->native, alpha); 669 } else if (renderer->SetTextureAlphaMod) { 670 return renderer->SetTextureAlphaMod(renderer, texture); 671 } else { 672 return 0; 673 } 674} 675 676int 677SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha) 678{ 679 CHECK_TEXTURE_MAGIC(texture, -1); 680 681 if (alpha) { 682 *alpha = texture->a; 683 } 684 return 0; 685} 686 687int 688SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode) 689{ 690 SDL_Renderer *renderer; 691 692 CHECK_TEXTURE_MAGIC(texture, -1); 693 694 renderer = texture->renderer; 695 texture->blendMode = blendMode; 696 if (texture->native) { 697 return SDL_SetTextureBlendMode(texture->native, blendMode); 698 } else if (renderer->SetTextureBlendMode) { 699 return renderer->SetTextureBlendMode(renderer, texture); 700 } else { 701 return 0; 702 } 703} 704 705int 706SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode) 707{ 708 CHECK_TEXTURE_MAGIC(texture, -1); 709 710 if (blendMode) { 711 *blendMode = texture->blendMode; 712 } 713 return 0; 714} 715 716static int 717SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, 718 const void *pixels, int pitch) 719{ 720 SDL_Texture *native = texture->native; 721 SDL_Rect full_rect; 722 723 if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) { 724 return -1; 725 } 726 727 full_rect.x = 0; 728 full_rect.y = 0; 729 full_rect.w = texture->w; 730 full_rect.h = texture->h; 731 rect = &full_rect; 732 733 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 734 /* We can lock the texture and copy to it */ 735 void *native_pixels; 736 int native_pitch; 737 738 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 739 return -1; 740 } 741 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 742 rect->w, rect->h, native_pixels, native_pitch); 743 SDL_UnlockTexture(native); 744 } else { 745 /* Use a temporary buffer for updating */ 746 void *temp_pixels; 747 int temp_pitch; 748 749 temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 750 temp_pixels = SDL_malloc(rect->h * temp_pitch); 751 if (!temp_pixels) { 752 return SDL_OutOfMemory(); 753 } 754 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 755 rect->w, rect->h, temp_pixels, temp_pitch); 756 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 757 SDL_free(temp_pixels); 758 } 759 return 0; 760} 761 762static int 763SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect, 764 const void *pixels, int pitch) 765{ 766 SDL_Texture *native = texture->native; 767 768 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 769 /* We can lock the texture and copy to it */ 770 void *native_pixels; 771 int native_pitch; 772 773 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 774 return -1; 775 } 776 SDL_ConvertPixels(rect->w, rect->h, 777 texture->format, pixels, pitch, 778 native->format, native_pixels, native_pitch); 779 SDL_UnlockTexture(native); 780 } else { 781 /* Use a temporary buffer for updating */ 782 void *temp_pixels; 783 int temp_pitch; 784 785 temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 786 temp_pixels = SDL_malloc(rect->h * temp_pitch); 787 if (!temp_pixels) { 788 return SDL_OutOfMemory(); 789 } 790 SDL_ConvertPixels(rect->w, rect->h, 791 texture->format, pixels, pitch, 792 native->format, temp_pixels, temp_pitch); 793 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 794 SDL_free(temp_pixels); 795 } 796 return 0; 797} 798 799int 800SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, 801 const void *pixels, int pitch) 802{ 803 SDL_Renderer *renderer; 804 SDL_Rect full_rect; 805 806 CHECK_TEXTURE_MAGIC(texture, -1); 807 808 if (!pixels) { 809 return SDL_InvalidParamError("pixels"); 810 } 811 if (!pitch) { 812 return SDL_InvalidParamError("pitch"); 813 } 814 815 if (!rect) { 816 full_rect.x = 0; 817 full_rect.y = 0; 818 full_rect.w = texture->w; 819 full_rect.h = texture->h; 820 rect = &full_rect; 821 } 822 823 if (texture->yuv) { 824 return SDL_UpdateTextureYUV(texture, rect, pixels, pitch); 825 } else if (texture->native) { 826 return SDL_UpdateTextureNative(texture, rect, pixels, pitch); 827 } else { 828 renderer = texture->renderer; 829 return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); 830 } 831} 832 833static int 834SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect, 835 const Uint8 *Yplane, int Ypitch, 836 const Uint8 *Uplane, int Upitch, 837 const Uint8 *Vplane, int Vpitch) 838{ 839 SDL_Texture *native = texture->native; 840 SDL_Rect full_rect; 841 842 if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) { 843 return -1; 844 } 845 846 full_rect.x = 0; 847 full_rect.y = 0; 848 full_rect.w = texture->w; 849 full_rect.h = texture->h; 850 rect = &full_rect; 851 852 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 853 /* We can lock the texture and copy to it */ 854 void *native_pixels; 855 int native_pitch; 856 857 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 858 return -1; 859 } 860 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 861 rect->w, rect->h, native_pixels, native_pitch); 862 SDL_UnlockTexture(native); 863 } else { 864 /* Use a temporary buffer for updating */ 865 void *temp_pixels; 866 int temp_pitch; 867 868 temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 869 temp_pixels = SDL_malloc(rect->h * temp_pitch); 870 if (!temp_pixels) { 871 return SDL_OutOfMemory(); 872 } 873 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 874 rect->w, rect->h, temp_pixels, temp_pitch); 875 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 876 SDL_free(temp_pixels); 877 } 878 return 0; 879} 880 881int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect, 882 const Uint8 *Yplane, int Ypitch, 883 const Uint8 *Uplane, int Upitch, 884 const Uint8 *Vplane, int Vpitch) 885{ 886 SDL_Renderer *renderer; 887 SDL_Rect full_rect; 888 889 CHECK_TEXTURE_MAGIC(texture, -1); 890 891 if (!Yplane) { 892 return SDL_InvalidParamError("Yplane"); 893 } 894 if (!Ypitch) { 895 return SDL_InvalidParamError("Ypitch"); 896 } 897 if (!Uplane) { 898 return SDL_InvalidParamError("Uplane"); 899 } 900 if (!Upitch) { 901 return SDL_InvalidParamError("Upitch"); 902 } 903 if (!Vplane) { 904 return SDL_InvalidParamError("Vplane"); 905 } 906 if (!Vpitch) { 907 return SDL_InvalidParamError("Vpitch"); 908 } 909 910 if (texture->format != SDL_PIXELFORMAT_YV12 && 911 texture->format != SDL_PIXELFORMAT_IYUV) { 912 return SDL_SetError("Texture format must by YV12 or IYUV"); 913 } 914 915 if (!rect) { 916 full_rect.x = 0; 917 full_rect.y = 0; 918 full_rect.w = texture->w; 919 full_rect.h = texture->h; 920 rect = &full_rect; 921 } 922 923 if (texture->yuv) { 924 return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); 925 } else { 926 SDL_assert(!texture->native); 927 renderer = texture->renderer; 928 SDL_assert(renderer->UpdateTextureYUV); 929 if (renderer->UpdateTextureYUV) { 930 return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); 931 } else { 932 return SDL_Unsupported(); 933 } 934 } 935} 936 937static int 938SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, 939 void **pixels, int *pitch) 940{ 941 return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch); 942} 943 944static int 945SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect, 946 void **pixels, int *pitch) 947{ 948 texture->locked_rect = *rect; 949 *pixels = (void *) ((Uint8 *) texture->pixels + 950 rect->y * texture->pitch + 951 rect->x * SDL_BYTESPERPIXEL(texture->format)); 952 *pitch = texture->pitch; 953 return 0; 954} 955 956int 957SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, 958 void **pixels, int *pitch) 959{ 960 SDL_Renderer *renderer; 961 SDL_Rect full_rect; 962 963 CHECK_TEXTURE_MAGIC(texture, -1); 964 965 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { 966 return SDL_SetError("SDL_LockTexture(): texture must be streaming"); 967 } 968 969 if (!rect) { 970 full_rect.x = 0; 971 full_rect.y = 0; 972 full_rect.w = texture->w; 973 full_rect.h = texture->h; 974 rect = &full_rect; 975 } 976 977 if (texture->yuv) { 978 return SDL_LockTextureYUV(texture, rect, pixels, pitch); 979 } else if (texture->native) { 980 return SDL_LockTextureNative(texture, rect, pixels, pitch); 981 } else { 982 renderer = texture->renderer; 983 return renderer->LockTexture(renderer, texture, rect, pixels, pitch); 984 } 985} 986 987static void 988SDL_UnlockTextureYUV(SDL_Texture * texture) 989{ 990 SDL_Texture *native = texture->native; 991 void *native_pixels = NULL; 992 int native_pitch = 0; 993 SDL_Rect rect; 994 995 rect.x = 0; 996 rect.y = 0; 997 rect.w = texture->w; 998 rect.h = texture->h; 999 1000 if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) { 1001 return; 1002 } 1003 SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format, 1004 rect.w, rect.h, native_pixels, native_pitch); 1005 SDL_UnlockTexture(native); 1006} 1007 1008static void 1009SDL_UnlockTextureNative(SDL_Texture * texture) 1010{ 1011 SDL_Texture *native = texture->native; 1012 void *native_pixels = NULL; 1013 int native_pitch = 0; 1014 const SDL_Rect *rect = &texture->locked_rect; 1015 const void* pixels = (void *) ((Uint8 *) texture->pixels + 1016 rect->y * texture->pitch + 1017 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1018 int pitch = texture->pitch; 1019 1020 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 1021 return; 1022 } 1023 SDL_ConvertPixels(rect->w, rect->h, 1024 texture->format, pixels, pitch, 1025 native->format, native_pixels, native_pitch); 1026 SDL_UnlockTexture(native); 1027} 1028 1029void 1030SDL_UnlockTexture(SDL_Texture * texture) 1031{ 1032 SDL_Renderer *renderer; 1033 1034 CHECK_TEXTURE_MAGIC(texture, ); 1035 1036 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { 1037 return; 1038 } 1039 if (texture->yuv) { 1040 SDL_UnlockTextureYUV(texture); 1041 } else if (texture->native) { 1042 SDL_UnlockTextureNative(texture); 1043 } else { 1044 renderer = texture->renderer; 1045 renderer->UnlockTexture(renderer, texture); 1046 } 1047} 1048 1049SDL_bool 1050SDL_RenderTargetSupported(SDL_Renderer *renderer) 1051{ 1052 if (!renderer || !renderer->SetRenderTarget) { 1053 return SDL_FALSE; 1054 } 1055 return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0; 1056} 1057 1058int 1059SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 1060{ 1061 if (!SDL_RenderTargetSupported(renderer)) { 1062 return SDL_Unsupported(); 1063 } 1064 if (texture == renderer->target) { 1065 /* Nothing to do! */ 1066 return 0; 1067 } 1068 1069 /* texture == NULL is valid and means reset the target to the window */ 1070 if (texture) { 1071 CHECK_TEXTURE_MAGIC(texture, -1); 1072 if (renderer != texture->renderer) { 1073 return SDL_SetError("Texture was not created with this renderer"); 1074 } 1075 if (texture->access != SDL_TEXTUREACCESS_TARGET) { 1076 return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET"); 1077 } 1078 if (texture->native) { 1079 /* Always render to the native texture */ 1080 texture = texture->native; 1081 } 1082 } 1083 1084 if (texture && !renderer->target) { 1085 /* Make a backup of the viewport */ 1086 renderer->viewport_backup = renderer->viewport; 1087 renderer->clip_rect_backup = renderer->clip_rect; 1088 renderer->clipping_enabled_backup = renderer->clipping_enabled; 1089 renderer->scale_backup = renderer->scale; 1090 renderer->logical_w_backup = renderer->logical_w; 1091 renderer->logical_h_backup = renderer->logical_h; 1092 } 1093 renderer->target = texture; 1094 1095 if (renderer->SetRenderTarget(renderer, texture) < 0) { 1096 return -1; 1097 } 1098 1099 if (texture) { 1100 renderer->viewport.x = 0; 1101 renderer->viewport.y = 0; 1102 renderer->viewport.w = texture->w; 1103 renderer->viewport.h = texture->h; 1104 renderer->scale.x = 1.0f; 1105 renderer->scale.y = 1.0f; 1106 renderer->logical_w = texture->w; 1107 renderer->logical_h = texture->h; 1108 } else { 1109 renderer->viewport = renderer->viewport_backup; 1110 renderer->clip_rect = renderer->clip_rect_backup; 1111 renderer->clipping_enabled = renderer->clipping_enabled_backup; 1112 renderer->scale = renderer->scale_backup; 1113 renderer->logical_w = renderer->logical_w_backup; 1114 renderer->logical_h = renderer->logical_h_backup; 1115 } 1116 if (renderer->UpdateViewport(renderer) < 0) { 1117 return -1; 1118 } 1119 if (renderer->UpdateClipRect(renderer) < 0) { 1120 return -1; 1121 } 1122 1123 /* All set! */ 1124 return 0; 1125} 1126 1127SDL_Texture * 1128SDL_GetRenderTarget(SDL_Renderer *renderer) 1129{ 1130 return renderer->target; 1131} 1132 1133static int 1134UpdateLogicalSize(SDL_Renderer *renderer) 1135{ 1136 int w = 1, h = 1; 1137 float want_aspect; 1138 float real_aspect; 1139 float scale; 1140 SDL_Rect viewport; 1141 1142 if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { 1143 return -1; 1144 } 1145 1146 want_aspect = (float)renderer->logical_w / renderer->logical_h; 1147 real_aspect = (float)w / h; 1148 1149 /* Clear the scale because we're setting viewport in output coordinates */ 1150 SDL_RenderSetScale(renderer, 1.0f, 1.0f); 1151 1152 if (SDL_fabs(want_aspect-real_aspect) < 0.0001) { 1153 /* The aspect ratios are the same, just scale appropriately */ 1154 scale = (float)w / renderer->logical_w; 1155 SDL_RenderSetViewport(renderer, NULL); 1156 } else if (want_aspect > real_aspect) { 1157 /* We want a wider aspect ratio than is available - letterbox it */ 1158 scale = (float)w / renderer->logical_w; 1159 viewport.x = 0; 1160 viewport.w = w; 1161 viewport.h = (int)SDL_ceil(renderer->logical_h * scale); 1162 viewport.y = (h - viewport.h) / 2; 1163 SDL_RenderSetViewport(renderer, &viewport); 1164 } else { 1165 /* We want a narrower aspect ratio than is available - use side-bars */ 1166 scale = (float)h / renderer->logical_h; 1167 viewport.y = 0; 1168 viewport.h = h; 1169 viewport.w = (int)SDL_ceil(renderer->logical_w * scale); 1170 viewport.x = (w - viewport.w) / 2; 1171 SDL_RenderSetViewport(renderer, &viewport); 1172 } 1173 1174 /* Set the new scale */ 1175 SDL_RenderSetScale(renderer, scale, scale); 1176 1177 return 0; 1178} 1179 1180int 1181SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h) 1182{ 1183 CHECK_RENDERER_MAGIC(renderer, -1); 1184 1185 if (!w || !h) { 1186 /* Clear any previous logical resolution */ 1187 renderer->logical_w = 0; 1188 renderer->logical_h = 0; 1189 SDL_RenderSetViewport(renderer, NULL); 1190 SDL_RenderSetScale(renderer, 1.0f, 1.0f); 1191 return 0; 1192 } 1193 1194 renderer->logical_w = w; 1195 renderer->logical_h = h; 1196 1197 return UpdateLogicalSize(renderer); 1198} 1199 1200void 1201SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h) 1202{ 1203 CHECK_RENDERER_MAGIC(renderer, ); 1204 1205 if (w) { 1206 *w = renderer->logical_w; 1207 } 1208 if (h) { 1209 *h = renderer->logical_h; 1210 } 1211} 1212 1213int 1214SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) 1215{ 1216 CHECK_RENDERER_MAGIC(renderer, -1); 1217 1218 if (rect) { 1219 renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x); 1220 renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y); 1221 renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x); 1222 renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y); 1223 } else { 1224 renderer->viewport.x = 0; 1225 renderer->viewport.y = 0; 1226 if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) { 1227 return -1; 1228 } 1229 } 1230 return renderer->UpdateViewport(renderer); 1231} 1232 1233void 1234SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect) 1235{ 1236 CHECK_RENDERER_MAGIC(renderer, ); 1237 1238 if (rect) { 1239 rect->x = (int)(renderer->viewport.x / renderer->scale.x); 1240 rect->y = (int)(renderer->viewport.y / renderer->scale.y); 1241 rect->w = (int)(renderer->viewport.w / renderer->scale.x); 1242 rect->h = (int)(renderer->viewport.h / renderer->scale.y); 1243 } 1244} 1245 1246int 1247SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1248{ 1249 CHECK_RENDERER_MAGIC(renderer, -1) 1250 1251 if (rect) { 1252 renderer->clipping_enabled = SDL_TRUE; 1253 renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x); 1254 renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y); 1255 renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x); 1256 renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y); 1257 } else { 1258 renderer->clipping_enabled = SDL_FALSE; 1259 SDL_zero(renderer->clip_rect); 1260 } 1261 return renderer->UpdateClipRect(renderer); 1262} 1263 1264void 1265SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect) 1266{ 1267 CHECK_RENDERER_MAGIC(renderer, ) 1268 1269 if (rect) { 1270 rect->x = (int)(renderer->clip_rect.x / renderer->scale.x); 1271 rect->y = (int)(renderer->clip_rect.y / renderer->scale.y); 1272 rect->w = (int)(renderer->clip_rect.w / renderer->scale.x); 1273 rect->h = (int)(renderer->clip_rect.h / renderer->scale.y); 1274 } 1275} 1276 1277SDL_bool 1278SDL_RenderIsClipEnabled(SDL_Renderer * renderer) 1279{ 1280 CHECK_RENDERER_MAGIC(renderer, SDL_FALSE) 1281 return renderer->clipping_enabled; 1282} 1283 1284int 1285SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY) 1286{ 1287 CHECK_RENDERER_MAGIC(renderer, -1); 1288 1289 renderer->scale.x = scaleX; 1290 renderer->scale.y = scaleY; 1291 return 0; 1292} 1293 1294void 1295SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY) 1296{ 1297 CHECK_RENDERER_MAGIC(renderer, ); 1298 1299 if (scaleX) { 1300 *scaleX = renderer->scale.x; 1301 } 1302 if (scaleY) { 1303 *scaleY = renderer->scale.y; 1304 } 1305} 1306 1307int 1308SDL_SetRenderDrawColor(SDL_Renderer * renderer, 1309 Uint8 r, Uint8 g, Uint8 b, Uint8 a) 1310{ 1311 CHECK_RENDERER_MAGIC(renderer, -1); 1312 1313 renderer->r = r; 1314 renderer->g = g; 1315 renderer->b = b; 1316 renderer->a = a; 1317 return 0; 1318} 1319 1320int 1321SDL_GetRenderDrawColor(SDL_Renderer * renderer, 1322 Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a) 1323{ 1324 CHECK_RENDERER_MAGIC(renderer, -1); 1325 1326 if (r) { 1327 *r = renderer->r; 1328 } 1329 if (g) { 1330 *g = renderer->g; 1331 } 1332 if (b) { 1333 *b = renderer->b; 1334 } 1335 if (a) { 1336 *a = renderer->a; 1337 } 1338 return 0; 1339} 1340 1341int 1342SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) 1343{ 1344 CHECK_RENDERER_MAGIC(renderer, -1); 1345 1346 renderer->blendMode = blendMode; 1347 return 0; 1348} 1349 1350int 1351SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode) 1352{ 1353 CHECK_RENDERER_MAGIC(renderer, -1); 1354 1355 *blendMode = renderer->blendMode; 1356 return 0; 1357} 1358 1359int 1360SDL_RenderClear(SDL_Renderer * renderer) 1361{ 1362 CHECK_RENDERER_MAGIC(renderer, -1); 1363 1364 /* Don't draw while we're hidden */ 1365 if (renderer->hidden) { 1366 return 0; 1367 } 1368 return renderer->RenderClear(renderer); 1369} 1370 1371int 1372SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y) 1373{ 1374 SDL_Point point; 1375 1376 point.x = x; 1377 point.y = y; 1378 return SDL_RenderDrawPoints(renderer, &point, 1); 1379} 1380 1381static int 1382RenderDrawPointsWithRects(SDL_Renderer * renderer, 1383 const SDL_Point * points, int count) 1384{ 1385 SDL_FRect *frects; 1386 int i; 1387 int status; 1388 1389 frects = SDL_stack_alloc(SDL_FRect, count); 1390 if (!frects) { 1391 return SDL_OutOfMemory(); 1392 } 1393 for (i = 0; i < count; ++i) { 1394 frects[i].x = points[i].x * renderer->scale.x; 1395 frects[i].y = points[i].y * renderer->scale.y; 1396 frects[i].w = renderer->scale.x; 1397 frects[i].h = renderer->scale.y; 1398 } 1399 1400 status = renderer->RenderFillRects(renderer, frects, count); 1401 1402 SDL_stack_free(frects); 1403 1404 return status; 1405} 1406 1407int 1408SDL_RenderDrawPoints(SDL_Renderer * renderer, 1409 const SDL_Point * points, int count) 1410{ 1411 SDL_FPoint *fpoints; 1412 int i; 1413 int status; 1414 1415 CHECK_RENDERER_MAGIC(renderer, -1); 1416 1417 if (!points) { 1418 return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points"); 1419 } 1420 if (count < 1) { 1421 return 0; 1422 } 1423 /* Don't draw while we're hidden */ 1424 if (renderer->hidden) { 1425 return 0; 1426 } 1427 1428 if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { 1429 return RenderDrawPointsWithRects(renderer, points, count); 1430 } 1431 1432 fpoints = SDL_stack_alloc(SDL_FPoint, count); 1433 if (!fpoints) { 1434 return SDL_OutOfMemory(); 1435 } 1436 for (i = 0; i < count; ++i) { 1437 fpoints[i].x = points[i].x * renderer->scale.x; 1438 fpoints[i].y = points[i].y * renderer->scale.y; 1439 } 1440 1441 status = renderer->RenderDrawPoints(renderer, fpoints, count); 1442 1443 SDL_stack_free(fpoints); 1444 1445 return status; 1446} 1447 1448int 1449SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) 1450{ 1451 SDL_Point points[2]; 1452 1453 points[0].x = x1; 1454 points[0].y = y1; 1455 points[1].x = x2; 1456 points[1].y = y2; 1457 return SDL_RenderDrawLines(renderer, points, 2); 1458} 1459 1460static int 1461RenderDrawLinesWithRects(SDL_Renderer * renderer, 1462 const SDL_Point * points, int count) 1463{ 1464 SDL_FRect *frect; 1465 SDL_FRect *frects; 1466 SDL_FPoint fpoints[2]; 1467 int i, nrects; 1468 int status; 1469 1470 frects = SDL_stack_alloc(SDL_FRect, count-1); 1471 if (!frects) { 1472 return SDL_OutOfMemory(); 1473 } 1474 1475 status = 0; 1476 nrects = 0; 1477 for (i = 0; i < count-1; ++i) { 1478 if (points[i].x == points[i+1].x) { 1479 int minY = SDL_min(points[i].y, points[i+1].y); 1480 int maxY = SDL_max(points[i].y, points[i+1].y); 1481 1482 frect = &frects[nrects++]; 1483 frect->x = points[i].x * renderer->scale.x; 1484 frect->y = minY * renderer->scale.y; 1485 frect->w = renderer->scale.x; 1486 frect->h = (maxY - minY + 1) * renderer->scale.y; 1487 } else if (points[i].y == points[i+1].y) { 1488 int minX = SDL_min(points[i].x, points[i+1].x); 1489 int maxX = SDL_max(points[i].x, points[i+1].x); 1490 1491 frect = &frects[nrects++]; 1492 frect->x = minX * renderer->scale.x; 1493 frect->y = points[i].y * renderer->scale.y; 1494 frect->w = (maxX - minX + 1) * renderer->scale.x; 1495 frect->h = renderer->scale.y; 1496 } else { 1497 /* FIXME: We can't use a rect for this line... */ 1498 fpoints[0].x = points[i].x * renderer->scale.x; 1499 fpoints[0].y = points[i].y * renderer->scale.y; 1500 fpoints[1].x = points[i+1].x * renderer->scale.x; 1501 fpoints[1].y = points[i+1].y * renderer->scale.y; 1502 status += renderer->RenderDrawLines(renderer, fpoints, 2); 1503 } 1504 } 1505 1506 status += renderer->RenderFillRects(renderer, frects, nrects); 1507 1508 SDL_stack_free(frects); 1509 1510 if (status < 0) { 1511 status = -1; 1512 } 1513 return status; 1514} 1515 1516int 1517SDL_RenderDrawLines(SDL_Renderer * renderer, 1518 const SDL_Point * points, int count) 1519{ 1520 SDL_FPoint *fpoints; 1521 int i; 1522 int status; 1523 1524 CHECK_RENDERER_MAGIC(renderer, -1); 1525 1526 if (!points) { 1527 return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points"); 1528 } 1529 if (count < 2) { 1530 return 0; 1531 } 1532 /* Don't draw while we're hidden */ 1533 if (renderer->hidden) { 1534 return 0; 1535 } 1536 1537 if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { 1538 return RenderDrawLinesWithRects(renderer, points, count); 1539 } 1540 1541 fpoints = SDL_stack_alloc(SDL_FPoint, count); 1542 if (!fpoints) { 1543 return SDL_OutOfMemory(); 1544 } 1545 for (i = 0; i < count; ++i) { 1546 fpoints[i].x = points[i].x * renderer->scale.x; 1547 fpoints[i].y = points[i].y * renderer->scale.y; 1548 } 1549 1550 status = renderer->RenderDrawLines(renderer, fpoints, count); 1551 1552 SDL_stack_free(fpoints); 1553 1554 return status; 1555} 1556 1557int 1558SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1559{ 1560 SDL_Rect full_rect; 1561 SDL_Point points[5]; 1562 1563 CHECK_RENDERER_MAGIC(renderer, -1); 1564 1565 /* If 'rect' == NULL, then outline the whole surface */ 1566 if (!rect) { 1567 SDL_RenderGetViewport(renderer, &full_rect); 1568 full_rect.x = 0; 1569 full_rect.y = 0; 1570 rect = &full_rect; 1571 } 1572 1573 points[0].x = rect->x; 1574 points[0].y = rect->y; 1575 points[1].x = rect->x+rect->w-1; 1576 points[1].y = rect->y; 1577 points[2].x = rect->x+rect->w-1; 1578 points[2].y = rect->y+rect->h-1; 1579 points[3].x = rect->x; 1580 points[3].y = rect->y+rect->h-1; 1581 points[4].x = rect->x; 1582 points[4].y = rect->y; 1583 return SDL_RenderDrawLines(renderer, points, 5); 1584} 1585 1586int 1587SDL_RenderDrawRects(SDL_Renderer * renderer, 1588 const SDL_Rect * rects, int count) 1589{ 1590 int i; 1591 1592 CHECK_RENDERER_MAGIC(renderer, -1); 1593 1594 if (!rects) { 1595 return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects"); 1596 } 1597 if (count < 1) { 1598 return 0; 1599 } 1600 1601 /* Don't draw while we're hidden */ 1602 if (renderer->hidden) { 1603 return 0; 1604 } 1605 for (i = 0; i < count; ++i) { 1606 if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) { 1607 return -1; 1608 } 1609 } 1610 return 0; 1611} 1612 1613int 1614SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1615{ 1616 SDL_Rect full_rect = { 0, 0, 0, 0 }; 1617 1618 CHECK_RENDERER_MAGIC(renderer, -1); 1619 1620 /* If 'rect' == NULL, then outline the whole surface */ 1621 if (!rect) { 1622 SDL_RenderGetViewport(renderer, &full_rect); 1623 full_rect.x = 0; 1624 full_rect.y = 0; 1625 rect = &full_rect; 1626 } 1627 return SDL_RenderFillRects(renderer, rect, 1); 1628} 1629 1630int 1631SDL_RenderFillRects(SDL_Renderer * renderer, 1632 const SDL_Rect * rects, int count) 1633{ 1634 SDL_FRect *frects; 1635 int i; 1636 int status; 1637 1638 CHECK_RENDERER_MAGIC(renderer, -1); 1639 1640 if (!rects) { 1641 return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects"); 1642 } 1643 if (count < 1) { 1644 return 0; 1645 } 1646 /* Don't draw while we're hidden */ 1647 if (renderer->hidden) { 1648 return 0; 1649 } 1650 1651 frects = SDL_stack_alloc(SDL_FRect, count); 1652 if (!frects) { 1653 return SDL_OutOfMemory(); 1654 } 1655 for (i = 0; i < count; ++i) { 1656 frects[i].x = rects[i].x * renderer->scale.x; 1657 frects[i].y = rects[i].y * renderer->scale.y; 1658 frects[i].w = rects[i].w * renderer->scale.x; 1659 frects[i].h = rects[i].h * renderer->scale.y; 1660 } 1661 1662 status = renderer->RenderFillRects(renderer, frects, count); 1663 1664 SDL_stack_free(frects); 1665 1666 return status; 1667} 1668 1669int 1670SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 1671 const SDL_Rect * srcrect, const SDL_Rect * dstrect) 1672{ 1673 SDL_Rect real_srcrect = { 0, 0, 0, 0 }; 1674 SDL_Rect real_dstrect = { 0, 0, 0, 0 }; 1675 SDL_FRect frect; 1676 1677 CHECK_RENDERER_MAGIC(renderer, -1); 1678 CHECK_TEXTURE_MAGIC(texture, -1); 1679 1680 if (renderer != texture->renderer) { 1681 return SDL_SetError("Texture was not created with this renderer"); 1682 } 1683 1684 real_srcrect.x = 0; 1685 real_srcrect.y = 0; 1686 real_srcrect.w = texture->w; 1687 real_srcrect.h = texture->h; 1688 if (srcrect) { 1689 if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) { 1690 return 0; 1691 } 1692 } 1693 1694 SDL_RenderGetViewport(renderer, &real_dstrect); 1695 real_dstrect.x = 0; 1696 real_dstrect.y = 0; 1697 if (dstrect) { 1698 if (!SDL_HasIntersection(dstrect, &real_dstrect)) { 1699 return 0; 1700 } 1701 real_dstrect = *dstrect; 1702 } 1703 1704 if (texture->native) { 1705 texture = texture->native; 1706 } 1707 1708 /* Don't draw while we're hidden */ 1709 if (renderer->hidden) { 1710 return 0; 1711 } 1712 1713 frect.x = real_dstrect.x * renderer->scale.x; 1714 frect.y = real_dstrect.y * renderer->scale.y; 1715 frect.w = real_dstrect.w * renderer->scale.x; 1716 frect.h = real_dstrect.h * renderer->scale.y; 1717 1718 return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect); 1719} 1720 1721 1722int 1723SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 1724 const SDL_Rect * srcrect, const SDL_Rect * dstrect, 1725 const double angle, const SDL_Point *center, const SDL_RendererFlip flip) 1726{ 1727 SDL_Rect real_srcrect = { 0, 0, 0, 0 }; 1728 SDL_Rect real_dstrect = { 0, 0, 0, 0 }; 1729 SDL_Point real_center; 1730 SDL_FRect frect; 1731 SDL_FPoint fcenter; 1732 1733 CHECK_RENDERER_MAGIC(renderer, -1); 1734 CHECK_TEXTURE_MAGIC(texture, -1); 1735 1736 if (renderer != texture->renderer) { 1737 return SDL_SetError("Texture was not created with this renderer"); 1738 } 1739 if (!renderer->RenderCopyEx) { 1740 return SDL_SetError("Renderer does not support RenderCopyEx"); 1741 } 1742 1743 real_srcrect.x = 0; 1744 real_srcrect.y = 0; 1745 real_srcrect.w = texture->w; 1746 real_srcrect.h = texture->h; 1747 if (srcrect) { 1748 if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) { 1749 return 0; 1750 } 1751 } 1752 1753 /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */ 1754 if (dstrect) { 1755 real_dstrect = *dstrect; 1756 } else { 1757 SDL_RenderGetViewport(renderer, &real_dstrect); 1758 real_dstrect.x = 0; 1759 real_dstrect.y = 0; 1760 } 1761 1762 if (texture->native) { 1763 texture = texture->native; 1764 } 1765 1766 if(center) real_center = *center; 1767 else { 1768 real_center.x = real_dstrect.w/2; 1769 real_center.y = real_dstrect.h/2; 1770 } 1771 1772 frect.x = real_dstrect.x * renderer->scale.x; 1773 frect.y = real_dstrect.y * renderer->scale.y; 1774 frect.w = real_dstrect.w * renderer->scale.x; 1775 frect.h = real_dstrect.h * renderer->scale.y; 1776 1777 fcenter.x = real_center.x * renderer->scale.x; 1778 fcenter.y = real_center.y * renderer->scale.y; 1779 1780 return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip); 1781} 1782 1783int 1784SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 1785 Uint32 format, void * pixels, int pitch) 1786{ 1787 SDL_Rect real_rect; 1788 1789 CHECK_RENDERER_MAGIC(renderer, -1); 1790 1791 if (!renderer->RenderReadPixels) { 1792 return SDL_Unsupported(); 1793 } 1794 1795 if (!format) { 1796 format = SDL_GetWindowPixelFormat(renderer->window); 1797 } 1798 1799 real_rect.x = renderer->viewport.x; 1800 real_rect.y = renderer->viewport.y; 1801 real_rect.w = renderer->viewport.w; 1802 real_rect.h = renderer->viewport.h; 1803 if (rect) { 1804 if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) { 1805 return 0; 1806 } 1807 if (real_rect.y > rect->y) { 1808 pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y); 1809 } 1810 if (real_rect.x > rect->x) { 1811 int bpp = SDL_BYTESPERPIXEL(format); 1812 pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x); 1813 } 1814 } 1815 1816 return renderer->RenderReadPixels(renderer, &real_rect, 1817 format, pixels, pitch); 1818} 1819 1820void 1821SDL_RenderPresent(SDL_Renderer * renderer) 1822{ 1823 CHECK_RENDERER_MAGIC(renderer, ); 1824 1825 /* Don't draw while we're hidden */ 1826 if (renderer->hidden) { 1827 return; 1828 } 1829 renderer->RenderPresent(renderer); 1830} 1831 1832void 1833SDL_DestroyTexture(SDL_Texture * texture) 1834{ 1835 SDL_Renderer *renderer; 1836 1837 CHECK_TEXTURE_MAGIC(texture, ); 1838 1839 renderer = texture->renderer; 1840 if (texture == renderer->target) { 1841 SDL_SetRenderTarget(renderer, NULL); 1842 } 1843 1844 texture->magic = NULL; 1845 1846 if (texture->next) { 1847 texture->next->prev = texture->prev; 1848 } 1849 if (texture->prev) { 1850 texture->prev->next = texture->next; 1851 } else { 1852 renderer->textures = texture->next; 1853 } 1854 1855 if (texture->native) { 1856 SDL_DestroyTexture(texture->native); 1857 } 1858 if (texture->yuv) { 1859 SDL_SW_DestroyYUVTexture(texture->yuv); 1860 } 1861 SDL_free(texture->pixels); 1862 1863 renderer->DestroyTexture(renderer, texture); 1864 SDL_free(texture); 1865} 1866 1867void 1868SDL_DestroyRenderer(SDL_Renderer * renderer) 1869{ 1870 CHECK_RENDERER_MAGIC(renderer, ); 1871 1872 SDL_DelEventWatch(SDL_RendererEventWatch, renderer); 1873 1874 /* Free existing textures for this renderer */ 1875 while (renderer->textures) { 1876 SDL_DestroyTexture(renderer->textures); 1877 } 1878 1879 if (renderer->window) { 1880 SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL); 1881 } 1882 1883 /* It's no longer magical... */ 1884 renderer->magic = NULL; 1885 1886 /* Free the renderer instance */ 1887 renderer->DestroyRenderer(renderer); 1888} 1889 1890int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh) 1891{ 1892 SDL_Renderer *renderer; 1893 1894 CHECK_TEXTURE_MAGIC(texture, -1); 1895 renderer = texture->renderer; 1896 if (texture->native) { 1897 return SDL_GL_BindTexture(texture->native, texw, texh); 1898 } else if (renderer && renderer->GL_BindTexture) { 1899 return renderer->GL_BindTexture(renderer, texture, texw, texh); 1900 } else { 1901 return SDL_Unsupported(); 1902 } 1903} 1904 1905int SDL_GL_UnbindTexture(SDL_Texture *texture) 1906{ 1907 SDL_Renderer *renderer; 1908 1909 CHECK_TEXTURE_MAGIC(texture, -1); 1910 renderer = texture->renderer; 1911 if (texture->native) { 1912 return SDL_GL_UnbindTexture(texture->native); 1913 } else if (renderer && renderer->GL_UnbindTexture) { 1914 return renderer->GL_UnbindTexture(renderer, texture); 1915 } 1916 1917 return SDL_Unsupported(); 1918} 1919 1920/* vi: set ts=4 sw=4 expandtab: */