Atlas - SDL_render.c

Home / ext / SDL2 / src / render Lines: 1 | Size: 67531 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 SDL_assert(renderer && renderer->magic == &renderer_magic); \ 37 if (!renderer || renderer->magic != &renderer_magic) { \ 38 SDL_SetError("Invalid renderer"); \ 39 return retval; \ 40 } 41 42#define CHECK_TEXTURE_MAGIC(texture, retval) \ 43 SDL_assert(texture && texture->magic == &texture_magic); \ 44 if (!texture || texture->magic != &texture_magic) { \ 45 SDL_SetError("Invalid texture"); \ 46 return retval; \ 47 } 48 49/* Predefined blend modes */ 50#define SDL_COMPOSE_BLENDMODE(srcColorFactor, dstColorFactor, colorOperation, \ 51 srcAlphaFactor, dstAlphaFactor, alphaOperation) \ 52 (SDL_BlendMode)(((Uint32)colorOperation << 0) | \ 53 ((Uint32)srcColorFactor << 4) | \ 54 ((Uint32)dstColorFactor << 8) | \ 55 ((Uint32)alphaOperation << 16) | \ 56 ((Uint32)srcAlphaFactor << 20) | \ 57 ((Uint32)dstAlphaFactor << 24)) 58 59#define SDL_BLENDMODE_NONE_FULL \ 60 SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD, \ 61 SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ZERO, SDL_BLENDOPERATION_ADD) 62 63#define SDL_BLENDMODE_BLEND_FULL \ 64 SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD, \ 65 SDL_BLENDFACTOR_ONE, SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA, SDL_BLENDOPERATION_ADD) 66 67#define SDL_BLENDMODE_ADD_FULL \ 68 SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_SRC_ALPHA, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD, \ 69 SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) 70 71#define SDL_BLENDMODE_MOD_FULL \ 72 SDL_COMPOSE_BLENDMODE(SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_SRC_COLOR, SDL_BLENDOPERATION_ADD, \ 73 SDL_BLENDFACTOR_ZERO, SDL_BLENDFACTOR_ONE, SDL_BLENDOPERATION_ADD) 74 75#if !SDL_RENDER_DISABLED 76static const SDL_RenderDriver *render_drivers[] = { 77#if SDL_VIDEO_RENDER_D3D 78 &D3D_RenderDriver, 79#endif 80#if SDL_VIDEO_RENDER_D3D11 81 &D3D11_RenderDriver, 82#endif 83#if SDL_VIDEO_RENDER_OGL 84 &GL_RenderDriver, 85#endif 86#if SDL_VIDEO_RENDER_OGL_ES2 87 &GLES2_RenderDriver, 88#endif 89#if SDL_VIDEO_RENDER_OGL_ES 90 &GLES_RenderDriver, 91#endif 92#if SDL_VIDEO_RENDER_DIRECTFB 93 &DirectFB_RenderDriver, 94#endif 95#if SDL_VIDEO_RENDER_METAL 96 &METAL_RenderDriver, 97#endif 98#if SDL_VIDEO_RENDER_PSP 99 &PSP_RenderDriver, 100#endif 101 &SW_RenderDriver 102}; 103#endif /* !SDL_RENDER_DISABLED */ 104 105static char renderer_magic; 106static char texture_magic; 107 108static int UpdateLogicalSize(SDL_Renderer *renderer); 109 110int 111SDL_GetNumRenderDrivers(void) 112{ 113#if !SDL_RENDER_DISABLED 114 return SDL_arraysize(render_drivers); 115#else 116 return 0; 117#endif 118} 119 120int 121SDL_GetRenderDriverInfo(int index, SDL_RendererInfo * info) 122{ 123#if !SDL_RENDER_DISABLED 124 if (index < 0 || index >= SDL_GetNumRenderDrivers()) { 125 return SDL_SetError("index must be in the range of 0 - %d", 126 SDL_GetNumRenderDrivers() - 1); 127 } 128 *info = render_drivers[index]->info; 129 return 0; 130#else 131 return SDL_SetError("SDL not built with rendering support"); 132#endif 133} 134 135static void GetWindowViewportValues(SDL_Renderer *renderer, int *logical_w, int *logical_h, SDL_Rect *viewport, SDL_FPoint *scale) 136{ 137 SDL_LockMutex(renderer->target_mutex); 138 *logical_w = renderer->target ? renderer->logical_w_backup : renderer->logical_w; 139 *logical_h = renderer->target ? renderer->logical_h_backup : renderer->logical_h; 140 *viewport = renderer->target ? renderer->viewport_backup : renderer->viewport; 141 *scale = renderer->target ? renderer->scale_backup : renderer->scale; 142 SDL_UnlockMutex(renderer->target_mutex); 143} 144 145static int SDLCALL 146SDL_RendererEventWatch(void *userdata, SDL_Event *event) 147{ 148 SDL_Renderer *renderer = (SDL_Renderer *)userdata; 149 150 if (event->type == SDL_WINDOWEVENT) { 151 SDL_Window *window = SDL_GetWindowFromID(event->window.windowID); 152 if (window == renderer->window) { 153 if (renderer->WindowEvent) { 154 renderer->WindowEvent(renderer, &event->window); 155 } 156 157 if (event->window.event == SDL_WINDOWEVENT_SIZE_CHANGED) { 158 /* Make sure we're operating on the default render target */ 159 SDL_Texture *saved_target = SDL_GetRenderTarget(renderer); 160 if (saved_target) { 161 SDL_SetRenderTarget(renderer, NULL); 162 } 163 164 if (renderer->logical_w) { 165 UpdateLogicalSize(renderer); 166 } else { 167 /* Window was resized, reset viewport */ 168 int w, h; 169 170 if (renderer->GetOutputSize) { 171 renderer->GetOutputSize(renderer, &w, &h); 172 } else { 173 SDL_GetWindowSize(renderer->window, &w, &h); 174 } 175 176 if (renderer->target) { 177 renderer->viewport_backup.x = 0; 178 renderer->viewport_backup.y = 0; 179 renderer->viewport_backup.w = w; 180 renderer->viewport_backup.h = h; 181 } else { 182 renderer->viewport.x = 0; 183 renderer->viewport.y = 0; 184 renderer->viewport.w = w; 185 renderer->viewport.h = h; 186 renderer->UpdateViewport(renderer); 187 } 188 } 189 190 if (saved_target) { 191 SDL_SetRenderTarget(renderer, saved_target); 192 } 193 } else if (event->window.event == SDL_WINDOWEVENT_HIDDEN) { 194 renderer->hidden = SDL_TRUE; 195 } else if (event->window.event == SDL_WINDOWEVENT_SHOWN) { 196 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED)) { 197 renderer->hidden = SDL_FALSE; 198 } 199 } else if (event->window.event == SDL_WINDOWEVENT_MINIMIZED) { 200 renderer->hidden = SDL_TRUE; 201 } else if (event->window.event == SDL_WINDOWEVENT_RESTORED || 202 event->window.event == SDL_WINDOWEVENT_MAXIMIZED) { 203 if (!(SDL_GetWindowFlags(window) & SDL_WINDOW_HIDDEN)) { 204 renderer->hidden = SDL_FALSE; 205 } 206 } 207 } 208 } else if (event->type == SDL_MOUSEMOTION) { 209 SDL_Window *window = SDL_GetWindowFromID(event->motion.windowID); 210 if (window == renderer->window) { 211 int logical_w, logical_h; 212 SDL_Rect viewport; 213 SDL_FPoint scale; 214 GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); 215 if (logical_w) { 216 event->motion.x -= (int)(viewport.x * renderer->dpi_scale.x); 217 event->motion.y -= (int)(viewport.y * renderer->dpi_scale.y); 218 event->motion.x = (int)(event->motion.x / (scale.x * renderer->dpi_scale.x)); 219 event->motion.y = (int)(event->motion.y / (scale.y * renderer->dpi_scale.y)); 220 if (event->motion.xrel > 0) { 221 event->motion.xrel = SDL_max(1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x))); 222 } else if (event->motion.xrel < 0) { 223 event->motion.xrel = SDL_min(-1, (int)(event->motion.xrel / (scale.x * renderer->dpi_scale.x))); 224 } 225 if (event->motion.yrel > 0) { 226 event->motion.yrel = SDL_max(1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y))); 227 } else if (event->motion.yrel < 0) { 228 event->motion.yrel = SDL_min(-1, (int)(event->motion.yrel / (scale.y * renderer->dpi_scale.y))); 229 } 230 } 231 } 232 } else if (event->type == SDL_MOUSEBUTTONDOWN || 233 event->type == SDL_MOUSEBUTTONUP) { 234 SDL_Window *window = SDL_GetWindowFromID(event->button.windowID); 235 if (window == renderer->window) { 236 int logical_w, logical_h; 237 SDL_Rect viewport; 238 SDL_FPoint scale; 239 GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); 240 if (logical_w) { 241 event->button.x -= (int)(viewport.x * renderer->dpi_scale.x); 242 event->button.y -= (int)(viewport.y * renderer->dpi_scale.y); 243 event->button.x = (int)(event->button.x / (scale.x * renderer->dpi_scale.x)); 244 event->button.y = (int)(event->button.y / (scale.y * renderer->dpi_scale.y)); 245 } 246 } 247 } else if (event->type == SDL_FINGERDOWN || 248 event->type == SDL_FINGERUP || 249 event->type == SDL_FINGERMOTION) { 250 int logical_w, logical_h; 251 SDL_Rect viewport; 252 SDL_FPoint scale; 253 GetWindowViewportValues(renderer, &logical_w, &logical_h, &viewport, &scale); 254 if (logical_w) { 255 int w = 1; 256 int h = 1; 257 SDL_GetRendererOutputSize(renderer, &w, &h); 258 259 event->tfinger.x *= (w - 1); 260 event->tfinger.y *= (h - 1); 261 262 event->tfinger.x -= (viewport.x * renderer->dpi_scale.x); 263 event->tfinger.y -= (viewport.y * renderer->dpi_scale.y); 264 event->tfinger.x = (event->tfinger.x / (scale.x * renderer->dpi_scale.x)); 265 event->tfinger.y = (event->tfinger.y / (scale.y * renderer->dpi_scale.y)); 266 267 if (logical_w > 1) { 268 event->tfinger.x = event->tfinger.x / (logical_w - 1); 269 } else { 270 event->tfinger.x = 0.5f; 271 } 272 if (logical_h > 1) { 273 event->tfinger.y = event->tfinger.y / (logical_h - 1); 274 } else { 275 event->tfinger.y = 0.5f; 276 } 277 } 278 } 279 280 return 0; 281} 282 283int 284SDL_CreateWindowAndRenderer(int width, int height, Uint32 window_flags, 285 SDL_Window **window, SDL_Renderer **renderer) 286{ 287 *window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, 288 SDL_WINDOWPOS_UNDEFINED, 289 width, height, window_flags); 290 if (!*window) { 291 *renderer = NULL; 292 return -1; 293 } 294 295 *renderer = SDL_CreateRenderer(*window, -1, 0); 296 if (!*renderer) { 297 return -1; 298 } 299 300 return 0; 301} 302 303SDL_Renderer * 304SDL_CreateRenderer(SDL_Window * window, int index, Uint32 flags) 305{ 306#if !SDL_RENDER_DISABLED 307 SDL_Renderer *renderer = NULL; 308 int n = SDL_GetNumRenderDrivers(); 309 const char *hint; 310 311 if (!window) { 312 SDL_SetError("Invalid window"); 313 return NULL; 314 } 315 316 if (SDL_GetRenderer(window)) { 317 SDL_SetError("Renderer already associated with window"); 318 return NULL; 319 } 320 321 if (SDL_GetHint(SDL_HINT_RENDER_VSYNC)) { 322 if (SDL_GetHintBoolean(SDL_HINT_RENDER_VSYNC, SDL_TRUE)) { 323 flags |= SDL_RENDERER_PRESENTVSYNC; 324 } else { 325 flags &= ~SDL_RENDERER_PRESENTVSYNC; 326 } 327 } 328 329 if (index < 0) { 330 hint = SDL_GetHint(SDL_HINT_RENDER_DRIVER); 331 if (hint) { 332 for (index = 0; index < n; ++index) { 333 const SDL_RenderDriver *driver = render_drivers[index]; 334 335 if (SDL_strcasecmp(hint, driver->info.name) == 0) { 336 /* Create a new renderer instance */ 337 renderer = driver->CreateRenderer(window, flags); 338 break; 339 } 340 } 341 } 342 343 if (!renderer) { 344 for (index = 0; index < n; ++index) { 345 const SDL_RenderDriver *driver = render_drivers[index]; 346 347 if ((driver->info.flags & flags) == flags) { 348 /* Create a new renderer instance */ 349 renderer = driver->CreateRenderer(window, flags); 350 if (renderer) { 351 /* Yay, we got one! */ 352 break; 353 } 354 } 355 } 356 } 357 if (index == n) { 358 SDL_SetError("Couldn't find matching render driver"); 359 return NULL; 360 } 361 } else { 362 if (index >= SDL_GetNumRenderDrivers()) { 363 SDL_SetError("index must be -1 or in the range of 0 - %d", 364 SDL_GetNumRenderDrivers() - 1); 365 return NULL; 366 } 367 /* Create a new renderer instance */ 368 renderer = render_drivers[index]->CreateRenderer(window, flags); 369 } 370 371 if (renderer) { 372 renderer->magic = &renderer_magic; 373 renderer->window = window; 374 renderer->target_mutex = SDL_CreateMutex(); 375 renderer->scale.x = 1.0f; 376 renderer->scale.y = 1.0f; 377 renderer->dpi_scale.x = 1.0f; 378 renderer->dpi_scale.y = 1.0f; 379 380 if (window && renderer->GetOutputSize) { 381 int window_w, window_h; 382 int output_w, output_h; 383 if (renderer->GetOutputSize(renderer, &output_w, &output_h) == 0) { 384 SDL_GetWindowSize(renderer->window, &window_w, &window_h); 385 renderer->dpi_scale.x = (float)window_w / output_w; 386 renderer->dpi_scale.y = (float)window_h / output_h; 387 } 388 } 389 390 if (SDL_GetWindowFlags(window) & (SDL_WINDOW_HIDDEN|SDL_WINDOW_MINIMIZED)) { 391 renderer->hidden = SDL_TRUE; 392 } else { 393 renderer->hidden = SDL_FALSE; 394 } 395 396 SDL_SetWindowData(window, SDL_WINDOWRENDERDATA, renderer); 397 398 SDL_RenderSetViewport(renderer, NULL); 399 400 SDL_AddEventWatch(SDL_RendererEventWatch, renderer); 401 402 SDL_LogInfo(SDL_LOG_CATEGORY_RENDER, 403 "Created renderer: %s", renderer->info.name); 404 } 405 return renderer; 406#else 407 SDL_SetError("SDL not built with rendering support"); 408 return NULL; 409#endif 410} 411 412SDL_Renderer * 413SDL_CreateSoftwareRenderer(SDL_Surface * surface) 414{ 415#if !SDL_RENDER_DISABLED 416 SDL_Renderer *renderer; 417 418 renderer = SW_CreateRendererForSurface(surface); 419 420 if (renderer) { 421 renderer->magic = &renderer_magic; 422 renderer->target_mutex = SDL_CreateMutex(); 423 renderer->scale.x = 1.0f; 424 renderer->scale.y = 1.0f; 425 426 SDL_RenderSetViewport(renderer, NULL); 427 } 428 return renderer; 429#else 430 SDL_SetError("SDL not built with rendering support"); 431 return NULL; 432#endif /* !SDL_RENDER_DISABLED */ 433} 434 435SDL_Renderer * 436SDL_GetRenderer(SDL_Window * window) 437{ 438 return (SDL_Renderer *)SDL_GetWindowData(window, SDL_WINDOWRENDERDATA); 439} 440 441int 442SDL_GetRendererInfo(SDL_Renderer * renderer, SDL_RendererInfo * info) 443{ 444 CHECK_RENDERER_MAGIC(renderer, -1); 445 446 *info = renderer->info; 447 return 0; 448} 449 450int 451SDL_GetRendererOutputSize(SDL_Renderer * renderer, int *w, int *h) 452{ 453 CHECK_RENDERER_MAGIC(renderer, -1); 454 455 if (renderer->target) { 456 return SDL_QueryTexture(renderer->target, NULL, NULL, w, h); 457 } else if (renderer->GetOutputSize) { 458 return renderer->GetOutputSize(renderer, w, h); 459 } else if (renderer->window) { 460 SDL_GetWindowSize(renderer->window, w, h); 461 return 0; 462 } else { 463 SDL_assert(0 && "This should never happen"); 464 return SDL_SetError("Renderer doesn't support querying output size"); 465 } 466} 467 468static SDL_bool 469IsSupportedBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) 470{ 471 switch (blendMode) 472 { 473 /* These are required to be supported by all renderers */ 474 case SDL_BLENDMODE_NONE: 475 case SDL_BLENDMODE_BLEND: 476 case SDL_BLENDMODE_ADD: 477 case SDL_BLENDMODE_MOD: 478 return SDL_TRUE; 479 480 default: 481 return renderer->SupportsBlendMode && renderer->SupportsBlendMode(renderer, blendMode); 482 } 483} 484 485static SDL_bool 486IsSupportedFormat(SDL_Renderer * renderer, Uint32 format) 487{ 488 Uint32 i; 489 490 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 491 if (renderer->info.texture_formats[i] == format) { 492 return SDL_TRUE; 493 } 494 } 495 return SDL_FALSE; 496} 497 498static Uint32 499GetClosestSupportedFormat(SDL_Renderer * renderer, Uint32 format) 500{ 501 Uint32 i; 502 503 if (SDL_ISPIXELFORMAT_FOURCC(format)) { 504 /* Look for an exact match */ 505 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 506 if (renderer->info.texture_formats[i] == format) { 507 return renderer->info.texture_formats[i]; 508 } 509 } 510 } else { 511 SDL_bool hasAlpha = SDL_ISPIXELFORMAT_ALPHA(format); 512 513 /* We just want to match the first format that has the same channels */ 514 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 515 if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && 516 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == hasAlpha) { 517 return renderer->info.texture_formats[i]; 518 } 519 } 520 } 521 return renderer->info.texture_formats[0]; 522} 523 524SDL_ScaleMode SDL_GetScaleMode(void) 525{ 526 const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY); 527 528 if (!hint || SDL_strcasecmp(hint, "nearest") == 0) { 529 return SDL_ScaleModeNearest; 530 } else if (SDL_strcasecmp(hint, "linear") == 0) { 531 return SDL_ScaleModeLinear; 532 } else if (SDL_strcasecmp(hint, "best") == 0) { 533 return SDL_ScaleModeBest; 534 } else { 535 return (SDL_ScaleMode)SDL_atoi(hint); 536 } 537} 538 539SDL_Texture * 540SDL_CreateTexture(SDL_Renderer * renderer, Uint32 format, int access, int w, int h) 541{ 542 SDL_Texture *texture; 543 544 CHECK_RENDERER_MAGIC(renderer, NULL); 545 546 if (!format) { 547 format = renderer->info.texture_formats[0]; 548 } 549 if (SDL_BYTESPERPIXEL(format) == 0) { 550 SDL_SetError("Invalid texture format"); 551 return NULL; 552 } 553 if (SDL_ISPIXELFORMAT_INDEXED(format)) { 554 SDL_SetError("Palettized textures are not supported"); 555 return NULL; 556 } 557 if (w <= 0 || h <= 0) { 558 SDL_SetError("Texture dimensions can't be 0"); 559 return NULL; 560 } 561 if ((renderer->info.max_texture_width && w > renderer->info.max_texture_width) || 562 (renderer->info.max_texture_height && h > renderer->info.max_texture_height)) { 563 SDL_SetError("Texture dimensions are limited to %dx%d", renderer->info.max_texture_width, renderer->info.max_texture_height); 564 return NULL; 565 } 566 texture = (SDL_Texture *) SDL_calloc(1, sizeof(*texture)); 567 if (!texture) { 568 SDL_OutOfMemory(); 569 return NULL; 570 } 571 texture->magic = &texture_magic; 572 texture->format = format; 573 texture->access = access; 574 texture->w = w; 575 texture->h = h; 576 texture->r = 255; 577 texture->g = 255; 578 texture->b = 255; 579 texture->a = 255; 580 texture->scaleMode = SDL_GetScaleMode(); 581 texture->renderer = renderer; 582 texture->next = renderer->textures; 583 if (renderer->textures) { 584 renderer->textures->prev = texture; 585 } 586 renderer->textures = texture; 587 588 if (IsSupportedFormat(renderer, format)) { 589 if (renderer->CreateTexture(renderer, texture) < 0) { 590 SDL_DestroyTexture(texture); 591 return NULL; 592 } 593 } else { 594 texture->native = SDL_CreateTexture(renderer, 595 GetClosestSupportedFormat(renderer, format), 596 access, w, h); 597 if (!texture->native) { 598 SDL_DestroyTexture(texture); 599 return NULL; 600 } 601 602 /* Swap textures to have texture before texture->native in the list */ 603 texture->native->next = texture->next; 604 if (texture->native->next) { 605 texture->native->next->prev = texture->native; 606 } 607 texture->prev = texture->native->prev; 608 if (texture->prev) { 609 texture->prev->next = texture; 610 } 611 texture->native->prev = texture; 612 texture->next = texture->native; 613 renderer->textures = texture; 614 615 if (SDL_ISPIXELFORMAT_FOURCC(texture->format)) { 616 texture->yuv = SDL_SW_CreateYUVTexture(format, w, h); 617 if (!texture->yuv) { 618 SDL_DestroyTexture(texture); 619 return NULL; 620 } 621 } else if (access == SDL_TEXTUREACCESS_STREAMING) { 622 /* The pitch is 4 byte aligned */ 623 texture->pitch = (((w * SDL_BYTESPERPIXEL(format)) + 3) & ~3); 624 texture->pixels = SDL_calloc(1, texture->pitch * h); 625 if (!texture->pixels) { 626 SDL_DestroyTexture(texture); 627 return NULL; 628 } 629 } 630 } 631 return texture; 632} 633 634SDL_Texture * 635SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface) 636{ 637 const SDL_PixelFormat *fmt; 638 SDL_bool needAlpha; 639 Uint32 i; 640 Uint32 format; 641 SDL_Texture *texture; 642 643 CHECK_RENDERER_MAGIC(renderer, NULL); 644 645 if (!surface) { 646 SDL_SetError("SDL_CreateTextureFromSurface() passed NULL surface"); 647 return NULL; 648 } 649 650 /* See what the best texture format is */ 651 fmt = surface->format; 652 if (fmt->Amask || SDL_GetColorKey(surface, NULL) == 0) { 653 needAlpha = SDL_TRUE; 654 } else { 655 needAlpha = SDL_FALSE; 656 } 657 format = renderer->info.texture_formats[0]; 658 for (i = 0; i < renderer->info.num_texture_formats; ++i) { 659 if (!SDL_ISPIXELFORMAT_FOURCC(renderer->info.texture_formats[i]) && 660 SDL_ISPIXELFORMAT_ALPHA(renderer->info.texture_formats[i]) == needAlpha) { 661 format = renderer->info.texture_formats[i]; 662 break; 663 } 664 } 665 666 texture = SDL_CreateTexture(renderer, format, SDL_TEXTUREACCESS_STATIC, 667 surface->w, surface->h); 668 if (!texture) { 669 return NULL; 670 } 671 672 if (format == surface->format->format) { 673 if (SDL_MUSTLOCK(surface)) { 674 SDL_LockSurface(surface); 675 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); 676 SDL_UnlockSurface(surface); 677 } else { 678 SDL_UpdateTexture(texture, NULL, surface->pixels, surface->pitch); 679 } 680 } else { 681 SDL_PixelFormat *dst_fmt; 682 SDL_Surface *temp = NULL; 683 684 /* Set up a destination surface for the texture update */ 685 dst_fmt = SDL_AllocFormat(format); 686 if (!dst_fmt) { 687 SDL_DestroyTexture(texture); 688 return NULL; 689 } 690 temp = SDL_ConvertSurface(surface, dst_fmt, 0); 691 SDL_FreeFormat(dst_fmt); 692 if (temp) { 693 SDL_UpdateTexture(texture, NULL, temp->pixels, temp->pitch); 694 SDL_FreeSurface(temp); 695 } else { 696 SDL_DestroyTexture(texture); 697 return NULL; 698 } 699 } 700 701 { 702 Uint8 r, g, b, a; 703 SDL_BlendMode blendMode; 704 705 SDL_GetSurfaceColorMod(surface, &r, &g, &b); 706 SDL_SetTextureColorMod(texture, r, g, b); 707 708 SDL_GetSurfaceAlphaMod(surface, &a); 709 SDL_SetTextureAlphaMod(texture, a); 710 711 if (SDL_GetColorKey(surface, NULL) == 0) { 712 /* We converted to a texture with alpha format */ 713 SDL_SetTextureBlendMode(texture, SDL_BLENDMODE_BLEND); 714 } else { 715 SDL_GetSurfaceBlendMode(surface, &blendMode); 716 SDL_SetTextureBlendMode(texture, blendMode); 717 } 718 } 719 return texture; 720} 721 722int 723SDL_QueryTexture(SDL_Texture * texture, Uint32 * format, int *access, 724 int *w, int *h) 725{ 726 CHECK_TEXTURE_MAGIC(texture, -1); 727 728 if (format) { 729 *format = texture->format; 730 } 731 if (access) { 732 *access = texture->access; 733 } 734 if (w) { 735 *w = texture->w; 736 } 737 if (h) { 738 *h = texture->h; 739 } 740 return 0; 741} 742 743int 744SDL_SetTextureColorMod(SDL_Texture * texture, Uint8 r, Uint8 g, Uint8 b) 745{ 746 SDL_Renderer *renderer; 747 748 CHECK_TEXTURE_MAGIC(texture, -1); 749 750 renderer = texture->renderer; 751 if (r < 255 || g < 255 || b < 255) { 752 texture->modMode |= SDL_TEXTUREMODULATE_COLOR; 753 } else { 754 texture->modMode &= ~SDL_TEXTUREMODULATE_COLOR; 755 } 756 texture->r = r; 757 texture->g = g; 758 texture->b = b; 759 if (texture->native) { 760 return SDL_SetTextureColorMod(texture->native, r, g, b); 761 } else if (renderer->SetTextureColorMod) { 762 return renderer->SetTextureColorMod(renderer, texture); 763 } else { 764 return 0; 765 } 766} 767 768int 769SDL_GetTextureColorMod(SDL_Texture * texture, Uint8 * r, Uint8 * g, 770 Uint8 * b) 771{ 772 CHECK_TEXTURE_MAGIC(texture, -1); 773 774 if (r) { 775 *r = texture->r; 776 } 777 if (g) { 778 *g = texture->g; 779 } 780 if (b) { 781 *b = texture->b; 782 } 783 return 0; 784} 785 786int 787SDL_SetTextureAlphaMod(SDL_Texture * texture, Uint8 alpha) 788{ 789 SDL_Renderer *renderer; 790 791 CHECK_TEXTURE_MAGIC(texture, -1); 792 793 renderer = texture->renderer; 794 if (alpha < 255) { 795 texture->modMode |= SDL_TEXTUREMODULATE_ALPHA; 796 } else { 797 texture->modMode &= ~SDL_TEXTUREMODULATE_ALPHA; 798 } 799 texture->a = alpha; 800 if (texture->native) { 801 return SDL_SetTextureAlphaMod(texture->native, alpha); 802 } else if (renderer->SetTextureAlphaMod) { 803 return renderer->SetTextureAlphaMod(renderer, texture); 804 } else { 805 return 0; 806 } 807} 808 809int 810SDL_GetTextureAlphaMod(SDL_Texture * texture, Uint8 * alpha) 811{ 812 CHECK_TEXTURE_MAGIC(texture, -1); 813 814 if (alpha) { 815 *alpha = texture->a; 816 } 817 return 0; 818} 819 820int 821SDL_SetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode blendMode) 822{ 823 SDL_Renderer *renderer; 824 825 CHECK_TEXTURE_MAGIC(texture, -1); 826 827 renderer = texture->renderer; 828 if (!IsSupportedBlendMode(renderer, blendMode)) { 829 return SDL_Unsupported(); 830 } 831 texture->blendMode = blendMode; 832 if (texture->native) { 833 return SDL_SetTextureBlendMode(texture->native, blendMode); 834 } else if (renderer->SetTextureBlendMode) { 835 return renderer->SetTextureBlendMode(renderer, texture); 836 } else { 837 return 0; 838 } 839} 840 841int 842SDL_GetTextureBlendMode(SDL_Texture * texture, SDL_BlendMode *blendMode) 843{ 844 CHECK_TEXTURE_MAGIC(texture, -1); 845 846 if (blendMode) { 847 *blendMode = texture->blendMode; 848 } 849 return 0; 850} 851 852static int 853SDL_UpdateTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, 854 const void *pixels, int pitch) 855{ 856 SDL_Texture *native = texture->native; 857 SDL_Rect full_rect; 858 859 if (SDL_SW_UpdateYUVTexture(texture->yuv, rect, pixels, pitch) < 0) { 860 return -1; 861 } 862 863 full_rect.x = 0; 864 full_rect.y = 0; 865 full_rect.w = texture->w; 866 full_rect.h = texture->h; 867 rect = &full_rect; 868 869 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 870 /* We can lock the texture and copy to it */ 871 void *native_pixels = NULL; 872 int native_pitch = 0; 873 874 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 875 return -1; 876 } 877 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 878 rect->w, rect->h, native_pixels, native_pitch); 879 SDL_UnlockTexture(native); 880 } else { 881 /* Use a temporary buffer for updating */ 882 const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 883 const size_t alloclen = rect->h * temp_pitch; 884 if (alloclen > 0) { 885 void *temp_pixels = SDL_malloc(alloclen); 886 if (!temp_pixels) { 887 return SDL_OutOfMemory(); 888 } 889 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 890 rect->w, rect->h, temp_pixels, temp_pitch); 891 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 892 SDL_free(temp_pixels); 893 } 894 } 895 return 0; 896} 897 898static int 899SDL_UpdateTextureNative(SDL_Texture * texture, const SDL_Rect * rect, 900 const void *pixels, int pitch) 901{ 902 SDL_Texture *native = texture->native; 903 904 if (!rect->w || !rect->h) { 905 return 0; /* nothing to do. */ 906 } 907 908 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 909 /* We can lock the texture and copy to it */ 910 void *native_pixels = NULL; 911 int native_pitch = 0; 912 913 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 914 return -1; 915 } 916 SDL_ConvertPixels(rect->w, rect->h, 917 texture->format, pixels, pitch, 918 native->format, native_pixels, native_pitch); 919 SDL_UnlockTexture(native); 920 } else { 921 /* Use a temporary buffer for updating */ 922 const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 923 const size_t alloclen = rect->h * temp_pitch; 924 if (alloclen > 0) { 925 void *temp_pixels = SDL_malloc(alloclen); 926 if (!temp_pixels) { 927 return SDL_OutOfMemory(); 928 } 929 SDL_ConvertPixels(rect->w, rect->h, 930 texture->format, pixels, pitch, 931 native->format, temp_pixels, temp_pitch); 932 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 933 SDL_free(temp_pixels); 934 } 935 } 936 return 0; 937} 938 939int 940SDL_UpdateTexture(SDL_Texture * texture, const SDL_Rect * rect, 941 const void *pixels, int pitch) 942{ 943 SDL_Renderer *renderer; 944 SDL_Rect full_rect; 945 946 CHECK_TEXTURE_MAGIC(texture, -1); 947 948 if (!pixels) { 949 return SDL_InvalidParamError("pixels"); 950 } 951 if (!pitch) { 952 return SDL_InvalidParamError("pitch"); 953 } 954 955 if (!rect) { 956 full_rect.x = 0; 957 full_rect.y = 0; 958 full_rect.w = texture->w; 959 full_rect.h = texture->h; 960 rect = &full_rect; 961 } 962 963 if ((rect->w == 0) || (rect->h == 0)) { 964 return 0; /* nothing to do. */ 965 } else if (texture->yuv) { 966 return SDL_UpdateTextureYUV(texture, rect, pixels, pitch); 967 } else if (texture->native) { 968 return SDL_UpdateTextureNative(texture, rect, pixels, pitch); 969 } else { 970 renderer = texture->renderer; 971 return renderer->UpdateTexture(renderer, texture, rect, pixels, pitch); 972 } 973} 974 975static int 976SDL_UpdateTextureYUVPlanar(SDL_Texture * texture, const SDL_Rect * rect, 977 const Uint8 *Yplane, int Ypitch, 978 const Uint8 *Uplane, int Upitch, 979 const Uint8 *Vplane, int Vpitch) 980{ 981 SDL_Texture *native = texture->native; 982 SDL_Rect full_rect; 983 984 if (SDL_SW_UpdateYUVTexturePlanar(texture->yuv, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch) < 0) { 985 return -1; 986 } 987 988 full_rect.x = 0; 989 full_rect.y = 0; 990 full_rect.w = texture->w; 991 full_rect.h = texture->h; 992 rect = &full_rect; 993 994 if (!rect->w || !rect->h) { 995 return 0; /* nothing to do. */ 996 } 997 998 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 999 /* We can lock the texture and copy to it */ 1000 void *native_pixels = NULL; 1001 int native_pitch = 0; 1002 1003 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 1004 return -1; 1005 } 1006 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 1007 rect->w, rect->h, native_pixels, native_pitch); 1008 SDL_UnlockTexture(native); 1009 } else { 1010 /* Use a temporary buffer for updating */ 1011 const int temp_pitch = (((rect->w * SDL_BYTESPERPIXEL(native->format)) + 3) & ~3); 1012 const size_t alloclen = rect->h * temp_pitch; 1013 if (alloclen > 0) { 1014 void *temp_pixels = SDL_malloc(alloclen); 1015 if (!temp_pixels) { 1016 return SDL_OutOfMemory(); 1017 } 1018 SDL_SW_CopyYUVToRGB(texture->yuv, rect, native->format, 1019 rect->w, rect->h, temp_pixels, temp_pitch); 1020 SDL_UpdateTexture(native, rect, temp_pixels, temp_pitch); 1021 SDL_free(temp_pixels); 1022 } 1023 } 1024 return 0; 1025} 1026 1027int SDL_UpdateYUVTexture(SDL_Texture * texture, const SDL_Rect * rect, 1028 const Uint8 *Yplane, int Ypitch, 1029 const Uint8 *Uplane, int Upitch, 1030 const Uint8 *Vplane, int Vpitch) 1031{ 1032 SDL_Renderer *renderer; 1033 SDL_Rect full_rect; 1034 1035 CHECK_TEXTURE_MAGIC(texture, -1); 1036 1037 if (!Yplane) { 1038 return SDL_InvalidParamError("Yplane"); 1039 } 1040 if (!Ypitch) { 1041 return SDL_InvalidParamError("Ypitch"); 1042 } 1043 if (!Uplane) { 1044 return SDL_InvalidParamError("Uplane"); 1045 } 1046 if (!Upitch) { 1047 return SDL_InvalidParamError("Upitch"); 1048 } 1049 if (!Vplane) { 1050 return SDL_InvalidParamError("Vplane"); 1051 } 1052 if (!Vpitch) { 1053 return SDL_InvalidParamError("Vpitch"); 1054 } 1055 1056 if (texture->format != SDL_PIXELFORMAT_YV12 && 1057 texture->format != SDL_PIXELFORMAT_IYUV) { 1058 return SDL_SetError("Texture format must by YV12 or IYUV"); 1059 } 1060 1061 if (!rect) { 1062 full_rect.x = 0; 1063 full_rect.y = 0; 1064 full_rect.w = texture->w; 1065 full_rect.h = texture->h; 1066 rect = &full_rect; 1067 } 1068 1069 if (!rect->w || !rect->h) { 1070 return 0; /* nothing to do. */ 1071 } 1072 1073 if (texture->yuv) { 1074 return SDL_UpdateTextureYUVPlanar(texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); 1075 } else { 1076 SDL_assert(!texture->native); 1077 renderer = texture->renderer; 1078 SDL_assert(renderer->UpdateTextureYUV); 1079 if (renderer->UpdateTextureYUV) { 1080 return renderer->UpdateTextureYUV(renderer, texture, rect, Yplane, Ypitch, Uplane, Upitch, Vplane, Vpitch); 1081 } else { 1082 return SDL_Unsupported(); 1083 } 1084 } 1085} 1086 1087static int 1088SDL_LockTextureYUV(SDL_Texture * texture, const SDL_Rect * rect, 1089 void **pixels, int *pitch) 1090{ 1091 return SDL_SW_LockYUVTexture(texture->yuv, rect, pixels, pitch); 1092} 1093 1094static int 1095SDL_LockTextureNative(SDL_Texture * texture, const SDL_Rect * rect, 1096 void **pixels, int *pitch) 1097{ 1098 texture->locked_rect = *rect; 1099 *pixels = (void *) ((Uint8 *) texture->pixels + 1100 rect->y * texture->pitch + 1101 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1102 *pitch = texture->pitch; 1103 return 0; 1104} 1105 1106int 1107SDL_LockTexture(SDL_Texture * texture, const SDL_Rect * rect, 1108 void **pixels, int *pitch) 1109{ 1110 SDL_Renderer *renderer; 1111 SDL_Rect full_rect; 1112 1113 CHECK_TEXTURE_MAGIC(texture, -1); 1114 1115 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { 1116 return SDL_SetError("SDL_LockTexture(): texture must be streaming"); 1117 } 1118 1119 if (!rect) { 1120 full_rect.x = 0; 1121 full_rect.y = 0; 1122 full_rect.w = texture->w; 1123 full_rect.h = texture->h; 1124 rect = &full_rect; 1125 } 1126 1127 if (texture->yuv) { 1128 return SDL_LockTextureYUV(texture, rect, pixels, pitch); 1129 } else if (texture->native) { 1130 return SDL_LockTextureNative(texture, rect, pixels, pitch); 1131 } else { 1132 renderer = texture->renderer; 1133 return renderer->LockTexture(renderer, texture, rect, pixels, pitch); 1134 } 1135} 1136 1137static void 1138SDL_UnlockTextureYUV(SDL_Texture * texture) 1139{ 1140 SDL_Texture *native = texture->native; 1141 void *native_pixels = NULL; 1142 int native_pitch = 0; 1143 SDL_Rect rect; 1144 1145 rect.x = 0; 1146 rect.y = 0; 1147 rect.w = texture->w; 1148 rect.h = texture->h; 1149 1150 if (SDL_LockTexture(native, &rect, &native_pixels, &native_pitch) < 0) { 1151 return; 1152 } 1153 SDL_SW_CopyYUVToRGB(texture->yuv, &rect, native->format, 1154 rect.w, rect.h, native_pixels, native_pitch); 1155 SDL_UnlockTexture(native); 1156} 1157 1158static void 1159SDL_UnlockTextureNative(SDL_Texture * texture) 1160{ 1161 SDL_Texture *native = texture->native; 1162 void *native_pixels = NULL; 1163 int native_pitch = 0; 1164 const SDL_Rect *rect = &texture->locked_rect; 1165 const void* pixels = (void *) ((Uint8 *) texture->pixels + 1166 rect->y * texture->pitch + 1167 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1168 int pitch = texture->pitch; 1169 1170 if (SDL_LockTexture(native, rect, &native_pixels, &native_pitch) < 0) { 1171 return; 1172 } 1173 SDL_ConvertPixels(rect->w, rect->h, 1174 texture->format, pixels, pitch, 1175 native->format, native_pixels, native_pitch); 1176 SDL_UnlockTexture(native); 1177} 1178 1179void 1180SDL_UnlockTexture(SDL_Texture * texture) 1181{ 1182 SDL_Renderer *renderer; 1183 1184 CHECK_TEXTURE_MAGIC(texture, ); 1185 1186 if (texture->access != SDL_TEXTUREACCESS_STREAMING) { 1187 return; 1188 } 1189 if (texture->yuv) { 1190 SDL_UnlockTextureYUV(texture); 1191 } else if (texture->native) { 1192 SDL_UnlockTextureNative(texture); 1193 } else { 1194 renderer = texture->renderer; 1195 renderer->UnlockTexture(renderer, texture); 1196 } 1197} 1198 1199SDL_bool 1200SDL_RenderTargetSupported(SDL_Renderer *renderer) 1201{ 1202 if (!renderer || !renderer->SetRenderTarget) { 1203 return SDL_FALSE; 1204 } 1205 return (renderer->info.flags & SDL_RENDERER_TARGETTEXTURE) != 0; 1206} 1207 1208int 1209SDL_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 1210{ 1211 if (!SDL_RenderTargetSupported(renderer)) { 1212 return SDL_Unsupported(); 1213 } 1214 if (texture == renderer->target) { 1215 /* Nothing to do! */ 1216 return 0; 1217 } 1218 1219 /* texture == NULL is valid and means reset the target to the window */ 1220 if (texture) { 1221 CHECK_TEXTURE_MAGIC(texture, -1); 1222 if (renderer != texture->renderer) { 1223 return SDL_SetError("Texture was not created with this renderer"); 1224 } 1225 if (texture->access != SDL_TEXTUREACCESS_TARGET) { 1226 return SDL_SetError("Texture not created with SDL_TEXTUREACCESS_TARGET"); 1227 } 1228 if (texture->native) { 1229 /* Always render to the native texture */ 1230 texture = texture->native; 1231 } 1232 } 1233 1234 SDL_LockMutex(renderer->target_mutex); 1235 1236 if (texture && !renderer->target) { 1237 /* Make a backup of the viewport */ 1238 renderer->viewport_backup = renderer->viewport; 1239 renderer->clip_rect_backup = renderer->clip_rect; 1240 renderer->clipping_enabled_backup = renderer->clipping_enabled; 1241 renderer->scale_backup = renderer->scale; 1242 renderer->logical_w_backup = renderer->logical_w; 1243 renderer->logical_h_backup = renderer->logical_h; 1244 } 1245 renderer->target = texture; 1246 1247 if (renderer->SetRenderTarget(renderer, texture) < 0) { 1248 SDL_UnlockMutex(renderer->target_mutex); 1249 return -1; 1250 } 1251 1252 if (texture) { 1253 renderer->viewport.x = 0; 1254 renderer->viewport.y = 0; 1255 renderer->viewport.w = texture->w; 1256 renderer->viewport.h = texture->h; 1257 SDL_zero(renderer->clip_rect); 1258 renderer->clipping_enabled = SDL_FALSE; 1259 renderer->scale.x = 1.0f; 1260 renderer->scale.y = 1.0f; 1261 renderer->logical_w = texture->w; 1262 renderer->logical_h = texture->h; 1263 } else { 1264 renderer->viewport = renderer->viewport_backup; 1265 renderer->clip_rect = renderer->clip_rect_backup; 1266 renderer->clipping_enabled = renderer->clipping_enabled_backup; 1267 renderer->scale = renderer->scale_backup; 1268 renderer->logical_w = renderer->logical_w_backup; 1269 renderer->logical_h = renderer->logical_h_backup; 1270 } 1271 1272 SDL_UnlockMutex(renderer->target_mutex); 1273 1274 if (renderer->UpdateViewport(renderer) < 0) { 1275 return -1; 1276 } 1277 if (renderer->UpdateClipRect(renderer) < 0) { 1278 return -1; 1279 } 1280 1281 /* All set! */ 1282 return 0; 1283} 1284 1285SDL_Texture * 1286SDL_GetRenderTarget(SDL_Renderer *renderer) 1287{ 1288 return renderer->target; 1289} 1290 1291static int 1292UpdateLogicalSize(SDL_Renderer *renderer) 1293{ 1294 int w = 1, h = 1; 1295 float want_aspect; 1296 float real_aspect; 1297 float scale; 1298 SDL_Rect viewport; 1299 /* 0 is for letterbox, 1 is for overscan */ 1300 int scale_policy = 0; 1301 const char *hint; 1302 1303 if (!renderer->logical_w || !renderer->logical_h) { 1304 return 0; 1305 } 1306 if (SDL_GetRendererOutputSize(renderer, &w, &h) < 0) { 1307 return -1; 1308 } 1309 1310 hint = SDL_GetHint(SDL_HINT_RENDER_LOGICAL_SIZE_MODE); 1311 if (hint && (*hint == '1' || SDL_strcasecmp(hint, "overscan") == 0)) { 1312#if SDL_VIDEO_RENDER_D3D 1313 SDL_bool overscan_supported = SDL_TRUE; 1314 /* Unfortunately, Direct3D 9 doesn't support negative viewport numbers 1315 which the overscan implementation relies on. 1316 */ 1317 if (SDL_strcasecmp(SDL_GetCurrentVideoDriver(), "direct3d") == 0) { 1318 overscan_supported = SDL_FALSE; 1319 } 1320 if (overscan_supported) { 1321 scale_policy = 1; 1322 } 1323#else 1324 scale_policy = 1; 1325#endif 1326 } 1327 1328 want_aspect = (float)renderer->logical_w / renderer->logical_h; 1329 real_aspect = (float)w / h; 1330 1331 /* Clear the scale because we're setting viewport in output coordinates */ 1332 SDL_RenderSetScale(renderer, 1.0f, 1.0f); 1333 1334 if (renderer->integer_scale) { 1335 if (want_aspect > real_aspect) { 1336 scale = (float)(w / renderer->logical_w); 1337 } else { 1338 scale = (float)(h / renderer->logical_h); 1339 } 1340 viewport.w = (int)SDL_ceil(renderer->logical_w * scale); 1341 viewport.x = (w - viewport.w) / 2; 1342 viewport.h = (int)SDL_ceil(renderer->logical_h * scale); 1343 viewport.y = (h - viewport.h) / 2; 1344 1345 SDL_RenderSetViewport(renderer, &viewport); 1346 } else if (SDL_fabs(want_aspect-real_aspect) < 0.0001) { 1347 /* The aspect ratios are the same, just scale appropriately */ 1348 scale = (float)w / renderer->logical_w; 1349 SDL_RenderSetViewport(renderer, NULL); 1350 } else if (want_aspect > real_aspect) { 1351 if (scale_policy == 1) { 1352 /* We want a wider aspect ratio than is available - 1353 zoom so logical height matches the real height 1354 and the width will grow off the screen 1355 */ 1356 scale = (float)h / renderer->logical_h; 1357 viewport.y = 0; 1358 viewport.h = h; 1359 viewport.w = (int)SDL_ceil(renderer->logical_w * scale); 1360 viewport.x = (w - viewport.w) / 2; 1361 SDL_RenderSetViewport(renderer, &viewport); 1362 } else { 1363 /* We want a wider aspect ratio than is available - letterbox it */ 1364 scale = (float)w / renderer->logical_w; 1365 viewport.x = 0; 1366 viewport.w = w; 1367 viewport.h = (int)SDL_ceil(renderer->logical_h * scale); 1368 viewport.y = (h - viewport.h) / 2; 1369 SDL_RenderSetViewport(renderer, &viewport); 1370 } 1371 } else { 1372 if (scale_policy == 1) { 1373 /* We want a narrower aspect ratio than is available - 1374 zoom so logical width matches the real width 1375 and the height will grow off the screen 1376 */ 1377 scale = (float)w / renderer->logical_w; 1378 viewport.x = 0; 1379 viewport.w = w; 1380 viewport.h = (int)SDL_ceil(renderer->logical_h * scale); 1381 viewport.y = (h - viewport.h) / 2; 1382 SDL_RenderSetViewport(renderer, &viewport); 1383 } else { 1384 /* We want a narrower aspect ratio than is available - use side-bars */ 1385 scale = (float)h / renderer->logical_h; 1386 viewport.y = 0; 1387 viewport.h = h; 1388 viewport.w = (int)SDL_ceil(renderer->logical_w * scale); 1389 viewport.x = (w - viewport.w) / 2; 1390 SDL_RenderSetViewport(renderer, &viewport); 1391 } 1392 } 1393 1394 /* Set the new scale */ 1395 SDL_RenderSetScale(renderer, scale, scale); 1396 1397 return 0; 1398} 1399 1400int 1401SDL_RenderSetLogicalSize(SDL_Renderer * renderer, int w, int h) 1402{ 1403 CHECK_RENDERER_MAGIC(renderer, -1); 1404 1405 if (!w || !h) { 1406 /* Clear any previous logical resolution */ 1407 renderer->logical_w = 0; 1408 renderer->logical_h = 0; 1409 SDL_RenderSetViewport(renderer, NULL); 1410 SDL_RenderSetScale(renderer, 1.0f, 1.0f); 1411 return 0; 1412 } 1413 1414 renderer->logical_w = w; 1415 renderer->logical_h = h; 1416 1417 return UpdateLogicalSize(renderer); 1418} 1419 1420void 1421SDL_RenderGetLogicalSize(SDL_Renderer * renderer, int *w, int *h) 1422{ 1423 CHECK_RENDERER_MAGIC(renderer, ); 1424 1425 if (w) { 1426 *w = renderer->logical_w; 1427 } 1428 if (h) { 1429 *h = renderer->logical_h; 1430 } 1431} 1432 1433int 1434SDL_RenderSetIntegerScale(SDL_Renderer * renderer, SDL_bool enable) 1435{ 1436 CHECK_RENDERER_MAGIC(renderer, -1); 1437 1438 renderer->integer_scale = enable; 1439 1440 return UpdateLogicalSize(renderer); 1441} 1442 1443SDL_bool 1444SDLCALL SDL_RenderGetIntegerScale(SDL_Renderer * renderer) 1445{ 1446 CHECK_RENDERER_MAGIC(renderer, SDL_FALSE); 1447 1448 return renderer->integer_scale; 1449} 1450 1451int 1452SDL_RenderSetViewport(SDL_Renderer * renderer, const SDL_Rect * rect) 1453{ 1454 CHECK_RENDERER_MAGIC(renderer, -1); 1455 1456 if (rect) { 1457 renderer->viewport.x = (int)SDL_floor(rect->x * renderer->scale.x); 1458 renderer->viewport.y = (int)SDL_floor(rect->y * renderer->scale.y); 1459 renderer->viewport.w = (int)SDL_ceil(rect->w * renderer->scale.x); 1460 renderer->viewport.h = (int)SDL_ceil(rect->h * renderer->scale.y); 1461 } else { 1462 renderer->viewport.x = 0; 1463 renderer->viewport.y = 0; 1464 if (SDL_GetRendererOutputSize(renderer, &renderer->viewport.w, &renderer->viewport.h) < 0) { 1465 return -1; 1466 } 1467 } 1468 return renderer->UpdateViewport(renderer); 1469} 1470 1471void 1472SDL_RenderGetViewport(SDL_Renderer * renderer, SDL_Rect * rect) 1473{ 1474 CHECK_RENDERER_MAGIC(renderer, ); 1475 1476 if (rect) { 1477 rect->x = (int)(renderer->viewport.x / renderer->scale.x); 1478 rect->y = (int)(renderer->viewport.y / renderer->scale.y); 1479 rect->w = (int)(renderer->viewport.w / renderer->scale.x); 1480 rect->h = (int)(renderer->viewport.h / renderer->scale.y); 1481 } 1482} 1483 1484int 1485SDL_RenderSetClipRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1486{ 1487 CHECK_RENDERER_MAGIC(renderer, -1) 1488 1489 if (rect) { 1490 renderer->clipping_enabled = SDL_TRUE; 1491 renderer->clip_rect.x = (int)SDL_floor(rect->x * renderer->scale.x); 1492 renderer->clip_rect.y = (int)SDL_floor(rect->y * renderer->scale.y); 1493 renderer->clip_rect.w = (int)SDL_ceil(rect->w * renderer->scale.x); 1494 renderer->clip_rect.h = (int)SDL_ceil(rect->h * renderer->scale.y); 1495 } else { 1496 renderer->clipping_enabled = SDL_FALSE; 1497 SDL_zero(renderer->clip_rect); 1498 } 1499 return renderer->UpdateClipRect(renderer); 1500} 1501 1502void 1503SDL_RenderGetClipRect(SDL_Renderer * renderer, SDL_Rect * rect) 1504{ 1505 CHECK_RENDERER_MAGIC(renderer, ) 1506 1507 if (rect) { 1508 rect->x = (int)(renderer->clip_rect.x / renderer->scale.x); 1509 rect->y = (int)(renderer->clip_rect.y / renderer->scale.y); 1510 rect->w = (int)(renderer->clip_rect.w / renderer->scale.x); 1511 rect->h = (int)(renderer->clip_rect.h / renderer->scale.y); 1512 } 1513} 1514 1515SDL_bool 1516SDL_RenderIsClipEnabled(SDL_Renderer * renderer) 1517{ 1518 CHECK_RENDERER_MAGIC(renderer, SDL_FALSE) 1519 return renderer->clipping_enabled; 1520} 1521 1522int 1523SDL_RenderSetScale(SDL_Renderer * renderer, float scaleX, float scaleY) 1524{ 1525 CHECK_RENDERER_MAGIC(renderer, -1); 1526 1527 renderer->scale.x = scaleX; 1528 renderer->scale.y = scaleY; 1529 return 0; 1530} 1531 1532void 1533SDL_RenderGetScale(SDL_Renderer * renderer, float *scaleX, float *scaleY) 1534{ 1535 CHECK_RENDERER_MAGIC(renderer, ); 1536 1537 if (scaleX) { 1538 *scaleX = renderer->scale.x; 1539 } 1540 if (scaleY) { 1541 *scaleY = renderer->scale.y; 1542 } 1543} 1544 1545int 1546SDL_SetRenderDrawColor(SDL_Renderer * renderer, 1547 Uint8 r, Uint8 g, Uint8 b, Uint8 a) 1548{ 1549 CHECK_RENDERER_MAGIC(renderer, -1); 1550 1551 renderer->r = r; 1552 renderer->g = g; 1553 renderer->b = b; 1554 renderer->a = a; 1555 return 0; 1556} 1557 1558int 1559SDL_GetRenderDrawColor(SDL_Renderer * renderer, 1560 Uint8 * r, Uint8 * g, Uint8 * b, Uint8 * a) 1561{ 1562 CHECK_RENDERER_MAGIC(renderer, -1); 1563 1564 if (r) { 1565 *r = renderer->r; 1566 } 1567 if (g) { 1568 *g = renderer->g; 1569 } 1570 if (b) { 1571 *b = renderer->b; 1572 } 1573 if (a) { 1574 *a = renderer->a; 1575 } 1576 return 0; 1577} 1578 1579int 1580SDL_SetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) 1581{ 1582 CHECK_RENDERER_MAGIC(renderer, -1); 1583 1584 if (!IsSupportedBlendMode(renderer, blendMode)) { 1585 return SDL_Unsupported(); 1586 } 1587 renderer->blendMode = blendMode; 1588 return 0; 1589} 1590 1591int 1592SDL_GetRenderDrawBlendMode(SDL_Renderer * renderer, SDL_BlendMode *blendMode) 1593{ 1594 CHECK_RENDERER_MAGIC(renderer, -1); 1595 1596 *blendMode = renderer->blendMode; 1597 return 0; 1598} 1599 1600int 1601SDL_RenderClear(SDL_Renderer * renderer) 1602{ 1603 CHECK_RENDERER_MAGIC(renderer, -1); 1604 1605 /* Don't draw while we're hidden */ 1606 if (renderer->hidden) { 1607 return 0; 1608 } 1609 return renderer->RenderClear(renderer); 1610} 1611 1612int 1613SDL_RenderDrawPoint(SDL_Renderer * renderer, int x, int y) 1614{ 1615 SDL_Point point; 1616 1617 point.x = x; 1618 point.y = y; 1619 return SDL_RenderDrawPoints(renderer, &point, 1); 1620} 1621 1622static int 1623RenderDrawPointsWithRects(SDL_Renderer * renderer, 1624 const SDL_Point * points, int count) 1625{ 1626 SDL_FRect *frects; 1627 int i; 1628 int status; 1629 1630 frects = SDL_stack_alloc(SDL_FRect, count); 1631 if (!frects) { 1632 return SDL_OutOfMemory(); 1633 } 1634 for (i = 0; i < count; ++i) { 1635 frects[i].x = points[i].x * renderer->scale.x; 1636 frects[i].y = points[i].y * renderer->scale.y; 1637 frects[i].w = renderer->scale.x; 1638 frects[i].h = renderer->scale.y; 1639 } 1640 1641 status = renderer->RenderFillRects(renderer, frects, count); 1642 1643 SDL_stack_free(frects); 1644 1645 return status; 1646} 1647 1648int 1649SDL_RenderDrawPoints(SDL_Renderer * renderer, 1650 const SDL_Point * points, int count) 1651{ 1652 SDL_FPoint *fpoints; 1653 int i; 1654 int status; 1655 1656 CHECK_RENDERER_MAGIC(renderer, -1); 1657 1658 if (!points) { 1659 return SDL_SetError("SDL_RenderDrawPoints(): Passed NULL points"); 1660 } 1661 if (count < 1) { 1662 return 0; 1663 } 1664 1665 /* Don't draw while we're hidden */ 1666 if (renderer->hidden) { 1667 return 0; 1668 } 1669 1670 if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { 1671 return RenderDrawPointsWithRects(renderer, points, count); 1672 } 1673 1674 fpoints = SDL_stack_alloc(SDL_FPoint, count); 1675 if (!fpoints) { 1676 return SDL_OutOfMemory(); 1677 } 1678 for (i = 0; i < count; ++i) { 1679 fpoints[i].x = points[i].x * renderer->scale.x; 1680 fpoints[i].y = points[i].y * renderer->scale.y; 1681 } 1682 1683 status = renderer->RenderDrawPoints(renderer, fpoints, count); 1684 1685 SDL_stack_free(fpoints); 1686 1687 return status; 1688} 1689 1690int 1691SDL_RenderDrawLine(SDL_Renderer * renderer, int x1, int y1, int x2, int y2) 1692{ 1693 SDL_Point points[2]; 1694 1695 points[0].x = x1; 1696 points[0].y = y1; 1697 points[1].x = x2; 1698 points[1].y = y2; 1699 return SDL_RenderDrawLines(renderer, points, 2); 1700} 1701 1702static int 1703RenderDrawLinesWithRects(SDL_Renderer * renderer, 1704 const SDL_Point * points, int count) 1705{ 1706 SDL_FRect *frect; 1707 SDL_FRect *frects; 1708 SDL_FPoint fpoints[2]; 1709 int i, nrects; 1710 int status; 1711 1712 frects = SDL_stack_alloc(SDL_FRect, count-1); 1713 if (!frects) { 1714 return SDL_OutOfMemory(); 1715 } 1716 1717 status = 0; 1718 nrects = 0; 1719 for (i = 0; i < count-1; ++i) { 1720 if (points[i].x == points[i+1].x) { 1721 int minY = SDL_min(points[i].y, points[i+1].y); 1722 int maxY = SDL_max(points[i].y, points[i+1].y); 1723 1724 frect = &frects[nrects++]; 1725 frect->x = points[i].x * renderer->scale.x; 1726 frect->y = minY * renderer->scale.y; 1727 frect->w = renderer->scale.x; 1728 frect->h = (maxY - minY + 1) * renderer->scale.y; 1729 } else if (points[i].y == points[i+1].y) { 1730 int minX = SDL_min(points[i].x, points[i+1].x); 1731 int maxX = SDL_max(points[i].x, points[i+1].x); 1732 1733 frect = &frects[nrects++]; 1734 frect->x = minX * renderer->scale.x; 1735 frect->y = points[i].y * renderer->scale.y; 1736 frect->w = (maxX - minX + 1) * renderer->scale.x; 1737 frect->h = renderer->scale.y; 1738 } else { 1739 /* FIXME: We can't use a rect for this line... */ 1740 fpoints[0].x = points[i].x * renderer->scale.x; 1741 fpoints[0].y = points[i].y * renderer->scale.y; 1742 fpoints[1].x = points[i+1].x * renderer->scale.x; 1743 fpoints[1].y = points[i+1].y * renderer->scale.y; 1744 status += renderer->RenderDrawLines(renderer, fpoints, 2); 1745 } 1746 } 1747 1748 status += renderer->RenderFillRects(renderer, frects, nrects); 1749 1750 SDL_stack_free(frects); 1751 1752 if (status < 0) { 1753 status = -1; 1754 } 1755 return status; 1756} 1757 1758int 1759SDL_RenderDrawLines(SDL_Renderer * renderer, 1760 const SDL_Point * points, int count) 1761{ 1762 SDL_FPoint *fpoints; 1763 int i; 1764 int status; 1765 1766 CHECK_RENDERER_MAGIC(renderer, -1); 1767 1768 if (!points) { 1769 return SDL_SetError("SDL_RenderDrawLines(): Passed NULL points"); 1770 } 1771 if (count < 2) { 1772 return 0; 1773 } 1774 1775 /* Don't draw while we're hidden */ 1776 if (renderer->hidden) { 1777 return 0; 1778 } 1779 1780 if (renderer->scale.x != 1.0f || renderer->scale.y != 1.0f) { 1781 return RenderDrawLinesWithRects(renderer, points, count); 1782 } 1783 1784 fpoints = SDL_stack_alloc(SDL_FPoint, count); 1785 if (!fpoints) { 1786 return SDL_OutOfMemory(); 1787 } 1788 for (i = 0; i < count; ++i) { 1789 fpoints[i].x = points[i].x * renderer->scale.x; 1790 fpoints[i].y = points[i].y * renderer->scale.y; 1791 } 1792 1793 status = renderer->RenderDrawLines(renderer, fpoints, count); 1794 1795 SDL_stack_free(fpoints); 1796 1797 return status; 1798} 1799 1800int 1801SDL_RenderDrawRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1802{ 1803 SDL_Rect full_rect; 1804 SDL_Point points[5]; 1805 1806 CHECK_RENDERER_MAGIC(renderer, -1); 1807 1808 /* If 'rect' == NULL, then outline the whole surface */ 1809 if (!rect) { 1810 SDL_RenderGetViewport(renderer, &full_rect); 1811 full_rect.x = 0; 1812 full_rect.y = 0; 1813 rect = &full_rect; 1814 } 1815 1816 points[0].x = rect->x; 1817 points[0].y = rect->y; 1818 points[1].x = rect->x+rect->w-1; 1819 points[1].y = rect->y; 1820 points[2].x = rect->x+rect->w-1; 1821 points[2].y = rect->y+rect->h-1; 1822 points[3].x = rect->x; 1823 points[3].y = rect->y+rect->h-1; 1824 points[4].x = rect->x; 1825 points[4].y = rect->y; 1826 return SDL_RenderDrawLines(renderer, points, 5); 1827} 1828 1829int 1830SDL_RenderDrawRects(SDL_Renderer * renderer, 1831 const SDL_Rect * rects, int count) 1832{ 1833 int i; 1834 1835 CHECK_RENDERER_MAGIC(renderer, -1); 1836 1837 if (!rects) { 1838 return SDL_SetError("SDL_RenderDrawRects(): Passed NULL rects"); 1839 } 1840 if (count < 1) { 1841 return 0; 1842 } 1843 1844 /* Don't draw while we're hidden */ 1845 if (renderer->hidden) { 1846 return 0; 1847 } 1848 1849 for (i = 0; i < count; ++i) { 1850 if (SDL_RenderDrawRect(renderer, &rects[i]) < 0) { 1851 return -1; 1852 } 1853 } 1854 return 0; 1855} 1856 1857int 1858SDL_RenderFillRect(SDL_Renderer * renderer, const SDL_Rect * rect) 1859{ 1860 SDL_Rect full_rect = { 0, 0, 0, 0 }; 1861 1862 CHECK_RENDERER_MAGIC(renderer, -1); 1863 1864 /* If 'rect' == NULL, then outline the whole surface */ 1865 if (!rect) { 1866 SDL_RenderGetViewport(renderer, &full_rect); 1867 full_rect.x = 0; 1868 full_rect.y = 0; 1869 rect = &full_rect; 1870 } 1871 return SDL_RenderFillRects(renderer, rect, 1); 1872} 1873 1874int 1875SDL_RenderFillRects(SDL_Renderer * renderer, 1876 const SDL_Rect * rects, int count) 1877{ 1878 SDL_FRect *frects; 1879 int i; 1880 int status; 1881 1882 CHECK_RENDERER_MAGIC(renderer, -1); 1883 1884 if (!rects) { 1885 return SDL_SetError("SDL_RenderFillRects(): Passed NULL rects"); 1886 } 1887 if (count < 1) { 1888 return 0; 1889 } 1890 1891 /* Don't draw while we're hidden */ 1892 if (renderer->hidden) { 1893 return 0; 1894 } 1895 1896 frects = SDL_stack_alloc(SDL_FRect, count); 1897 if (!frects) { 1898 return SDL_OutOfMemory(); 1899 } 1900 for (i = 0; i < count; ++i) { 1901 frects[i].x = rects[i].x * renderer->scale.x; 1902 frects[i].y = rects[i].y * renderer->scale.y; 1903 frects[i].w = rects[i].w * renderer->scale.x; 1904 frects[i].h = rects[i].h * renderer->scale.y; 1905 } 1906 1907 status = renderer->RenderFillRects(renderer, frects, count); 1908 1909 SDL_stack_free(frects); 1910 1911 return status; 1912} 1913 1914int 1915SDL_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 1916 const SDL_Rect * srcrect, const SDL_Rect * dstrect) 1917{ 1918 SDL_Rect real_srcrect = { 0, 0, 0, 0 }; 1919 SDL_Rect real_dstrect = { 0, 0, 0, 0 }; 1920 SDL_FRect frect; 1921 1922 CHECK_RENDERER_MAGIC(renderer, -1); 1923 CHECK_TEXTURE_MAGIC(texture, -1); 1924 1925 if (renderer != texture->renderer) { 1926 return SDL_SetError("Texture was not created with this renderer"); 1927 } 1928 1929 /* Don't draw while we're hidden */ 1930 if (renderer->hidden) { 1931 return 0; 1932 } 1933 1934 real_srcrect.x = 0; 1935 real_srcrect.y = 0; 1936 real_srcrect.w = texture->w; 1937 real_srcrect.h = texture->h; 1938 if (srcrect) { 1939 if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) { 1940 return 0; 1941 } 1942 } 1943 1944 SDL_RenderGetViewport(renderer, &real_dstrect); 1945 real_dstrect.x = 0; 1946 real_dstrect.y = 0; 1947 if (dstrect) { 1948 if (!SDL_HasIntersection(dstrect, &real_dstrect)) { 1949 return 0; 1950 } 1951 real_dstrect = *dstrect; 1952 } 1953 1954 if (texture->native) { 1955 texture = texture->native; 1956 } 1957 1958 frect.x = real_dstrect.x * renderer->scale.x; 1959 frect.y = real_dstrect.y * renderer->scale.y; 1960 frect.w = real_dstrect.w * renderer->scale.x; 1961 frect.h = real_dstrect.h * renderer->scale.y; 1962 1963 return renderer->RenderCopy(renderer, texture, &real_srcrect, &frect); 1964} 1965 1966 1967int 1968SDL_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 1969 const SDL_Rect * srcrect, const SDL_Rect * dstrect, 1970 const double angle, const SDL_Point *center, const SDL_RendererFlip flip) 1971{ 1972 SDL_Rect real_srcrect = { 0, 0, 0, 0 }; 1973 SDL_Rect real_dstrect = { 0, 0, 0, 0 }; 1974 SDL_Point real_center; 1975 SDL_FRect frect; 1976 SDL_FPoint fcenter; 1977 1978 if (flip == SDL_FLIP_NONE && (int)(angle/360) == angle/360) { /* fast path when we don't need rotation or flipping */ 1979 return SDL_RenderCopy(renderer, texture, srcrect, dstrect); 1980 } 1981 1982 CHECK_RENDERER_MAGIC(renderer, -1); 1983 CHECK_TEXTURE_MAGIC(texture, -1); 1984 1985 if (renderer != texture->renderer) { 1986 return SDL_SetError("Texture was not created with this renderer"); 1987 } 1988 if (!renderer->RenderCopyEx) { 1989 return SDL_SetError("Renderer does not support RenderCopyEx"); 1990 } 1991 1992 /* Don't draw while we're hidden */ 1993 if (renderer->hidden) { 1994 return 0; 1995 } 1996 1997 real_srcrect.x = 0; 1998 real_srcrect.y = 0; 1999 real_srcrect.w = texture->w; 2000 real_srcrect.h = texture->h; 2001 if (srcrect) { 2002 if (!SDL_IntersectRect(srcrect, &real_srcrect, &real_srcrect)) { 2003 return 0; 2004 } 2005 } 2006 2007 /* We don't intersect the dstrect with the viewport as RenderCopy does because of potential rotation clipping issues... TODO: should we? */ 2008 if (dstrect) { 2009 real_dstrect = *dstrect; 2010 } else { 2011 SDL_RenderGetViewport(renderer, &real_dstrect); 2012 real_dstrect.x = 0; 2013 real_dstrect.y = 0; 2014 } 2015 2016 if (texture->native) { 2017 texture = texture->native; 2018 } 2019 2020 if (center) { 2021 real_center = *center; 2022 } else { 2023 real_center.x = real_dstrect.w/2; 2024 real_center.y = real_dstrect.h/2; 2025 } 2026 2027 frect.x = real_dstrect.x * renderer->scale.x; 2028 frect.y = real_dstrect.y * renderer->scale.y; 2029 frect.w = real_dstrect.w * renderer->scale.x; 2030 frect.h = real_dstrect.h * renderer->scale.y; 2031 2032 fcenter.x = real_center.x * renderer->scale.x; 2033 fcenter.y = real_center.y * renderer->scale.y; 2034 2035 return renderer->RenderCopyEx(renderer, texture, &real_srcrect, &frect, angle, &fcenter, flip); 2036} 2037 2038int 2039SDL_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 2040 Uint32 format, void * pixels, int pitch) 2041{ 2042 SDL_Rect real_rect; 2043 2044 CHECK_RENDERER_MAGIC(renderer, -1); 2045 2046 if (!renderer->RenderReadPixels) { 2047 return SDL_Unsupported(); 2048 } 2049 2050 if (!format) { 2051 format = SDL_GetWindowPixelFormat(renderer->window); 2052 } 2053 2054 real_rect.x = renderer->viewport.x; 2055 real_rect.y = renderer->viewport.y; 2056 real_rect.w = renderer->viewport.w; 2057 real_rect.h = renderer->viewport.h; 2058 if (rect) { 2059 if (!SDL_IntersectRect(rect, &real_rect, &real_rect)) { 2060 return 0; 2061 } 2062 if (real_rect.y > rect->y) { 2063 pixels = (Uint8 *)pixels + pitch * (real_rect.y - rect->y); 2064 } 2065 if (real_rect.x > rect->x) { 2066 int bpp = SDL_BYTESPERPIXEL(format); 2067 pixels = (Uint8 *)pixels + bpp * (real_rect.x - rect->x); 2068 } 2069 } 2070 2071 return renderer->RenderReadPixels(renderer, &real_rect, 2072 format, pixels, pitch); 2073} 2074 2075void 2076SDL_RenderPresent(SDL_Renderer * renderer) 2077{ 2078 CHECK_RENDERER_MAGIC(renderer, ); 2079 2080 /* Don't draw while we're hidden */ 2081 if (renderer->hidden) { 2082 return; 2083 } 2084 renderer->RenderPresent(renderer); 2085} 2086 2087void 2088SDL_DestroyTexture(SDL_Texture * texture) 2089{ 2090 SDL_Renderer *renderer; 2091 2092 CHECK_TEXTURE_MAGIC(texture, ); 2093 2094 renderer = texture->renderer; 2095 if (texture == renderer->target) { 2096 SDL_SetRenderTarget(renderer, NULL); 2097 } 2098 2099 texture->magic = NULL; 2100 2101 if (texture->next) { 2102 texture->next->prev = texture->prev; 2103 } 2104 if (texture->prev) { 2105 texture->prev->next = texture->next; 2106 } else { 2107 renderer->textures = texture->next; 2108 } 2109 2110 if (texture->native) { 2111 SDL_DestroyTexture(texture->native); 2112 } 2113 if (texture->yuv) { 2114 SDL_SW_DestroyYUVTexture(texture->yuv); 2115 } 2116 SDL_free(texture->pixels); 2117 2118 renderer->DestroyTexture(renderer, texture); 2119 SDL_free(texture); 2120} 2121 2122void 2123SDL_DestroyRenderer(SDL_Renderer * renderer) 2124{ 2125 CHECK_RENDERER_MAGIC(renderer, ); 2126 2127 SDL_DelEventWatch(SDL_RendererEventWatch, renderer); 2128 2129 /* Free existing textures for this renderer */ 2130 while (renderer->textures) { 2131 SDL_Texture *tex = renderer->textures; (void) tex; 2132 SDL_DestroyTexture(renderer->textures); 2133 SDL_assert(tex != renderer->textures); /* satisfy static analysis. */ 2134 } 2135 2136 if (renderer->window) { 2137 SDL_SetWindowData(renderer->window, SDL_WINDOWRENDERDATA, NULL); 2138 } 2139 2140 /* It's no longer magical... */ 2141 renderer->magic = NULL; 2142 2143 /* Free the target mutex */ 2144 SDL_DestroyMutex(renderer->target_mutex); 2145 renderer->target_mutex = NULL; 2146 2147 /* Free the renderer instance */ 2148 renderer->DestroyRenderer(renderer); 2149} 2150 2151int SDL_GL_BindTexture(SDL_Texture *texture, float *texw, float *texh) 2152{ 2153 SDL_Renderer *renderer; 2154 2155 CHECK_TEXTURE_MAGIC(texture, -1); 2156 renderer = texture->renderer; 2157 if (texture->native) { 2158 return SDL_GL_BindTexture(texture->native, texw, texh); 2159 } else if (renderer && renderer->GL_BindTexture) { 2160 return renderer->GL_BindTexture(renderer, texture, texw, texh); 2161 } else { 2162 return SDL_Unsupported(); 2163 } 2164} 2165 2166int SDL_GL_UnbindTexture(SDL_Texture *texture) 2167{ 2168 SDL_Renderer *renderer; 2169 2170 CHECK_TEXTURE_MAGIC(texture, -1); 2171 renderer = texture->renderer; 2172 if (texture->native) { 2173 return SDL_GL_UnbindTexture(texture->native); 2174 } else if (renderer && renderer->GL_UnbindTexture) { 2175 return renderer->GL_UnbindTexture(renderer, texture); 2176 } 2177 2178 return SDL_Unsupported(); 2179} 2180 2181void * 2182SDL_RenderGetMetalLayer(SDL_Renderer * renderer) 2183{ 2184 CHECK_RENDERER_MAGIC(renderer, NULL); 2185 2186 if (renderer->GetMetalLayer) { 2187 return renderer->GetMetalLayer(renderer); 2188 } 2189 return NULL; 2190} 2191 2192void * 2193SDL_RenderGetMetalCommandEncoder(SDL_Renderer * renderer) 2194{ 2195 CHECK_RENDERER_MAGIC(renderer, NULL); 2196 2197 if (renderer->GetMetalCommandEncoder) { 2198 return renderer->GetMetalCommandEncoder(renderer); 2199 } 2200 return NULL; 2201} 2202 2203static SDL_BlendMode 2204SDL_GetShortBlendMode(SDL_BlendMode blendMode) 2205{ 2206 if (blendMode == SDL_BLENDMODE_NONE_FULL) { 2207 return SDL_BLENDMODE_NONE; 2208 } 2209 if (blendMode == SDL_BLENDMODE_BLEND_FULL) { 2210 return SDL_BLENDMODE_BLEND; 2211 } 2212 if (blendMode == SDL_BLENDMODE_ADD_FULL) { 2213 return SDL_BLENDMODE_ADD; 2214 } 2215 if (blendMode == SDL_BLENDMODE_MOD_FULL) { 2216 return SDL_BLENDMODE_MOD; 2217 } 2218 return blendMode; 2219} 2220 2221static SDL_BlendMode 2222SDL_GetLongBlendMode(SDL_BlendMode blendMode) 2223{ 2224 if (blendMode == SDL_BLENDMODE_NONE) { 2225 return SDL_BLENDMODE_NONE_FULL; 2226 } 2227 if (blendMode == SDL_BLENDMODE_BLEND) { 2228 return SDL_BLENDMODE_BLEND_FULL; 2229 } 2230 if (blendMode == SDL_BLENDMODE_ADD) { 2231 return SDL_BLENDMODE_ADD_FULL; 2232 } 2233 if (blendMode == SDL_BLENDMODE_MOD) { 2234 return SDL_BLENDMODE_MOD_FULL; 2235 } 2236 return blendMode; 2237} 2238 2239SDL_BlendMode 2240SDL_ComposeCustomBlendMode(SDL_BlendFactor srcColorFactor, SDL_BlendFactor dstColorFactor, 2241 SDL_BlendOperation colorOperation, 2242 SDL_BlendFactor srcAlphaFactor, SDL_BlendFactor dstAlphaFactor, 2243 SDL_BlendOperation alphaOperation) 2244{ 2245 SDL_BlendMode blendMode = SDL_COMPOSE_BLENDMODE(srcColorFactor, dstColorFactor, colorOperation, 2246 srcAlphaFactor, dstAlphaFactor, alphaOperation); 2247 return SDL_GetShortBlendMode(blendMode); 2248} 2249 2250SDL_BlendFactor 2251SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode) 2252{ 2253 blendMode = SDL_GetLongBlendMode(blendMode); 2254 return (SDL_BlendFactor)(((Uint32)blendMode >> 4) & 0xF); 2255} 2256 2257SDL_BlendFactor 2258SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode) 2259{ 2260 blendMode = SDL_GetLongBlendMode(blendMode); 2261 return (SDL_BlendFactor)(((Uint32)blendMode >> 8) & 0xF); 2262} 2263 2264SDL_BlendOperation 2265SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode) 2266{ 2267 blendMode = SDL_GetLongBlendMode(blendMode); 2268 return (SDL_BlendOperation)(((Uint32)blendMode >> 0) & 0xF); 2269} 2270 2271SDL_BlendFactor 2272SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode) 2273{ 2274 blendMode = SDL_GetLongBlendMode(blendMode); 2275 return (SDL_BlendFactor)(((Uint32)blendMode >> 20) & 0xF); 2276} 2277 2278SDL_BlendFactor 2279SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode) 2280{ 2281 blendMode = SDL_GetLongBlendMode(blendMode); 2282 return (SDL_BlendFactor)(((Uint32)blendMode >> 24) & 0xF); 2283} 2284 2285SDL_BlendOperation 2286SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode) 2287{ 2288 blendMode = SDL_GetLongBlendMode(blendMode); 2289 return (SDL_BlendOperation)(((Uint32)blendMode >> 16) & 0xF); 2290} 2291 2292/* vi: set ts=4 sw=4 expandtab: */ 2293
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.