Atlas - SDL_render_sw.c
Home / ext / SDL / src / render / software Lines: 1 | Size: 46031 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)][FILE BEGIN]1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2025 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#ifdef SDL_VIDEO_RENDER_SW 24 25#include "../SDL_sysrender.h" 26#include "SDL_render_sw_c.h" 27 28#include "SDL_draw.h" 29#include "SDL_blendfillrect.h" 30#include "SDL_blendline.h" 31#include "SDL_blendpoint.h" 32#include "SDL_drawline.h" 33#include "SDL_drawpoint.h" 34#include "SDL_triangle.h" 35#include "../../video/SDL_pixels_c.h" 36#include "../../video/SDL_rotate.h" 37 38// SDL surface based renderer implementation 39 40typedef struct 41{ 42 const SDL_Rect *viewport; 43 const SDL_Rect *cliprect; 44 bool surface_cliprect_dirty; 45 SDL_Color color; 46} SW_DrawStateCache; 47 48typedef struct 49{ 50 SDL_Surface *surface; 51 SDL_Surface *window; 52} SW_RenderData; 53 54static SDL_Surface *SW_ActivateRenderer(SDL_Renderer *renderer) 55{ 56 SW_RenderData *data = (SW_RenderData *)renderer->internal; 57 58 if (!data->surface) { 59 data->surface = data->window; 60 } 61 if (!data->surface) { 62 SDL_Surface *surface = SDL_GetWindowSurface(renderer->window); 63 if (surface) { 64 data->surface = data->window = surface; 65 } 66 } 67 return data->surface; 68} 69 70static void SW_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event) 71{ 72 SW_RenderData *data = (SW_RenderData *)renderer->internal; 73 74 if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) { 75 data->surface = NULL; 76 data->window = NULL; 77 } 78} 79 80static bool SW_GetOutputSize(SDL_Renderer *renderer, int *w, int *h) 81{ 82 SW_RenderData *data = (SW_RenderData *)renderer->internal; 83 84 if (data->surface) { 85 if (w) { 86 *w = data->surface->w; 87 } 88 if (h) { 89 *h = data->surface->h; 90 } 91 return true; 92 } 93 94 if (renderer->window) { 95 SDL_GetWindowSizeInPixels(renderer->window, w, h); 96 return true; 97 } 98 99 return SDL_SetError("Software renderer doesn't have an output surface"); 100} 101 102static bool SW_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 103{ 104 SDL_Palette *surface_palette = SDL_CreatePalette(256); 105 if (!surface_palette) { 106 return false; 107 } 108 palette->internal = surface_palette; 109 return true; 110} 111 112static bool SW_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors) 113{ 114 SDL_Palette *surface_palette = (SDL_Palette *)palette->internal; 115 return SDL_SetPaletteColors(surface_palette, colors, 0, ncolors); 116} 117 118static void SW_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette) 119{ 120 SDL_Palette *surface_palette = (SDL_Palette *)palette->internal; 121 SDL_DestroyPalette(surface_palette); 122} 123 124static bool SW_ChangeTexturePalette(SDL_Renderer *renderer, SDL_Texture *texture) 125{ 126 SDL_Surface *surface = (SDL_Surface *)texture->internal; 127 SDL_Palette *surface_palette = NULL; 128 if (texture->palette) { 129 surface_palette = (SDL_Palette *)texture->palette->internal; 130 } 131 return SDL_SetSurfacePalette(surface, surface_palette); 132} 133 134static bool SW_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props) 135{ 136 SDL_Surface *surface = SDL_CreateSurface(texture->w, texture->h, texture->format); 137 if (!surface) { 138 return SDL_SetError("Can't create surface"); 139 } 140 texture->internal = surface; 141 142 Uint8 r = (Uint8)SDL_roundf(SDL_clamp(texture->color.r, 0.0f, 1.0f) * 255.0f); 143 Uint8 g = (Uint8)SDL_roundf(SDL_clamp(texture->color.g, 0.0f, 1.0f) * 255.0f); 144 Uint8 b = (Uint8)SDL_roundf(SDL_clamp(texture->color.b, 0.0f, 1.0f) * 255.0f); 145 Uint8 a = (Uint8)SDL_roundf(SDL_clamp(texture->color.a, 0.0f, 1.0f) * 255.0f); 146 SDL_SetSurfaceColorMod(surface, r, g, b); 147 SDL_SetSurfaceAlphaMod(surface, a); 148 SDL_SetSurfaceBlendMode(surface, texture->blendMode); 149 150 if (SDL_ISPIXELFORMAT_INDEXED(surface->format)) { 151 surface->palette = SDL_CreatePalette((1 << SDL_BITSPERPIXEL(surface->format))); 152 if (!surface->palette) { 153 return SDL_SetError("Can't create palette"); 154 } 155 } 156 157 if (texture->access == SDL_TEXTUREACCESS_STATIC) { 158 SDL_SetSurfaceRLE(surface, true); 159 } 160 161 return true; 162} 163 164static bool SW_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, 165 const SDL_Rect *rect, const void *pixels, int pitch) 166{ 167 SDL_Surface *surface = (SDL_Surface *)texture->internal; 168 Uint8 *src, *dst; 169 int row; 170 size_t length; 171 172 if (SDL_MUSTLOCK(surface)) { 173 if (!SDL_LockSurface(surface)) { 174 return false; 175 } 176 } 177 src = (Uint8 *)pixels; 178 dst = (Uint8 *)surface->pixels + 179 rect->y * surface->pitch + 180 rect->x * surface->fmt->bytes_per_pixel; 181 length = (size_t)rect->w * surface->fmt->bytes_per_pixel; 182 for (row = 0; row < rect->h; ++row) { 183 SDL_memcpy(dst, src, length); 184 src += pitch; 185 dst += surface->pitch; 186 } 187 if (SDL_MUSTLOCK(surface)) { 188 SDL_UnlockSurface(surface); 189 } 190 return true; 191} 192 193static bool SW_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture, 194 const SDL_Rect *rect, void **pixels, int *pitch) 195{ 196 SDL_Surface *surface = (SDL_Surface *)texture->internal; 197 198 *pixels = 199 (void *)((Uint8 *)surface->pixels + rect->y * surface->pitch + 200 rect->x * surface->fmt->bytes_per_pixel); 201 *pitch = surface->pitch; 202 return true; 203} 204 205static void SW_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture) 206{ 207} 208 209static bool SW_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture) 210{ 211 SW_RenderData *data = (SW_RenderData *)renderer->internal; 212 213 if (texture) { 214 data->surface = (SDL_Surface *)texture->internal; 215 } else { 216 data->surface = data->window; 217 } 218 return true; 219} 220 221static bool SW_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd) 222{ 223 return true; // nothing to do in this backend. 224} 225 226static bool SW_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count) 227{ 228 SDL_Point *verts = (SDL_Point *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Point), 0, &cmd->data.draw.first); 229 int i; 230 231 if (!verts) { 232 return false; 233 } 234 235 cmd->data.draw.count = count; 236 237 for (i = 0; i < count; i++, verts++, points++) { 238 verts->x = (int)points->x; 239 verts->y = (int)points->y; 240 } 241 242 return true; 243} 244 245static bool SW_QueueFillRects(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count) 246{ 247 SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, count * sizeof(SDL_Rect), 0, &cmd->data.draw.first); 248 int i; 249 250 if (!verts) { 251 return false; 252 } 253 254 cmd->data.draw.count = count; 255 256 for (i = 0; i < count; i++, verts++, rects++) { 257 verts->x = (int)rects->x; 258 verts->w = (int)rects->w; 259 if (verts->w < 0) { 260 verts->w = -verts->w; 261 verts->x -= verts->w; 262 } 263 verts->y = (int)rects->y; 264 verts->h = (int)rects->h; 265 if (verts->h < 0) { 266 verts->h = -verts->h; 267 verts->y -= verts->h; 268 } 269 } 270 271 return true; 272} 273 274static bool SW_QueueCopy(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 275 const SDL_FRect *srcrect, const SDL_FRect *dstrect) 276{ 277 SDL_Rect *verts = (SDL_Rect *)SDL_AllocateRenderVertices(renderer, 2 * sizeof(SDL_Rect), 0, &cmd->data.draw.first); 278 279 if (!verts) { 280 return false; 281 } 282 283 cmd->data.draw.count = 1; 284 285 verts->x = (int)srcrect->x; 286 verts->y = (int)srcrect->y; 287 verts->w = (int)srcrect->w; 288 verts->h = (int)srcrect->h; 289 verts++; 290 291 verts->x = (int)dstrect->x; 292 verts->y = (int)dstrect->y; 293 verts->w = (int)dstrect->w; 294 verts->h = (int)dstrect->h; 295 296 return true; 297} 298 299typedef struct CopyExData 300{ 301 SDL_Rect srcrect; 302 SDL_Rect dstrect; 303 double angle; 304 SDL_FPoint center; 305 SDL_FlipMode flip; 306 float scale_x; 307 float scale_y; 308} CopyExData; 309 310static bool SW_QueueCopyEx(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 311 const SDL_FRect *srcrect, const SDL_FRect *dstrect, 312 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y) 313{ 314 CopyExData *verts = (CopyExData *)SDL_AllocateRenderVertices(renderer, sizeof(CopyExData), 0, &cmd->data.draw.first); 315 316 if (!verts) { 317 return false; 318 } 319 320 cmd->data.draw.count = 1; 321 322 verts->srcrect.x = (int)srcrect->x; 323 verts->srcrect.y = (int)srcrect->y; 324 verts->srcrect.w = (int)srcrect->w; 325 verts->srcrect.h = (int)srcrect->h; 326 verts->dstrect.x = (int)dstrect->x; 327 verts->dstrect.y = (int)dstrect->y; 328 verts->dstrect.w = (int)dstrect->w; 329 verts->dstrect.h = (int)dstrect->h; 330 verts->angle = angle; 331 SDL_copyp(&verts->center, center); 332 verts->flip = flip; 333 verts->scale_x = scale_x; 334 verts->scale_y = scale_y; 335 336 return true; 337} 338 339static bool Blit_to_Screen(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *surface, SDL_Rect *dstrect, 340 float scale_x, float scale_y, SDL_ScaleMode scaleMode) 341{ 342 bool result; 343 // Renderer scaling, if needed 344 if (scale_x != 1.0f || scale_y != 1.0f) { 345 SDL_Rect r; 346 r.x = (int)((float)dstrect->x * scale_x); 347 r.y = (int)((float)dstrect->y * scale_y); 348 r.w = (int)((float)dstrect->w * scale_x); 349 r.h = (int)((float)dstrect->h * scale_y); 350 result = SDL_BlitSurfaceScaled(src, srcrect, surface, &r, scaleMode); 351 } else { 352 result = SDL_BlitSurface(src, srcrect, surface, dstrect); 353 } 354 return result; 355} 356 357static bool SW_RenderCopyEx(SDL_Renderer *renderer, SDL_Surface *surface, SDL_Texture *texture, 358 const SDL_Rect *srcrect, const SDL_Rect *final_rect, 359 const double angle, const SDL_FPoint *center, const SDL_FlipMode flip, float scale_x, float scale_y, const SDL_ScaleMode scaleMode) 360{ 361 SDL_Surface *src = (SDL_Surface *)texture->internal; 362 SDL_Rect tmp_rect; 363 SDL_Surface *src_clone, *src_rotated, *src_scaled; 364 SDL_Surface *mask = NULL, *mask_rotated = NULL; 365 bool result = true; 366 SDL_BlendMode blendmode; 367 Uint8 alphaMod, rMod, gMod, bMod; 368 int applyModulation = false; 369 int blitRequired = false; 370 int isOpaque = false; 371 372 if (!SDL_SurfaceValid(surface)) { 373 return false; 374 } 375 376 tmp_rect.x = 0; 377 tmp_rect.y = 0; 378 tmp_rect.w = final_rect->w; 379 tmp_rect.h = final_rect->h; 380 381 /* It is possible to encounter an RLE encoded surface here and locking it is 382 * necessary because this code is going to access the pixel buffer directly. 383 */ 384 if (SDL_MUSTLOCK(src)) { 385 if (!SDL_LockSurface(src)) { 386 return false; 387 } 388 } 389 390 /* Clone the source surface but use its pixel buffer directly. 391 * The original source surface must be treated as read-only. 392 */ 393 src_clone = SDL_CreateSurfaceFrom(src->w, src->h, src->format, src->pixels, src->pitch); 394 if (!src_clone) { 395 if (SDL_MUSTLOCK(src)) { 396 SDL_UnlockSurface(src); 397 } 398 return false; 399 } 400 if (src->palette) { 401 SDL_SetSurfacePalette(src_clone, src->palette); 402 } 403 404 SDL_GetSurfaceBlendMode(src, &blendmode); 405 SDL_GetSurfaceAlphaMod(src, &alphaMod); 406 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); 407 408 // SDLgfx_rotateSurface only accepts 32-bit surfaces with a 8888 layout. Everything else has to be converted. 409 if (!(SDL_BITSPERPIXEL(src->format) == 32 && SDL_PIXELLAYOUT(src->format) == SDL_PACKEDLAYOUT_8888)) { 410 blitRequired = true; 411 } 412 413 // If scaling and cropping is necessary, it has to be taken care of before the rotation. 414 if (!(srcrect->w == final_rect->w && srcrect->h == final_rect->h && srcrect->x == 0 && srcrect->y == 0)) { 415 blitRequired = true; 416 } 417 418 // srcrect is not selecting the whole src surface, so cropping is needed 419 if (!(srcrect->w == src->w && srcrect->h == src->h && srcrect->x == 0 && srcrect->y == 0)) { 420 blitRequired = true; 421 } 422 423 // The color and alpha modulation has to be applied before the rotation when using the NONE, MOD or MUL blend modes. 424 if ((blendmode == SDL_BLENDMODE_NONE || blendmode == SDL_BLENDMODE_MOD || blendmode == SDL_BLENDMODE_MUL) && (alphaMod & rMod & gMod & bMod) != 255) { 425 applyModulation = true; 426 SDL_SetSurfaceAlphaMod(src_clone, alphaMod); 427 SDL_SetSurfaceColorMod(src_clone, rMod, gMod, bMod); 428 } 429 430 // Opaque surfaces are much easier to handle with the NONE blend mode. 431 if (blendmode == SDL_BLENDMODE_NONE && !SDL_ISPIXELFORMAT_ALPHA(src->format) && alphaMod == 255) { 432 isOpaque = true; 433 } 434 435 /* The NONE blend mode requires a mask for non-opaque surfaces. This mask will be used 436 * to clear the pixels in the destination surface. The other steps are explained below. 437 */ 438 if (blendmode == SDL_BLENDMODE_NONE && !isOpaque) { 439 mask = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888); 440 if (!mask) { 441 result = false; 442 } else { 443 SDL_SetSurfaceBlendMode(mask, SDL_BLENDMODE_MOD); 444 } 445 } 446 447 /* Create a new surface should there be a format mismatch or if scaling, cropping, 448 * or modulation is required. It's possible to use the source surface directly otherwise. 449 */ 450 if (result && (blitRequired || applyModulation)) { 451 SDL_Rect scale_rect = tmp_rect; 452 src_scaled = SDL_CreateSurface(final_rect->w, final_rect->h, SDL_PIXELFORMAT_ARGB8888); 453 if (!src_scaled) { 454 result = false; 455 } else { 456 SDL_SetSurfaceBlendMode(src_clone, SDL_BLENDMODE_NONE); 457 result = SDL_BlitSurfaceScaled(src_clone, srcrect, src_scaled, &scale_rect, scaleMode); 458 SDL_DestroySurface(src_clone); 459 src_clone = src_scaled; 460 src_scaled = NULL; 461 } 462 } 463 464 // SDLgfx_rotateSurface is going to make decisions depending on the blend mode. 465 SDL_SetSurfaceBlendMode(src_clone, blendmode); 466 467 if (result) { 468 SDL_Rect rect_dest; 469 double cangle, sangle; 470 471 SDLgfx_rotozoomSurfaceSizeTrig(tmp_rect.w, tmp_rect.h, angle, center, 472 &rect_dest, &cangle, &sangle); 473 src_rotated = SDLgfx_rotateSurface(src_clone, angle, 474 (scaleMode == SDL_SCALEMODE_NEAREST || scaleMode == SDL_SCALEMODE_PIXELART) ? 0 : 1, flip & SDL_FLIP_HORIZONTAL, flip & SDL_FLIP_VERTICAL, 475 &rect_dest, cangle, sangle, center); 476 if (!src_rotated) { 477 result = false; 478 } 479 if (result && mask) { 480 // The mask needed for the NONE blend mode gets rotated with the same parameters. 481 mask_rotated = SDLgfx_rotateSurface(mask, angle, 482 false, 0, 0, 483 &rect_dest, cangle, sangle, center); 484 if (!mask_rotated) { 485 result = false; 486 } 487 } 488 if (result) { 489 490 tmp_rect.x = final_rect->x + rect_dest.x; 491 tmp_rect.y = final_rect->y + rect_dest.y; 492 tmp_rect.w = rect_dest.w; 493 tmp_rect.h = rect_dest.h; 494 495 /* The NONE blend mode needs some special care with non-opaque surfaces. 496 * Other blend modes or opaque surfaces can be blitted directly. 497 */ 498 if (blendmode != SDL_BLENDMODE_NONE || isOpaque) { 499 if (applyModulation == false) { 500 // If the modulation wasn't already applied, make it happen now. 501 SDL_SetSurfaceAlphaMod(src_rotated, alphaMod); 502 SDL_SetSurfaceColorMod(src_rotated, rMod, gMod, bMod); 503 } 504 // Renderer scaling, if needed 505 result = Blit_to_Screen(src_rotated, NULL, surface, &tmp_rect, scale_x, scale_y, scaleMode); 506 } else { 507 /* The NONE blend mode requires three steps to get the pixels onto the destination surface. 508 * First, the area where the rotated pixels will be blitted to get set to zero. 509 * This is accomplished by simply blitting a mask with the NONE blend mode. 510 * The colorkey set by the rotate function will discard the correct pixels. 511 */ 512 SDL_Rect mask_rect = tmp_rect; 513 SDL_SetSurfaceBlendMode(mask_rotated, SDL_BLENDMODE_NONE); 514 // Renderer scaling, if needed 515 result = Blit_to_Screen(mask_rotated, NULL, surface, &mask_rect, scale_x, scale_y, scaleMode); 516 if (result) { 517 /* The next step copies the alpha value. This is done with the BLEND blend mode and 518 * by modulating the source colors with 0. Since the destination is all zeros, this 519 * will effectively set the destination alpha to the source alpha. 520 */ 521 SDL_SetSurfaceColorMod(src_rotated, 0, 0, 0); 522 mask_rect = tmp_rect; 523 // Renderer scaling, if needed 524 result = Blit_to_Screen(src_rotated, NULL, surface, &mask_rect, scale_x, scale_y, scaleMode); 525 if (result) { 526 /* The last step gets the color values in place. The ADD blend mode simply adds them to 527 * the destination (where the color values are all zero). However, because the ADD blend 528 * mode modulates the colors with the alpha channel, a surface without an alpha mask needs 529 * to be created. This makes all source pixels opaque and the colors get copied correctly. 530 */ 531 SDL_Surface *src_rotated_rgb = SDL_CreateSurfaceFrom(src_rotated->w, src_rotated->h, src_rotated->format, src_rotated->pixels, src_rotated->pitch); 532 if (!src_rotated_rgb) { 533 result = false; 534 } else { 535 SDL_SetSurfaceBlendMode(src_rotated_rgb, SDL_BLENDMODE_ADD); 536 // Renderer scaling, if needed 537 result = Blit_to_Screen(src_rotated_rgb, NULL, surface, &tmp_rect, scale_x, scale_y, scaleMode); 538 SDL_DestroySurface(src_rotated_rgb); 539 } 540 } 541 } 542 SDL_DestroySurface(mask_rotated); 543 } 544 if (src_rotated) { 545 SDL_DestroySurface(src_rotated); 546 } 547 } 548 } 549 550 if (SDL_MUSTLOCK(src)) { 551 SDL_UnlockSurface(src); 552 } 553 if (mask) { 554 SDL_DestroySurface(mask); 555 } 556 if (src_clone) { 557 SDL_DestroySurface(src_clone); 558 } 559 return result; 560} 561 562typedef struct GeometryFillData 563{ 564 SDL_Point dst; 565 SDL_Color color; 566} GeometryFillData; 567 568typedef struct GeometryCopyData 569{ 570 SDL_Point src; 571 SDL_Point dst; 572 SDL_Color color; 573} GeometryCopyData; 574 575static bool SW_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, 576 const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride, 577 int num_vertices, const void *indices, int num_indices, int size_indices, 578 float scale_x, float scale_y) 579{ 580 int i; 581 int count = indices ? num_indices : num_vertices; 582 void *verts; 583 size_t sz = texture ? sizeof(GeometryCopyData) : sizeof(GeometryFillData); 584 const float color_scale = cmd->data.draw.color_scale; 585 586 verts = SDL_AllocateRenderVertices(renderer, count * sz, 0, &cmd->data.draw.first); 587 if (!verts) { 588 return false; 589 } 590 591 cmd->data.draw.count = count; 592 size_indices = indices ? size_indices : 0; 593 594 if (texture) { 595 GeometryCopyData *ptr = (GeometryCopyData *)verts; 596 for (i = 0; i < count; i++) { 597 int j; 598 float *xy_; 599 SDL_FColor col_; 600 float *uv_; 601 if (size_indices == 4) { 602 j = ((const Uint32 *)indices)[i]; 603 } else if (size_indices == 2) { 604 j = ((const Uint16 *)indices)[i]; 605 } else if (size_indices == 1) { 606 j = ((const Uint8 *)indices)[i]; 607 } else { 608 j = i; 609 } 610 611 xy_ = (float *)((char *)xy + j * xy_stride); 612 col_ = *(SDL_FColor *)((char *)color + j * color_stride); 613 614 uv_ = (float *)((char *)uv + j * uv_stride); 615 616 ptr->src.x = (int)(uv_[0] * texture->w); 617 ptr->src.y = (int)(uv_[1] * texture->h); 618 619 ptr->dst.x = (int)(xy_[0] * scale_x); 620 ptr->dst.y = (int)(xy_[1] * scale_y); 621 trianglepoint_2_fixedpoint(&ptr->dst); 622 623 ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f); 624 ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f); 625 ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f); 626 ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f); 627 628 ptr++; 629 } 630 } else { 631 GeometryFillData *ptr = (GeometryFillData *)verts; 632 633 for (i = 0; i < count; i++) { 634 int j; 635 float *xy_; 636 SDL_FColor col_; 637 if (size_indices == 4) { 638 j = ((const Uint32 *)indices)[i]; 639 } else if (size_indices == 2) { 640 j = ((const Uint16 *)indices)[i]; 641 } else if (size_indices == 1) { 642 j = ((const Uint8 *)indices)[i]; 643 } else { 644 j = i; 645 } 646 647 xy_ = (float *)((char *)xy + j * xy_stride); 648 col_ = *(SDL_FColor *)((char *)color + j * color_stride); 649 650 ptr->dst.x = (int)(xy_[0] * scale_x); 651 ptr->dst.y = (int)(xy_[1] * scale_y); 652 trianglepoint_2_fixedpoint(&ptr->dst); 653 654 ptr->color.r = (Uint8)SDL_roundf(SDL_clamp(col_.r * color_scale, 0.0f, 1.0f) * 255.0f); 655 ptr->color.g = (Uint8)SDL_roundf(SDL_clamp(col_.g * color_scale, 0.0f, 1.0f) * 255.0f); 656 ptr->color.b = (Uint8)SDL_roundf(SDL_clamp(col_.b * color_scale, 0.0f, 1.0f) * 255.0f); 657 ptr->color.a = (Uint8)SDL_roundf(SDL_clamp(col_.a, 0.0f, 1.0f) * 255.0f); 658 659 ptr++; 660 } 661 } 662 return true; 663} 664 665static void PrepTextureForCopy(const SDL_RenderCommand *cmd, SW_DrawStateCache *drawstate) 666{ 667 const Uint8 r = drawstate->color.r; 668 const Uint8 g = drawstate->color.g; 669 const Uint8 b = drawstate->color.b; 670 const Uint8 a = drawstate->color.a; 671 const SDL_BlendMode blend = cmd->data.draw.blend; 672 SDL_Texture *texture = cmd->data.draw.texture; 673 SDL_Surface *surface = (SDL_Surface *)texture->internal; 674 675 // !!! FIXME: we can probably avoid some of these calls. 676 SDL_SetSurfaceColorMod(surface, r, g, b); 677 SDL_SetSurfaceAlphaMod(surface, a); 678 SDL_SetSurfaceBlendMode(surface, blend); 679} 680 681static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate) 682{ 683 if (drawstate->surface_cliprect_dirty) { 684 const SDL_Rect *viewport = drawstate->viewport; 685 const SDL_Rect *cliprect = drawstate->cliprect; 686 SDL_assert_release(viewport != NULL); // the higher level should have forced a SDL_RENDERCMD_SETVIEWPORT 687 688 if (cliprect && viewport) { 689 SDL_Rect clip_rect; 690 clip_rect.x = cliprect->x + viewport->x; 691 clip_rect.y = cliprect->y + viewport->y; 692 clip_rect.w = cliprect->w; 693 clip_rect.h = cliprect->h; 694 SDL_GetRectIntersection(viewport, &clip_rect, &clip_rect); 695 SDL_SetSurfaceClipRect(surface, &clip_rect); 696 } else { 697 SDL_SetSurfaceClipRect(surface, drawstate->viewport); 698 } 699 drawstate->surface_cliprect_dirty = false; 700 } 701} 702 703static void SW_InvalidateCachedState(SDL_Renderer *renderer) 704{ 705 // SW_DrawStateCache only lives during SW_RunCommandQueue, so nothing to do here! 706} 707 708 709static bool SW_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize) 710{ 711 SDL_Surface *surface = SW_ActivateRenderer(renderer); 712 SW_DrawStateCache drawstate; 713 714 if (!SDL_SurfaceValid(surface)) { 715 return false; 716 } 717 718 drawstate.viewport = NULL; 719 drawstate.cliprect = NULL; 720 drawstate.surface_cliprect_dirty = true; 721 drawstate.color.r = 0; 722 drawstate.color.g = 0; 723 drawstate.color.b = 0; 724 drawstate.color.a = 0; 725 726 while (cmd) { 727 switch (cmd->command) { 728 case SDL_RENDERCMD_SETDRAWCOLOR: 729 { 730 drawstate.color.r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 731 drawstate.color.g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 732 drawstate.color.b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 733 drawstate.color.a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); 734 break; 735 } 736 737 case SDL_RENDERCMD_SETVIEWPORT: 738 { 739 drawstate.viewport = &cmd->data.viewport.rect; 740 drawstate.surface_cliprect_dirty = true; 741 break; 742 } 743 744 case SDL_RENDERCMD_SETCLIPRECT: 745 { 746 drawstate.cliprect = cmd->data.cliprect.enabled ? &cmd->data.cliprect.rect : NULL; 747 drawstate.surface_cliprect_dirty = true; 748 break; 749 } 750 751 case SDL_RENDERCMD_CLEAR: 752 { 753 const Uint8 r = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.r * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 754 const Uint8 g = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.g * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 755 const Uint8 b = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.b * cmd->data.color.color_scale, 0.0f, 1.0f) * 255.0f); 756 const Uint8 a = (Uint8)SDL_roundf(SDL_clamp(cmd->data.color.color.a, 0.0f, 1.0f) * 255.0f); 757 // By definition the clear ignores the clip rect 758 SDL_SetSurfaceClipRect(surface, NULL); 759 SDL_FillSurfaceRect(surface, NULL, SDL_MapSurfaceRGBA(surface, r, g, b, a)); 760 drawstate.surface_cliprect_dirty = true; 761 break; 762 } 763 764 case SDL_RENDERCMD_DRAW_POINTS: 765 { 766 const Uint8 r = drawstate.color.r; 767 const Uint8 g = drawstate.color.g; 768 const Uint8 b = drawstate.color.b; 769 const Uint8 a = drawstate.color.a; 770 const int count = (int)cmd->data.draw.count; 771 SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first); 772 const SDL_BlendMode blend = cmd->data.draw.blend; 773 SetDrawState(surface, &drawstate); 774 775 // Apply viewport 776 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 777 int i; 778 for (i = 0; i < count; i++) { 779 verts[i].x += drawstate.viewport->x; 780 verts[i].y += drawstate.viewport->y; 781 } 782 } 783 784 if (blend == SDL_BLENDMODE_NONE) { 785 SDL_DrawPoints(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); 786 } else { 787 SDL_BlendPoints(surface, verts, count, blend, r, g, b, a); 788 } 789 break; 790 } 791 792 case SDL_RENDERCMD_DRAW_LINES: 793 { 794 const Uint8 r = drawstate.color.r; 795 const Uint8 g = drawstate.color.g; 796 const Uint8 b = drawstate.color.b; 797 const Uint8 a = drawstate.color.a; 798 const int count = (int)cmd->data.draw.count; 799 SDL_Point *verts = (SDL_Point *)(((Uint8 *)vertices) + cmd->data.draw.first); 800 const SDL_BlendMode blend = cmd->data.draw.blend; 801 SetDrawState(surface, &drawstate); 802 803 // Apply viewport 804 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 805 int i; 806 for (i = 0; i < count; i++) { 807 verts[i].x += drawstate.viewport->x; 808 verts[i].y += drawstate.viewport->y; 809 } 810 } 811 812 if (blend == SDL_BLENDMODE_NONE) { 813 SDL_DrawLines(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); 814 } else { 815 SDL_BlendLines(surface, verts, count, blend, r, g, b, a); 816 } 817 break; 818 } 819 820 case SDL_RENDERCMD_FILL_RECTS: 821 { 822 const Uint8 r = drawstate.color.r; 823 const Uint8 g = drawstate.color.g; 824 const Uint8 b = drawstate.color.b; 825 const Uint8 a = drawstate.color.a; 826 const int count = (int)cmd->data.draw.count; 827 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); 828 const SDL_BlendMode blend = cmd->data.draw.blend; 829 SetDrawState(surface, &drawstate); 830 831 // Apply viewport 832 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 833 int i; 834 for (i = 0; i < count; i++) { 835 verts[i].x += drawstate.viewport->x; 836 verts[i].y += drawstate.viewport->y; 837 } 838 } 839 840 if (blend == SDL_BLENDMODE_NONE) { 841 SDL_FillSurfaceRects(surface, verts, count, SDL_MapSurfaceRGBA(surface, r, g, b, a)); 842 } else { 843 SDL_BlendFillRects(surface, verts, count, blend, r, g, b, a); 844 } 845 break; 846 } 847 848 case SDL_RENDERCMD_COPY: 849 { 850 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); 851 const SDL_Rect *srcrect = verts; 852 SDL_Rect *dstrect = verts + 1; 853 SDL_Texture *texture = cmd->data.draw.texture; 854 SDL_Surface *src = (SDL_Surface *)texture->internal; 855 856 SetDrawState(surface, &drawstate); 857 858 PrepTextureForCopy(cmd, &drawstate); 859 860 // Apply viewport 861 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 862 dstrect->x += drawstate.viewport->x; 863 dstrect->y += drawstate.viewport->y; 864 } 865 866 if (srcrect->w == dstrect->w && srcrect->h == dstrect->h) { 867 SDL_BlitSurface(src, srcrect, surface, dstrect); 868 } else { 869 // Prevent to do scaling + clipping on viewport boundaries as it may lose proportion 870 if (dstrect->x < 0 || dstrect->y < 0 || dstrect->x + dstrect->w > surface->w || dstrect->y + dstrect->h > surface->h) { 871 SDL_Surface *tmp = SDL_CreateSurface(dstrect->w, dstrect->h, surface->format); 872 // Scale to an intermediate surface, then blit 873 if (tmp) { 874 SDL_Rect r; 875 SDL_BlendMode blendmode; 876 Uint8 alphaMod, rMod, gMod, bMod; 877 878 SDL_GetSurfaceBlendMode(src, &blendmode); 879 SDL_GetSurfaceAlphaMod(src, &alphaMod); 880 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); 881 882 r.x = 0; 883 r.y = 0; 884 r.w = dstrect->w; 885 r.h = dstrect->h; 886 887 SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE); 888 SDL_SetSurfaceColorMod(src, 255, 255, 255); 889 SDL_SetSurfaceAlphaMod(src, 255); 890 891 SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, cmd->data.draw.texture_scale_mode); 892 893 SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod); 894 SDL_SetSurfaceAlphaMod(tmp, alphaMod); 895 SDL_SetSurfaceBlendMode(tmp, blendmode); 896 897 SDL_BlitSurface(tmp, NULL, surface, dstrect); 898 SDL_DestroySurface(tmp); 899 // No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy() 900 } 901 } else { 902 SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, cmd->data.draw.texture_scale_mode); 903 } 904 } 905 break; 906 } 907 908 case SDL_RENDERCMD_COPY_EX: 909 { 910 CopyExData *copydata = (CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first); 911 SetDrawState(surface, &drawstate); 912 PrepTextureForCopy(cmd, &drawstate); 913 914 // Apply viewport 915 if (drawstate.viewport && 916 (drawstate.viewport->x || drawstate.viewport->y) && 917 (copydata->scale_x > 0.0f && copydata->scale_y > 0.0f)) { 918 copydata->dstrect.x += (int)(drawstate.viewport->x / copydata->scale_x); 919 copydata->dstrect.y += (int)(drawstate.viewport->y / copydata->scale_y); 920 } 921 922 SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, ©data->srcrect, 923 ©data->dstrect, copydata->angle, ©data->center, copydata->flip, 924 copydata->scale_x, copydata->scale_y, cmd->data.draw.texture_scale_mode); 925 break; 926 } 927 928 case SDL_RENDERCMD_GEOMETRY: 929 { 930 int i; 931 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); 932 const int count = (int)cmd->data.draw.count; 933 SDL_Texture *texture = cmd->data.draw.texture; 934 const SDL_BlendMode blend = cmd->data.draw.blend; 935 936 SetDrawState(surface, &drawstate); 937 938 if (texture) { 939 SDL_Surface *src = (SDL_Surface *)texture->internal; 940 941 GeometryCopyData *ptr = (GeometryCopyData *)verts; 942 943 PrepTextureForCopy(cmd, &drawstate); 944 945 // Apply viewport 946 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 947 SDL_Point vp; 948 vp.x = drawstate.viewport->x; 949 vp.y = drawstate.viewport->y; 950 trianglepoint_2_fixedpoint(&vp); 951 for (i = 0; i < count; i++) { 952 ptr[i].dst.x += vp.x; 953 ptr[i].dst.y += vp.y; 954 } 955 } 956 957 for (i = 0; i < count; i += 3, ptr += 3) { 958 SDL_SW_BlitTriangle( 959 src, 960 &(ptr[0].src), &(ptr[1].src), &(ptr[2].src), 961 surface, 962 &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), 963 ptr[0].color, ptr[1].color, ptr[2].color, 964 cmd->data.draw.texture_address_mode_u, 965 cmd->data.draw.texture_address_mode_v); 966 } 967 } else { 968 GeometryFillData *ptr = (GeometryFillData *)verts; 969 970 // Apply viewport 971 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 972 SDL_Point vp; 973 vp.x = drawstate.viewport->x; 974 vp.y = drawstate.viewport->y; 975 trianglepoint_2_fixedpoint(&vp); 976 for (i = 0; i < count; i++) { 977 ptr[i].dst.x += vp.x; 978 ptr[i].dst.y += vp.y; 979 } 980 } 981 982 for (i = 0; i < count; i += 3, ptr += 3) { 983 SDL_SW_FillTriangle(surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), blend, ptr[0].color, ptr[1].color, ptr[2].color); 984 } 985 } 986 break; 987 } 988 989 case SDL_RENDERCMD_NO_OP: 990 break; 991 } 992 993 cmd = cmd->next; 994 } 995 996 return true; 997} 998 999static SDL_Surface *SW_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) 1000{ 1001 SDL_Surface *surface = SW_ActivateRenderer(renderer); 1002 void *pixels; 1003 1004 if (!SDL_SurfaceValid(surface)) { 1005 return NULL; 1006 } 1007 1008 /* NOTE: The rect is already adjusted according to the viewport by 1009 * SDL_RenderReadPixels. 1010 */ 1011 1012 if (rect->x < 0 || rect->x + rect->w > surface->w || 1013 rect->y < 0 || rect->y + rect->h > surface->h) { 1014 SDL_SetError("Tried to read outside of surface bounds"); 1015 return NULL; 1016 } 1017 1018 pixels = (void *)((Uint8 *)surface->pixels + 1019 rect->y * surface->pitch + 1020 rect->x * surface->fmt->bytes_per_pixel); 1021 1022 return SDL_DuplicatePixels(rect->w, rect->h, surface->format, SDL_COLORSPACE_SRGB, pixels, surface->pitch); 1023} 1024 1025static bool SW_RenderPresent(SDL_Renderer *renderer) 1026{ 1027 SDL_Window *window = renderer->window; 1028 1029 if (!window) { 1030 return false; 1031 } 1032 return SDL_UpdateWindowSurface(window); 1033} 1034 1035static void SW_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 1036{ 1037 SDL_Surface *surface = (SDL_Surface *)texture->internal; 1038 1039 SDL_DestroySurface(surface); 1040} 1041 1042static void SW_DestroyRenderer(SDL_Renderer *renderer) 1043{ 1044 SDL_Window *window = renderer->window; 1045 SW_RenderData *data = (SW_RenderData *)renderer->internal; 1046 1047 if (window) { 1048 SDL_DestroyWindowSurface(window); 1049 } 1050 SDL_free(data); 1051} 1052 1053static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormat format) 1054{ 1055 // Prefer the format used by the framebuffer by default. 1056 SDL_AddSupportedTextureFormat(renderer, format); 1057 1058 switch (format) { 1059 case SDL_PIXELFORMAT_XRGB4444: 1060 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444); 1061 break; 1062 case SDL_PIXELFORMAT_XBGR4444: 1063 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444); 1064 break; 1065 case SDL_PIXELFORMAT_ARGB4444: 1066 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB4444); 1067 break; 1068 case SDL_PIXELFORMAT_ABGR4444: 1069 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR4444); 1070 break; 1071 1072 case SDL_PIXELFORMAT_XRGB1555: 1073 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB1555); 1074 break; 1075 case SDL_PIXELFORMAT_XBGR1555: 1076 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555); 1077 break; 1078 case SDL_PIXELFORMAT_ARGB1555: 1079 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB1555); 1080 break; 1081 case SDL_PIXELFORMAT_ABGR1555: 1082 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR1555); 1083 break; 1084 1085 case SDL_PIXELFORMAT_XRGB8888: 1086 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1087 break; 1088 case SDL_PIXELFORMAT_RGBX8888: 1089 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); 1090 break; 1091 case SDL_PIXELFORMAT_XBGR8888: 1092 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 1093 break; 1094 case SDL_PIXELFORMAT_BGRX8888: 1095 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); 1096 break; 1097 case SDL_PIXELFORMAT_ARGB8888: 1098 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1099 break; 1100 case SDL_PIXELFORMAT_RGBA8888: 1101 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); 1102 break; 1103 case SDL_PIXELFORMAT_ABGR8888: 1104 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); 1105 break; 1106 case SDL_PIXELFORMAT_BGRA8888: 1107 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); 1108 break; 1109 default: 1110 break; 1111 } 1112 1113 /* Ensure that we always have a SDL_PACKEDLAYOUT_8888 format. Having a matching component order increases the 1114 * chances of getting a fast path for blitting. 1115 */ 1116 if (SDL_ISPIXELFORMAT_PACKED(format)) { 1117 if (SDL_PIXELLAYOUT(format) != SDL_PACKEDLAYOUT_8888) { 1118 switch (SDL_PIXELORDER(format)) { 1119 case SDL_PACKEDORDER_BGRX: 1120 case SDL_PACKEDORDER_BGRA: 1121 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); 1122 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); 1123 break; 1124 case SDL_PACKEDORDER_RGBX: 1125 case SDL_PACKEDORDER_RGBA: 1126 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); 1127 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); 1128 break; 1129 case SDL_PACKEDORDER_XBGR: 1130 case SDL_PACKEDORDER_ABGR: 1131 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); 1132 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 1133 break; 1134 case SDL_PACKEDORDER_XRGB: 1135 case SDL_PACKEDORDER_ARGB: 1136 default: 1137 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1138 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1139 break; 1140 } 1141 } 1142 } else { 1143 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1144 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1145 } 1146 1147 // Add 8-bit palettized format 1148 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); 1149} 1150 1151bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props) 1152{ 1153 SW_RenderData *data; 1154 1155 CHECK_PARAM(!SDL_SurfaceValid(surface)) { 1156 return SDL_InvalidParamError("surface"); 1157 } 1158 1159 CHECK_PARAM(SDL_BITSPERPIXEL(surface->format) < 8 || 1160 SDL_BITSPERPIXEL(surface->format) > 32) { 1161 return SDL_SetError("Unsupported surface format"); 1162 } 1163 1164 SDL_SetupRendererColorspace(renderer, create_props); 1165 1166 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { 1167 return SDL_SetError("Unsupported output colorspace"); 1168 } 1169 1170 renderer->software = true; 1171 1172 data = (SW_RenderData *)SDL_calloc(1, sizeof(*data)); 1173 if (!data) { 1174 return false; 1175 } 1176 data->surface = surface; 1177 data->window = surface; 1178 1179 renderer->WindowEvent = SW_WindowEvent; 1180 renderer->GetOutputSize = SW_GetOutputSize; 1181 renderer->CreatePalette = SW_CreatePalette; 1182 renderer->UpdatePalette = SW_UpdatePalette; 1183 renderer->DestroyPalette = SW_DestroyPalette; 1184 renderer->ChangeTexturePalette = SW_ChangeTexturePalette; 1185 renderer->CreateTexture = SW_CreateTexture; 1186 renderer->UpdateTexture = SW_UpdateTexture; 1187 renderer->LockTexture = SW_LockTexture; 1188 renderer->UnlockTexture = SW_UnlockTexture; 1189 renderer->SetRenderTarget = SW_SetRenderTarget; 1190 renderer->QueueSetViewport = SW_QueueNoOp; 1191 renderer->QueueSetDrawColor = SW_QueueNoOp; 1192 renderer->QueueDrawPoints = SW_QueueDrawPoints; 1193 renderer->QueueDrawLines = SW_QueueDrawPoints; // lines and points queue vertices the same way. 1194 renderer->QueueFillRects = SW_QueueFillRects; 1195 renderer->QueueCopy = SW_QueueCopy; 1196 renderer->QueueCopyEx = SW_QueueCopyEx; 1197 renderer->QueueGeometry = SW_QueueGeometry; 1198 renderer->InvalidateCachedState = SW_InvalidateCachedState; 1199 renderer->RunCommandQueue = SW_RunCommandQueue; 1200 renderer->RenderReadPixels = SW_RenderReadPixels; 1201 renderer->RenderPresent = SW_RenderPresent; 1202 renderer->DestroyTexture = SW_DestroyTexture; 1203 renderer->DestroyRenderer = SW_DestroyRenderer; 1204 renderer->internal = data; 1205 SW_InvalidateCachedState(renderer); 1206 1207 renderer->name = SW_RenderDriver.name; 1208 1209 SW_SelectBestFormats(renderer, surface->format); 1210 1211 return true; 1212} 1213 1214static bool SW_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 1215{ 1216 // Set the vsync hint based on our flags, if it's not already set 1217 const char *hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); 1218 const bool no_hint_set = (!hint || !*hint); 1219 1220 if (no_hint_set) { 1221 if (SDL_GetBooleanProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0)) { 1222 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); 1223 } else { 1224 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); 1225 } 1226 } 1227 1228 SDL_Surface *surface = SDL_GetWindowSurface(window); 1229 1230 // Reset the vsync hint if we set it above 1231 if (no_hint_set) { 1232 SDL_SetHint(SDL_HINT_RENDER_VSYNC, ""); 1233 } 1234 1235 if (!SDL_SurfaceValid(surface)) { 1236 return false; 1237 } 1238 1239 if (!SW_CreateRendererForSurface(renderer, surface, create_props)) { 1240 SDL_DestroyWindowSurface(window); 1241 return false; 1242 } 1243 return true; 1244} 1245 1246SDL_RenderDriver SW_RenderDriver = { 1247 SW_CreateRenderer, SDL_SOFTWARE_RENDERER 1248}; 1249 1250#endif // SDL_VIDEO_RENDER_SW 1251[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.