Atlas - SDL_render_sw.c

Home / ext / SDL / src / render / software Lines: 1 | Size: 46158 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2026 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_PixelFormat tmp_format = SDL_ISPIXELFORMAT_ALPHA(src->format) ? SDL_PIXELFORMAT_ARGB8888 : surface->format; 872 SDL_Surface *tmp = SDL_CreateSurface(dstrect->w, dstrect->h, tmp_format); 873 // Scale to an intermediate surface, then blit 874 if (tmp) { 875 SDL_Rect r; 876 SDL_BlendMode blendmode; 877 Uint8 alphaMod, rMod, gMod, bMod; 878 879 SDL_GetSurfaceBlendMode(src, &blendmode); 880 SDL_GetSurfaceAlphaMod(src, &alphaMod); 881 SDL_GetSurfaceColorMod(src, &rMod, &gMod, &bMod); 882 883 r.x = 0; 884 r.y = 0; 885 r.w = dstrect->w; 886 r.h = dstrect->h; 887 888 SDL_SetSurfaceBlendMode(src, SDL_BLENDMODE_NONE); 889 SDL_SetSurfaceColorMod(src, 255, 255, 255); 890 SDL_SetSurfaceAlphaMod(src, 255); 891 892 SDL_BlitSurfaceScaled(src, srcrect, tmp, &r, cmd->data.draw.texture_scale_mode); 893 894 SDL_SetSurfaceColorMod(tmp, rMod, gMod, bMod); 895 SDL_SetSurfaceAlphaMod(tmp, alphaMod); 896 SDL_SetSurfaceBlendMode(tmp, blendmode); 897 898 SDL_BlitSurface(tmp, NULL, surface, dstrect); 899 SDL_DestroySurface(tmp); 900 // No need to set back r/g/b/a/blendmode to 'src' since it's done in PrepTextureForCopy() 901 } 902 } else { 903 SDL_BlitSurfaceScaled(src, srcrect, surface, dstrect, cmd->data.draw.texture_scale_mode); 904 } 905 } 906 break; 907 } 908 909 case SDL_RENDERCMD_COPY_EX: 910 { 911 CopyExData *copydata = (CopyExData *)(((Uint8 *)vertices) + cmd->data.draw.first); 912 SetDrawState(surface, &drawstate); 913 PrepTextureForCopy(cmd, &drawstate); 914 915 // Apply viewport 916 if (drawstate.viewport && 917 (drawstate.viewport->x || drawstate.viewport->y) && 918 (copydata->scale_x > 0.0f && copydata->scale_y > 0.0f)) { 919 copydata->dstrect.x += (int)(drawstate.viewport->x / copydata->scale_x); 920 copydata->dstrect.y += (int)(drawstate.viewport->y / copydata->scale_y); 921 } 922 923 SW_RenderCopyEx(renderer, surface, cmd->data.draw.texture, &copydata->srcrect, 924 &copydata->dstrect, copydata->angle, &copydata->center, copydata->flip, 925 copydata->scale_x, copydata->scale_y, cmd->data.draw.texture_scale_mode); 926 break; 927 } 928 929 case SDL_RENDERCMD_GEOMETRY: 930 { 931 int i; 932 SDL_Rect *verts = (SDL_Rect *)(((Uint8 *)vertices) + cmd->data.draw.first); 933 const int count = (int)cmd->data.draw.count; 934 SDL_Texture *texture = cmd->data.draw.texture; 935 const SDL_BlendMode blend = cmd->data.draw.blend; 936 937 SetDrawState(surface, &drawstate); 938 939 if (texture) { 940 SDL_Surface *src = (SDL_Surface *)texture->internal; 941 942 GeometryCopyData *ptr = (GeometryCopyData *)verts; 943 944 PrepTextureForCopy(cmd, &drawstate); 945 946 // Apply viewport 947 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 948 SDL_Point vp; 949 vp.x = drawstate.viewport->x; 950 vp.y = drawstate.viewport->y; 951 trianglepoint_2_fixedpoint(&vp); 952 for (i = 0; i < count; i++) { 953 ptr[i].dst.x += vp.x; 954 ptr[i].dst.y += vp.y; 955 } 956 } 957 958 for (i = 0; i < count; i += 3, ptr += 3) { 959 SDL_SW_BlitTriangle( 960 src, 961 &(ptr[0].src), &(ptr[1].src), &(ptr[2].src), 962 surface, 963 &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), 964 ptr[0].color, ptr[1].color, ptr[2].color, 965 cmd->data.draw.texture_address_mode_u, 966 cmd->data.draw.texture_address_mode_v); 967 } 968 } else { 969 GeometryFillData *ptr = (GeometryFillData *)verts; 970 971 // Apply viewport 972 if (drawstate.viewport && (drawstate.viewport->x || drawstate.viewport->y)) { 973 SDL_Point vp; 974 vp.x = drawstate.viewport->x; 975 vp.y = drawstate.viewport->y; 976 trianglepoint_2_fixedpoint(&vp); 977 for (i = 0; i < count; i++) { 978 ptr[i].dst.x += vp.x; 979 ptr[i].dst.y += vp.y; 980 } 981 } 982 983 for (i = 0; i < count; i += 3, ptr += 3) { 984 SDL_SW_FillTriangle(surface, &(ptr[0].dst), &(ptr[1].dst), &(ptr[2].dst), blend, ptr[0].color, ptr[1].color, ptr[2].color); 985 } 986 } 987 break; 988 } 989 990 case SDL_RENDERCMD_NO_OP: 991 break; 992 } 993 994 cmd = cmd->next; 995 } 996 997 return true; 998} 999 1000static SDL_Surface *SW_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect) 1001{ 1002 SDL_Surface *surface = SW_ActivateRenderer(renderer); 1003 void *pixels; 1004 1005 if (!SDL_SurfaceValid(surface)) { 1006 return NULL; 1007 } 1008 1009 /* NOTE: The rect is already adjusted according to the viewport by 1010 * SDL_RenderReadPixels. 1011 */ 1012 1013 if (rect->x < 0 || rect->x + rect->w > surface->w || 1014 rect->y < 0 || rect->y + rect->h > surface->h) { 1015 SDL_SetError("Tried to read outside of surface bounds"); 1016 return NULL; 1017 } 1018 1019 pixels = (void *)((Uint8 *)surface->pixels + 1020 rect->y * surface->pitch + 1021 rect->x * surface->fmt->bytes_per_pixel); 1022 1023 return SDL_DuplicatePixels(rect->w, rect->h, surface->format, SDL_COLORSPACE_SRGB, pixels, surface->pitch); 1024} 1025 1026static bool SW_RenderPresent(SDL_Renderer *renderer) 1027{ 1028 SDL_Window *window = renderer->window; 1029 1030 if (!window) { 1031 return false; 1032 } 1033 return SDL_UpdateWindowSurface(window); 1034} 1035 1036static void SW_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture) 1037{ 1038 SDL_Surface *surface = (SDL_Surface *)texture->internal; 1039 1040 SDL_DestroySurface(surface); 1041} 1042 1043static void SW_DestroyRenderer(SDL_Renderer *renderer) 1044{ 1045 SDL_Window *window = renderer->window; 1046 SW_RenderData *data = (SW_RenderData *)renderer->internal; 1047 1048 if (window) { 1049 SDL_DestroyWindowSurface(window); 1050 } 1051 SDL_free(data); 1052} 1053 1054static void SW_SelectBestFormats(SDL_Renderer *renderer, SDL_PixelFormat format) 1055{ 1056 // Prefer the format used by the framebuffer by default. 1057 SDL_AddSupportedTextureFormat(renderer, format); 1058 1059 switch (format) { 1060 case SDL_PIXELFORMAT_XRGB4444: 1061 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB4444); 1062 break; 1063 case SDL_PIXELFORMAT_XBGR4444: 1064 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR4444); 1065 break; 1066 case SDL_PIXELFORMAT_ARGB4444: 1067 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB4444); 1068 break; 1069 case SDL_PIXELFORMAT_ABGR4444: 1070 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR4444); 1071 break; 1072 1073 case SDL_PIXELFORMAT_XRGB1555: 1074 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB1555); 1075 break; 1076 case SDL_PIXELFORMAT_XBGR1555: 1077 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR1555); 1078 break; 1079 case SDL_PIXELFORMAT_ARGB1555: 1080 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB1555); 1081 break; 1082 case SDL_PIXELFORMAT_ABGR1555: 1083 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR1555); 1084 break; 1085 1086 case SDL_PIXELFORMAT_XRGB8888: 1087 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1088 break; 1089 case SDL_PIXELFORMAT_RGBX8888: 1090 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); 1091 break; 1092 case SDL_PIXELFORMAT_XBGR8888: 1093 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 1094 break; 1095 case SDL_PIXELFORMAT_BGRX8888: 1096 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); 1097 break; 1098 case SDL_PIXELFORMAT_ARGB8888: 1099 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1100 break; 1101 case SDL_PIXELFORMAT_RGBA8888: 1102 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); 1103 break; 1104 case SDL_PIXELFORMAT_ABGR8888: 1105 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); 1106 break; 1107 case SDL_PIXELFORMAT_BGRA8888: 1108 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); 1109 break; 1110 default: 1111 break; 1112 } 1113 1114 /* Ensure that we always have a SDL_PACKEDLAYOUT_8888 format. Having a matching component order increases the 1115 * chances of getting a fast path for blitting. 1116 */ 1117 if (SDL_ISPIXELFORMAT_PACKED(format)) { 1118 if (SDL_PIXELLAYOUT(format) != SDL_PACKEDLAYOUT_8888) { 1119 switch (SDL_PIXELORDER(format)) { 1120 case SDL_PACKEDORDER_BGRX: 1121 case SDL_PACKEDORDER_BGRA: 1122 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX8888); 1123 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA8888); 1124 break; 1125 case SDL_PACKEDORDER_RGBX: 1126 case SDL_PACKEDORDER_RGBA: 1127 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX8888); 1128 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA8888); 1129 break; 1130 case SDL_PACKEDORDER_XBGR: 1131 case SDL_PACKEDORDER_ABGR: 1132 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XBGR8888); 1133 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR8888); 1134 break; 1135 case SDL_PACKEDORDER_XRGB: 1136 case SDL_PACKEDORDER_ARGB: 1137 default: 1138 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1139 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1140 break; 1141 } 1142 } 1143 } else { 1144 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_XRGB8888); 1145 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ARGB8888); 1146 } 1147 1148 // Add 8-bit palettized format 1149 SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8); 1150} 1151 1152bool SW_CreateRendererForSurface(SDL_Renderer *renderer, SDL_Surface *surface, SDL_PropertiesID create_props) 1153{ 1154 SW_RenderData *data; 1155 1156 CHECK_PARAM(!SDL_SurfaceValid(surface)) { 1157 return SDL_InvalidParamError("surface"); 1158 } 1159 1160 CHECK_PARAM(SDL_BITSPERPIXEL(surface->format) < 8 || 1161 SDL_BITSPERPIXEL(surface->format) > 32) { 1162 return SDL_SetError("Unsupported surface format"); 1163 } 1164 1165 SDL_SetupRendererColorspace(renderer, create_props); 1166 1167 if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) { 1168 return SDL_SetError("Unsupported output colorspace"); 1169 } 1170 1171 renderer->software = true; 1172 1173 data = (SW_RenderData *)SDL_calloc(1, sizeof(*data)); 1174 if (!data) { 1175 return false; 1176 } 1177 data->surface = surface; 1178 data->window = surface; 1179 1180 renderer->WindowEvent = SW_WindowEvent; 1181 renderer->GetOutputSize = SW_GetOutputSize; 1182 renderer->CreatePalette = SW_CreatePalette; 1183 renderer->UpdatePalette = SW_UpdatePalette; 1184 renderer->DestroyPalette = SW_DestroyPalette; 1185 renderer->ChangeTexturePalette = SW_ChangeTexturePalette; 1186 renderer->CreateTexture = SW_CreateTexture; 1187 renderer->UpdateTexture = SW_UpdateTexture; 1188 renderer->LockTexture = SW_LockTexture; 1189 renderer->UnlockTexture = SW_UnlockTexture; 1190 renderer->SetRenderTarget = SW_SetRenderTarget; 1191 renderer->QueueSetViewport = SW_QueueNoOp; 1192 renderer->QueueSetDrawColor = SW_QueueNoOp; 1193 renderer->QueueDrawPoints = SW_QueueDrawPoints; 1194 renderer->QueueDrawLines = SW_QueueDrawPoints; // lines and points queue vertices the same way. 1195 renderer->QueueFillRects = SW_QueueFillRects; 1196 renderer->QueueCopy = SW_QueueCopy; 1197 renderer->QueueCopyEx = SW_QueueCopyEx; 1198 renderer->QueueGeometry = SW_QueueGeometry; 1199 renderer->InvalidateCachedState = SW_InvalidateCachedState; 1200 renderer->RunCommandQueue = SW_RunCommandQueue; 1201 renderer->RenderReadPixels = SW_RenderReadPixels; 1202 renderer->RenderPresent = SW_RenderPresent; 1203 renderer->DestroyTexture = SW_DestroyTexture; 1204 renderer->DestroyRenderer = SW_DestroyRenderer; 1205 renderer->internal = data; 1206 SW_InvalidateCachedState(renderer); 1207 1208 renderer->name = SW_RenderDriver.name; 1209 1210 SW_SelectBestFormats(renderer, surface->format); 1211 1212 return true; 1213} 1214 1215static bool SW_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props) 1216{ 1217 // Set the vsync hint based on our flags, if it's not already set 1218 const char *hint = SDL_GetHint(SDL_HINT_RENDER_VSYNC); 1219 const bool no_hint_set = (!hint || !*hint); 1220 1221 if (no_hint_set) { 1222 if (SDL_GetBooleanProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0)) { 1223 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1"); 1224 } else { 1225 SDL_SetHint(SDL_HINT_RENDER_VSYNC, "0"); 1226 } 1227 } 1228 1229 SDL_Surface *surface = SDL_GetWindowSurface(window); 1230 1231 // Reset the vsync hint if we set it above 1232 if (no_hint_set) { 1233 SDL_SetHint(SDL_HINT_RENDER_VSYNC, ""); 1234 } 1235 1236 if (!SDL_SurfaceValid(surface)) { 1237 return false; 1238 } 1239 1240 if (!SW_CreateRendererForSurface(renderer, surface, create_props)) { 1241 SDL_DestroyWindowSurface(window); 1242 return false; 1243 } 1244 return true; 1245} 1246 1247SDL_RenderDriver SW_RenderDriver = { 1248 SW_CreateRenderer, SDL_SOFTWARE_RENDERER 1249}; 1250 1251#endif // SDL_VIDEO_RENDER_SW 1252
[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.