Atlas - SDL_render_sw.c

Home / ext / SDL2 / src / render / software Lines: 1 | Size: 31506 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#if !SDL_RENDER_DISABLED 24 25#include "../SDL_sysrender.h" 26#include "SDL_render_sw_c.h" 27#include "SDL_hints.h" 28 29#include "SDL_draw.h" 30#include "SDL_blendfillrect.h" 31#include "SDL_blendline.h" 32#include "SDL_blendpoint.h" 33#include "SDL_drawline.h" 34#include "SDL_drawpoint.h" 35#include "SDL_rotate.h" 36 37/* SDL surface based renderer implementation */ 38 39static SDL_Renderer *SW_CreateRenderer(SDL_Window * window, Uint32 flags); 40static void SW_WindowEvent(SDL_Renderer * renderer, 41 const SDL_WindowEvent *event); 42static int SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h); 43static int SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); 44static int SW_SetTextureColorMod(SDL_Renderer * renderer, 45 SDL_Texture * texture); 46static int SW_SetTextureAlphaMod(SDL_Renderer * renderer, 47 SDL_Texture * texture); 48static int SW_SetTextureBlendMode(SDL_Renderer * renderer, 49 SDL_Texture * texture); 50static int SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 51 const SDL_Rect * rect, const void *pixels, 52 int pitch); 53static int SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 54 const SDL_Rect * rect, void **pixels, int *pitch); 55static void SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); 56static int SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture); 57static int SW_UpdateViewport(SDL_Renderer * renderer); 58static int SW_UpdateClipRect(SDL_Renderer * renderer); 59static int SW_RenderClear(SDL_Renderer * renderer); 60static int SW_RenderDrawPoints(SDL_Renderer * renderer, 61 const SDL_FPoint * points, int count); 62static int SW_RenderDrawLines(SDL_Renderer * renderer, 63 const SDL_FPoint * points, int count); 64static int SW_RenderFillRects(SDL_Renderer * renderer, 65 const SDL_FRect * rects, int count); 66static int SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 67 const SDL_Rect * srcrect, const SDL_FRect * dstrect); 68static int SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 69 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 70 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip); 71static int SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 72 Uint32 format, void * pixels, int pitch); 73static void SW_RenderPresent(SDL_Renderer * renderer); 74static void SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture); 75static void SW_DestroyRenderer(SDL_Renderer * renderer); 76 77 78SDL_RenderDriver SW_RenderDriver = { 79 SW_CreateRenderer, 80 { 81 "software", 82 SDL_RENDERER_SOFTWARE | SDL_RENDERER_TARGETTEXTURE, 83 8, 84 { 85 SDL_PIXELFORMAT_ARGB8888, 86 SDL_PIXELFORMAT_ABGR8888, 87 SDL_PIXELFORMAT_RGBA8888, 88 SDL_PIXELFORMAT_BGRA8888, 89 SDL_PIXELFORMAT_RGB888, 90 SDL_PIXELFORMAT_BGR888, 91 SDL_PIXELFORMAT_RGB565, 92 SDL_PIXELFORMAT_RGB555 93 }, 94 0, 95 0} 96}; 97 98typedef struct 99{ 100 SDL_Surface *surface; 101 SDL_Surface *window; 102} SW_RenderData; 103 104 105static SDL_Surface * 106SW_ActivateRenderer(SDL_Renderer * renderer) 107{ 108 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 109 110 if (!data->surface) { 111 data->surface = data->window; 112 } 113 if (!data->surface) { 114 SDL_Surface *surface = SDL_GetWindowSurface(renderer->window); 115 if (surface) { 116 data->surface = data->window = surface; 117 118 SW_UpdateViewport(renderer); 119 SW_UpdateClipRect(renderer); 120 } 121 } 122 return data->surface; 123} 124 125SDL_Renderer * 126SW_CreateRendererForSurface(SDL_Surface * surface) 127{ 128 SDL_Renderer *renderer; 129 SW_RenderData *data; 130 131 if (!surface) { 132 SDL_SetError("Can't create renderer for NULL surface"); 133 return NULL; 134 } 135 136 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer)); 137 if (!renderer) { 138 SDL_OutOfMemory(); 139 return NULL; 140 } 141 142 data = (SW_RenderData *) SDL_calloc(1, sizeof(*data)); 143 if (!data) { 144 SW_DestroyRenderer(renderer); 145 SDL_OutOfMemory(); 146 return NULL; 147 } 148 data->surface = surface; 149 data->window = surface; 150 151 renderer->WindowEvent = SW_WindowEvent; 152 renderer->GetOutputSize = SW_GetOutputSize; 153 renderer->CreateTexture = SW_CreateTexture; 154 renderer->SetTextureColorMod = SW_SetTextureColorMod; 155 renderer->SetTextureAlphaMod = SW_SetTextureAlphaMod; 156 renderer->SetTextureBlendMode = SW_SetTextureBlendMode; 157 renderer->UpdateTexture = SW_UpdateTexture; 158 renderer->LockTexture = SW_LockTexture; 159 renderer->UnlockTexture = SW_UnlockTexture; 160 renderer->SetRenderTarget = SW_SetRenderTarget; 161 renderer->UpdateViewport = SW_UpdateViewport; 162 renderer->UpdateClipRect = SW_UpdateClipRect; 163 renderer->RenderClear = SW_RenderClear; 164 renderer->RenderDrawPoints = SW_RenderDrawPoints; 165 renderer->RenderDrawLines = SW_RenderDrawLines; 166 renderer->RenderFillRects = SW_RenderFillRects; 167 renderer->RenderCopy = SW_RenderCopy; 168 renderer->RenderCopyEx = SW_RenderCopyEx; 169 renderer->RenderReadPixels = SW_RenderReadPixels; 170 renderer->RenderPresent = SW_RenderPresent; 171 renderer->DestroyTexture = SW_DestroyTexture; 172 renderer->DestroyRenderer = SW_DestroyRenderer; 173 renderer->info = SW_RenderDriver.info; 174 renderer->driverdata = data; 175 176 SW_ActivateRenderer(renderer); 177 178 return renderer; 179} 180 181SDL_Renderer * 182SW_CreateRenderer(SDL_Window * window, Uint32 flags) 183{ 184 SDL_Surface *surface; 185 186 surface = SDL_GetWindowSurface(window); 187 if (!surface) { 188 return NULL; 189 } 190 return SW_CreateRendererForSurface(surface); 191} 192 193static void 194SW_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 195{ 196 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 197 198 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { 199 data->surface = NULL; 200 data->window = NULL; 201 } 202} 203 204static int 205SW_GetOutputSize(SDL_Renderer * renderer, int *w, int *h) 206{ 207 SDL_Surface *surface = SW_ActivateRenderer(renderer); 208 209 if (surface) { 210 if (w) { 211 *w = surface->w; 212 } 213 if (h) { 214 *h = surface->h; 215 } 216 return 0; 217 } else { 218 SDL_SetError("Software renderer doesn't have an output surface"); 219 return -1; 220 } 221} 222 223static int 224SW_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 225{ 226 int bpp; 227 Uint32 Rmask, Gmask, Bmask, Amask; 228 229 if (!SDL_PixelFormatEnumToMasks 230 (texture->format, &bpp, &Rmask, &Gmask, &Bmask, &Amask)) { 231 return SDL_SetError("Unknown texture format"); 232 } 233 234 texture->driverdata = 235 SDL_CreateRGBSurface(0, texture->w, texture->h, bpp, Rmask, Gmask, 236 Bmask, Amask); 237 SDL_SetSurfaceColorMod(texture->driverdata, texture->r, texture->g, 238 texture->b); 239 SDL_SetSurfaceAlphaMod(texture->driverdata, texture->a); 240 SDL_SetSurfaceBlendMode(texture->driverdata, texture->blendMode); 241 242 /* Only RLE encode textures without an alpha channel since the RLE coder 243 * discards the color values of pixels with an alpha value of zero. 244 */ 245 if (texture->access == SDL_TEXTUREACCESS_STATIC && !Amask) { 246 SDL_SetSurfaceRLE(texture->driverdata, 1); 247 } 248 249 if (!texture->driverdata) { 250 return -1; 251 } 252 return 0; 253} 254 255static int 256SW_SetTextureColorMod(SDL_Renderer * renderer, SDL_Texture * texture) 257{ 258 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 259 /* If the color mod is ever enabled (non-white), permanently disable RLE (which doesn't support 260 * color mod) to avoid potentially frequent RLE encoding/decoding. 261 */ 262 if ((texture->r & texture->g & texture->b) != 255) { 263 SDL_SetSurfaceRLE(surface, 0); 264 } 265 return SDL_SetSurfaceColorMod(surface, texture->r, texture->g, 266 texture->b); 267} 268 269static int 270SW_SetTextureAlphaMod(SDL_Renderer * renderer, SDL_Texture * texture) 271{ 272 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 273 /* If the texture ever has multiple alpha values (surface alpha plus alpha channel), permanently 274 * disable RLE (which doesn't support this) to avoid potentially frequent RLE encoding/decoding. 275 */ 276 if (texture->a != 255 && surface->format->Amask) { 277 SDL_SetSurfaceRLE(surface, 0); 278 } 279 return SDL_SetSurfaceAlphaMod(surface, texture->a); 280} 281 282static int 283SW_SetTextureBlendMode(SDL_Renderer * renderer, SDL_Texture * texture) 284{ 285 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 286 /* If add or mod blending are ever enabled, permanently disable RLE (which doesn't support 287 * them) to avoid potentially frequent RLE encoding/decoding. 288 */ 289 if ((texture->blendMode == SDL_BLENDMODE_ADD || texture->blendMode == SDL_BLENDMODE_MOD)) { 290 SDL_SetSurfaceRLE(surface, 0); 291 } 292 return SDL_SetSurfaceBlendMode(surface, texture->blendMode); 293} 294 295static int 296SW_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 297 const SDL_Rect * rect, const void *pixels, int pitch) 298{ 299 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 300 Uint8 *src, *dst; 301 int row; 302 size_t length; 303 304 if(SDL_MUSTLOCK(surface)) 305 SDL_LockSurface(surface); 306 src = (Uint8 *) pixels; 307 dst = (Uint8 *) surface->pixels + 308 rect->y * surface->pitch + 309 rect->x * surface->format->BytesPerPixel; 310 length = rect->w * surface->format->BytesPerPixel; 311 for (row = 0; row < rect->h; ++row) { 312 SDL_memcpy(dst, src, length); 313 src += pitch; 314 dst += surface->pitch; 315 } 316 if(SDL_MUSTLOCK(surface)) 317 SDL_UnlockSurface(surface); 318 return 0; 319} 320 321static int 322SW_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 323 const SDL_Rect * rect, void **pixels, int *pitch) 324{ 325 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 326 327 *pixels = 328 (void *) ((Uint8 *) surface->pixels + rect->y * surface->pitch + 329 rect->x * surface->format->BytesPerPixel); 330 *pitch = surface->pitch; 331 return 0; 332} 333 334static void 335SW_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 336{ 337} 338 339static int 340SW_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 341{ 342 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 343 344 if (texture ) { 345 data->surface = (SDL_Surface *) texture->driverdata; 346 } else { 347 data->surface = data->window; 348 } 349 return 0; 350} 351 352static int 353SW_UpdateViewport(SDL_Renderer * renderer) 354{ 355 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 356 SDL_Surface *surface = data->surface; 357 358 if (!surface) { 359 /* We'll update the viewport after we recreate the surface */ 360 return 0; 361 } 362 363 SDL_SetClipRect(data->surface, &renderer->viewport); 364 return 0; 365} 366 367static int 368SW_UpdateClipRect(SDL_Renderer * renderer) 369{ 370 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 371 SDL_Surface *surface = data->surface; 372 if (surface) { 373 if (renderer->clipping_enabled) { 374 SDL_Rect clip_rect; 375 clip_rect = renderer->clip_rect; 376 clip_rect.x += renderer->viewport.x; 377 clip_rect.y += renderer->viewport.y; 378 SDL_IntersectRect(&renderer->viewport, &clip_rect, &clip_rect); 379 SDL_SetClipRect(surface, &clip_rect); 380 } else { 381 SDL_SetClipRect(surface, &renderer->viewport); 382 } 383 } 384 return 0; 385} 386 387static int 388SW_RenderClear(SDL_Renderer * renderer) 389{ 390 SDL_Surface *surface = SW_ActivateRenderer(renderer); 391 Uint32 color; 392 SDL_Rect clip_rect; 393 394 if (!surface) { 395 return -1; 396 } 397 398 color = SDL_MapRGBA(surface->format, 399 renderer->r, renderer->g, renderer->b, renderer->a); 400 401 /* By definition the clear ignores the clip rect */ 402 clip_rect = surface->clip_rect; 403 SDL_SetClipRect(surface, NULL); 404 SDL_FillRect(surface, NULL, color); 405 SDL_SetClipRect(surface, &clip_rect); 406 return 0; 407} 408 409static int 410SW_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points, 411 int count) 412{ 413 SDL_Surface *surface = SW_ActivateRenderer(renderer); 414 SDL_Point *final_points; 415 int i, status; 416 417 if (!surface) { 418 return -1; 419 } 420 421 final_points = SDL_stack_alloc(SDL_Point, count); 422 if (!final_points) { 423 return SDL_OutOfMemory(); 424 } 425 if (renderer->viewport.x || renderer->viewport.y) { 426 int x = renderer->viewport.x; 427 int y = renderer->viewport.y; 428 429 for (i = 0; i < count; ++i) { 430 final_points[i].x = (int)(x + points[i].x); 431 final_points[i].y = (int)(y + points[i].y); 432 } 433 } else { 434 for (i = 0; i < count; ++i) { 435 final_points[i].x = (int)points[i].x; 436 final_points[i].y = (int)points[i].y; 437 } 438 } 439 440 /* Draw the points! */ 441 if (renderer->blendMode == SDL_BLENDMODE_NONE) { 442 Uint32 color = SDL_MapRGBA(surface->format, 443 renderer->r, renderer->g, renderer->b, 444 renderer->a); 445 446 status = SDL_DrawPoints(surface, final_points, count, color); 447 } else { 448 status = SDL_BlendPoints(surface, final_points, count, 449 renderer->blendMode, 450 renderer->r, renderer->g, renderer->b, 451 renderer->a); 452 } 453 SDL_stack_free(final_points); 454 455 return status; 456} 457 458static int 459SW_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points, 460 int count) 461{ 462 SDL_Surface *surface = SW_ActivateRenderer(renderer); 463 SDL_Point *final_points; 464 int i, status; 465 466 if (!surface) { 467 return -1; 468 } 469 470 final_points = SDL_stack_alloc(SDL_Point, count); 471 if (!final_points) { 472 return SDL_OutOfMemory(); 473 } 474 if (renderer->viewport.x || renderer->viewport.y) { 475 int x = renderer->viewport.x; 476 int y = renderer->viewport.y; 477 478 for (i = 0; i < count; ++i) { 479 final_points[i].x = (int)(x + points[i].x); 480 final_points[i].y = (int)(y + points[i].y); 481 } 482 } else { 483 for (i = 0; i < count; ++i) { 484 final_points[i].x = (int)points[i].x; 485 final_points[i].y = (int)points[i].y; 486 } 487 } 488 489 /* Draw the lines! */ 490 if (renderer->blendMode == SDL_BLENDMODE_NONE) { 491 Uint32 color = SDL_MapRGBA(surface->format, 492 renderer->r, renderer->g, renderer->b, 493 renderer->a); 494 495 status = SDL_DrawLines(surface, final_points, count, color); 496 } else { 497 status = SDL_BlendLines(surface, final_points, count, 498 renderer->blendMode, 499 renderer->r, renderer->g, renderer->b, 500 renderer->a); 501 } 502 SDL_stack_free(final_points); 503 504 return status; 505} 506 507static int 508SW_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects, int count) 509{ 510 SDL_Surface *surface = SW_ActivateRenderer(renderer); 511 SDL_Rect *final_rects; 512 int i, status; 513 514 if (!surface) { 515 return -1; 516 } 517 518 final_rects = SDL_stack_alloc(SDL_Rect, count); 519 if (!final_rects) { 520 return SDL_OutOfMemory(); 521 } 522 if (renderer->viewport.x || renderer->viewport.y) { 523 int x = renderer->viewport.x; 524 int y = renderer->viewport.y; 525 526 for (i = 0; i < count; ++i) { 527 final_rects[i].x = (int)(x + rects[i].x); 528 final_rects[i].y = (int)(y + rects[i].y); 529 final_rects[i].w = SDL_max((int)rects[i].w, 1); 530 final_rects[i].h = SDL_max((int)rects[i].h, 1); 531 } 532 } else { 533 for (i = 0; i < count; ++i) { 534 final_rects[i].x = (int)rects[i].x; 535 final_rects[i].y = (int)rects[i].y; 536 final_rects[i].w = SDL_max((int)rects[i].w, 1); 537 final_rects[i].h = SDL_max((int)rects[i].h, 1); 538 } 539 } 540 541 if (renderer->blendMode == SDL_BLENDMODE_NONE) { 542 Uint32 color = SDL_MapRGBA(surface->format, 543 renderer->r, renderer->g, renderer->b, 544 renderer->a); 545 status = SDL_FillRects(surface, final_rects, count, color); 546 } else { 547 status = SDL_BlendFillRects(surface, final_rects, count, 548 renderer->blendMode, 549 renderer->r, renderer->g, renderer->b, 550 renderer->a); 551 } 552 SDL_stack_free(final_rects); 553 554 return status; 555} 556 557static int 558SW_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 559 const SDL_Rect * srcrect, const SDL_FRect * dstrect) 560{ 561 SDL_Surface *surface = SW_ActivateRenderer(renderer); 562 SDL_Surface *src = (SDL_Surface *) texture->driverdata; 563 SDL_Rect final_rect; 564 565 if (!surface) { 566 return -1; 567 } 568 569 if (renderer->viewport.x || renderer->viewport.y) { 570 final_rect.x = (int)(renderer->viewport.x + dstrect->x); 571 final_rect.y = (int)(renderer->viewport.y + dstrect->y); 572 } else { 573 final_rect.x = (int)dstrect->x; 574 final_rect.y = (int)dstrect->y; 575 } 576 final_rect.w = (int)dstrect->w; 577 final_rect.h = (int)dstrect->h; 578 579 if ( srcrect->w == final_rect.w && srcrect->h == final_rect.h ) { 580 return SDL_BlitSurface(src, srcrect, surface, &final_rect); 581 } else { 582 /* If scaling is ever done, permanently disable RLE (which doesn't support scaling) 583 * to avoid potentially frequent RLE encoding/decoding. 584 */ 585 SDL_SetSurfaceRLE(surface, 0); 586 return SDL_BlitScaled(src, srcrect, surface, &final_rect); 587 } 588} 589 590static int 591SW_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 592 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 593 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) 594{ 595 SDL_Surface *surface = SW_ActivateRenderer(renderer); 596 SDL_Surface *src = (SDL_Surface *) texture->driverdata; 597 SDL_Rect final_rect, tmp_rect; 598 SDL_Surface *src_clone, *src_rotated, *src_scaled; 599 SDL_Surface *mask = NULL, *mask_rotated = NULL; 600 int retval = 0, dstwidth, dstheight, abscenterx, abscentery; 601 double cangle, sangle, px, py, p1x, p1y, p2x, p2y, p3x, p3y, p4x, p4y; 602 SDL_BlendMode blendmode; 603 Uint8 alphaMod, rMod, gMod, bMod; 604 int applyModulation = SDL_FALSE; 605 int blitRequired = SDL_FALSE; 606 int isOpaque = SDL_FALSE; 607 608 if (!surface) { 609 return -1; 610 } 611 612 if (renderer->viewport.x || renderer->viewport.y) { 613 final_rect.x = (int)(renderer->viewport.x + dstrect->x); 614 final_rect.y = (int)(renderer->viewport.y + dstrect->y); 615 } else { 616 final_rect.x = (int)dstrect->x; 617 final_rect.y = (int)dstrect->y; 618 } 619 final_rect.w = (int)dstrect->w; 620 final_rect.h = (int)dstrect->h; 621 622 tmp_rect = final_rect; 623 tmp_rect.x = 0; 624 tmp_rect.y = 0; 625 626 /* It is possible to encounter an RLE encoded surface here and locking it is 627 * necessary because this code is going to access the pixel buffer directly. 628 */ 629 if (SDL_MUSTLOCK(src)) { 630 SDL_LockSurface(src); 631 } 632 633 /* Clone the source surface but use its pixel buffer directly. 634 * The original source surface must be treated as read-only. 635 */ 636 src_clone = SDL_CreateRGBSurfaceFrom(src->pixels, src->w, src->h, src->format->BitsPerPixel, src->pitch, 637 src->format->Rmask, src->format->Gmask, 638 src->format->Bmask, src->format->Amask); 639 if (src_clone == NULL) { 640 if (SDL_MUSTLOCK(src)) { 641 SDL_UnlockSurface(src); 642 } 643 return -1; 644 } 645 646 SDL_GetSurfaceBlendMode(src, &blendmode); 647 SDL_GetSurfaceAlphaMod(src, &alphaMod); 648 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); 649 650 /* SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. */ 651 if (src->format->BitsPerPixel != 32 || SDL_PIXELLAYOUT(src->format->format) != SDL_PACKEDLAYOUT_8888 || !src->format->Amask) { 652 blitRequired = SDL_TRUE; 653 } 654 655 /* If scaling and cropping is necessary, it has to be taken care of before the rotation. */ 656 if (!(srcrect->w == final_rect.w && srcrect->h == final_rect.h && srcrect->x == 0 && srcrect->y == 0)) { 657 blitRequired = SDL_TRUE; 658 } 659 660 /* The color and alpha modulation has to be applied before the rotation when using the NONE and MOD blend modes. */ 661 if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD) && (alphaMod & rMod & gMod & bMod) != 255) { 662 applyModulation = SDL_TRUE; 663 SDL_SetSurfaceAlphaMod(src_clone, alphaMod); 664 SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod); 665 } 666 667 /* Opaque surfaces are much easier to handle with the NONE blend mode. */ 668 if (blendmode == SDL_BLENDMODE_NONE && !src->format->Amask && alphaMod == 255) { 669 isOpaque = SDL_TRUE; 670 } 671 672 /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used 673 * to clear the pixels in the destination surface. The other steps are explained below. 674 */ 675 if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) { 676 mask = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32, 677 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 678 if (mask == NULL) { 679 retval = -1; 680 } else { 681 SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD); 682 } 683 } 684 685 /* Create a new surface should there be a format mismatch or if scaling, cropping, 686 * or modulation is required. It's possible to use the source surface directly otherwise. 687 */ 688 if (!retval && (blitRequired || applyModulation)) { 689 SDL_Rect scale_rect = tmp_rect; 690 src_scaled = SDL_CreateRGBSurface(0, final_rect.w, final_rect.h, 32, 691 0x00ff0000, 0x0000ff00, 0x000000ff, 0xff000000); 692 if (src_scaled == NULL) { 693 retval = -1; 694 } else { 695 SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE); 696 retval = SDL_BlitScaled(src_clone, srcrect, src_scaled, &scale_rect); 697 SDL_FreeSurface(src_clone); 698 src_clone = src_scaled; 699 src_scaled = NULL; 700 } 701 } 702 703 /* SDLgfx_rotateSurface is going to make decisions depending on the blend mode. */ 704 SDL_SetSurfaceBlendMode(src_clone, blendmode); 705 706 if (!retval) { 707 SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, &dstwidth, &dstheight, &cangle, &sangle); 708 src_rotated = SDLgfx_rotateSurface(src_clone, angle, dstwidth/2, dstheight/2, (texture->scaleMode == SDL_ScaleModeNearest) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, dstwidth, dstheight, cangle, sangle); 709 if (src_rotated == NULL) { 710 retval = -1; 711 } 712 if (!retval && mask != NULL) { 713 /* The mask needed for the NONE blend mode gets rotated with the same parameters. */ 714 mask_rotated = SDLgfx_rotateSurface(mask, angle, dstwidth/2, dstheight/2, SDL_FALSE, 0, 0, dstwidth, dstheight, cangle, sangle); 715 if (mask_rotated == NULL) { 716 retval = -1; 717 } 718 } 719 if (!retval) { 720 /* Find out where the new origin is by rotating the four final_rect points around the center and then taking the extremes */ 721 abscenterx = final_rect.x + (int)center->x; 722 abscentery = final_rect.y + (int)center->y; 723 /* Compensate the angle inversion to match the behaviour of the other backends */ 724 sangle = -sangle; 725 726 /* Top Left */ 727 px = final_rect.x - abscenterx; 728 py = final_rect.y - abscentery; 729 p1x = px * cangle - py * sangle + abscenterx; 730 p1y = px * sangle + py * cangle + abscentery; 731 732 /* Top Right */ 733 px = final_rect.x + final_rect.w - abscenterx; 734 py = final_rect.y - abscentery; 735 p2x = px * cangle - py * sangle + abscenterx; 736 p2y = px * sangle + py * cangle + abscentery; 737 738 /* Bottom Left */ 739 px = final_rect.x - abscenterx; 740 py = final_rect.y + final_rect.h - abscentery; 741 p3x = px * cangle - py * sangle + abscenterx; 742 p3y = px * sangle + py * cangle + abscentery; 743 744 /* Bottom Right */ 745 px = final_rect.x + final_rect.w - abscenterx; 746 py = final_rect.y + final_rect.h - abscentery; 747 p4x = px * cangle - py * sangle + abscenterx; 748 p4y = px * sangle + py * cangle + abscentery; 749 750 tmp_rect.x = (int)MIN(MIN(p1x, p2x), MIN(p3x, p4x)); 751 tmp_rect.y = (int)MIN(MIN(p1y, p2y), MIN(p3y, p4y)); 752 tmp_rect.w = dstwidth; 753 tmp_rect.h = dstheight; 754 755 /* The NONE blend mode needs some special care with non-opaque surfaces. 756 * Other blend modes or opaque surfaces can be blitted directly. 757 */ 758 if (blendmode != SDL_BLENDMODE_NONE || isOpaque) { 759 if (applyModulation == SDL_FALSE) { 760 /* If the modulation wasn't already applied, make it happen now. */ 761 SDL_SetSurfaceAlphaMod(src_rotated, alphaMod); 762 SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod); 763 } 764 retval = SDL_BlitSurface(src_rotated, NULL, surface, &tmp_rect); 765 } else { 766 /* The NONE blend mode requires three steps to get the pixels onto the destination surface. 767 * First, the area where the rotated pixels will be blitted to get set to zero. 768 * This is accomplished by simply blitting a mask with the NONE blend mode. 769 * The colorkey set by the rotate function will discard the correct pixels. 770 */ 771 SDL_Rect mask_rect = tmp_rect; 772 SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE); 773 retval = SDL_BlitSurface(mask_rotated, NULL, surface, &mask_rect); 774 if (!retval) { 775 /* The next step copies the alpha value. This is done with the BLEND blend mode and 776 * by modulating the source colors with 0. Since the destination is all zeros, this 777 * will effectively set the destination alpha to the source alpha. 778 */ 779 SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0); 780 mask_rect = tmp_rect; 781 retval = SDL_BlitSurface(src_rotated, NULL, surface, &mask_rect); 782 if (!retval) { 783 /* The last step gets the color values in place. The ADD blend mode simply adds them to 784 * the destination (where the color values are all zero). However, because the ADD blend 785 * mode modulates the colors with the alpha channel, a surface without an alpha mask needs 786 * to be created. This makes all source pixels opaque and the colors get copied correctly. 787 */ 788 SDL_Surface *src_rotated_rgb; 789 src_rotated_rgb = SDL_CreateRGBSurfaceFrom(src_rotated->pixels, src_rotated->w, src_rotated->h, 790 src_rotated->format->BitsPerPixel, src_rotated->pitch, 791 src_rotated->format->Rmask, src_rotated->format->Gmask, 792 src_rotated->format->Bmask, 0); 793 if (src_rotated_rgb == NULL) { 794 retval = -1; 795 } else { 796 SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); 797 retval = SDL_BlitSurface(src_rotated_rgb, NULL, surface, &tmp_rect); 798 SDL_FreeSurface(src_rotated_rgb); 799 } 800 } 801 } 802 SDL_FreeSurface(mask_rotated); 803 } 804 if (src_rotated != NULL) { 805 SDL_FreeSurface(src_rotated); 806 } 807 } 808 } 809 810 if (SDL_MUSTLOCK(src)) { 811 SDL_UnlockSurface(src); 812 } 813 if (mask != NULL) { 814 SDL_FreeSurface(mask); 815 } 816 if (src_clone != NULL) { 817 SDL_FreeSurface(src_clone); 818 } 819 return retval; 820} 821 822static int 823SW_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 824 Uint32 format, void * pixels, int pitch) 825{ 826 SDL_Surface *surface = SW_ActivateRenderer(renderer); 827 Uint32 src_format; 828 void *src_pixels; 829 830 if (!surface) { 831 return -1; 832 } 833 834 /* NOTE: The rect is already adjusted according to the viewport by 835 * SDL_RenderReadPixels. 836 */ 837 838 if (rect->x < 0 || rect->x+rect->w > surface->w || 839 rect->y < 0 || rect->y+rect->h > surface->h) { 840 return SDL_SetError("Tried to read outside of surface bounds"); 841 } 842 843 src_format = surface->format->format; 844 src_pixels = (void*)((Uint8 *) surface->pixels + 845 rect->y * surface->pitch + 846 rect->x * surface->format->BytesPerPixel); 847 848 return SDL_ConvertPixels(rect->w, rect->h, 849 src_format, src_pixels, surface->pitch, 850 format, pixels, pitch); 851} 852 853static void 854SW_RenderPresent(SDL_Renderer * renderer) 855{ 856 SDL_Window *window = renderer->window; 857 858 if (window) { 859 SDL_UpdateWindowSurface(window); 860 } 861} 862 863static void 864SW_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture) 865{ 866 SDL_Surface *surface = (SDL_Surface *) texture->driverdata; 867 868 SDL_FreeSurface(surface); 869} 870 871static void 872SW_DestroyRenderer(SDL_Renderer * renderer) 873{ 874 SW_RenderData *data = (SW_RenderData *) renderer->driverdata; 875 876 SDL_free(data); 877 SDL_free(renderer); 878} 879 880#endif /* !SDL_RENDER_DISABLED */ 881 882/* vi: set ts=4 sw=4 expandtab: */ 883
[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.