Atlas - SDL_triangle.c

Home / ext / SDL / src / render / software Lines: 1 | Size: 30522 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 <limits.h> 26 27#include "SDL_triangle.h" 28 29#include "../../video/SDL_surface_c.h" 30 31/* fixed points bits precision 32 * Set to 1, so that it can start rendering with middle of a pixel precision. 33 * It doesn't need to be increased. 34 * But, if increased too much, it overflows (srcx, srcy) coordinates used for filling with texture. 35 * (which could be turned to int64). 36 */ 37#define FP_BITS 1 38 39#define COLOR_EQ(c1, c2) ((c1).r == (c2).r && (c1).g == (c2).g && (c1).b == (c2).b && (c1).a == (c2).a) 40 41static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, 42 SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, 43 int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, 44 int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, 45 SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, 46 SDL_TextureAddressMode texture_address_mode_u, 47 SDL_TextureAddressMode texture_address_mode_v); 48 49#if 0 50bool SDL_BlitTriangle(SDL_Surface *src, const SDL_Point srcpoints[3], SDL_Surface *dst, const SDL_Point dstpoints[3]) 51{ 52 int i; 53 SDL_Point points[6]; 54 55 if (src == NULL || dst == NULL) { 56 return false; 57 } 58 59 for (i = 0; i < 3; i++) { 60 if (srcpoints[i].x < 0 || srcpoints[i].y < 0 || srcpoints[i].x >= src->w || srcpoints[i].y >= src->h) { 61 return SDL_SetError("Values of 'srcpoints' out of bounds"); 62 } 63 } 64 65 points[0] = srcpoints[0]; 66 points[1] = dstpoints[0]; 67 points[2] = srcpoints[1]; 68 points[3] = dstpoints[1]; 69 points[4] = srcpoints[2]; 70 points[5] = dstpoints[2]; 71 for (i = 0; i < 3; i++) { 72 trianglepoint_2_fixedpoint(&points[2 * i + 1]); 73 } 74 return SDL_SW_BlitTriangle(src, dst, points); 75} 76 77bool SDL_FillTriangle(SDL_Surface *dst, const SDL_Point points[3], Uint32 color) 78{ 79 int i; 80 SDL_Point points_tmp[3]; 81 if (dst == NULL) { 82 return false; 83 } 84 for (i = 0; i < 3; i++) { 85 points_tmp[i] = points[i]; 86 trianglepoint_2_fixedpoint(&points_tmp[i]); 87 } 88 return SDL_SW_FillTriangle(dst, points_tmp, SDL_BLENDMODE_NONE, color); 89} 90#endif 91 92// cross product AB x AC 93static Sint64 cross_product(const SDL_Point *a, const SDL_Point *b, int c_x, int c_y) 94{ 95 return ((Sint64)(b->x - a->x)) * ((Sint64)(c_y - a->y)) - ((Sint64)(b->y - a->y)) * ((Sint64)(c_x - a->x)); 96} 97 98// check for top left rules 99static bool is_top_left(const SDL_Point *a, const SDL_Point *b, int is_clockwise) 100{ 101 if (is_clockwise) { 102 if (a->y == b->y && a->x < b->x) { 103 return true; 104 } 105 if (b->y < a->y) { 106 return true; 107 } 108 } else { 109 if (a->y == b->y && b->x < a->x) { 110 return true; 111 } 112 if (a->y < b->y) { 113 return true; 114 } 115 } 116 return false; 117} 118 119// x = (y << FP_BITS) 120// prevent runtime error: left shift of negative value 121#define PRECOMP(x, y) \ 122 val = y; \ 123 if (val >= 0) { \ 124 x = val << FP_BITS; \ 125 } else { \ 126 val *= -1; \ 127 x = val << FP_BITS; \ 128 x *= -1; \ 129 } 130 131void trianglepoint_2_fixedpoint(SDL_Point *a) 132{ 133 int val; 134 PRECOMP(a->x, a->x); 135 PRECOMP(a->y, a->y); 136} 137 138// bounding rect of three points (in fixed point) 139static void bounding_rect_fixedpoint(const SDL_Point *a, const SDL_Point *b, const SDL_Point *c, SDL_Rect *r) 140{ 141 int min_x = SDL_min(a->x, SDL_min(b->x, c->x)); 142 int max_x = SDL_max(a->x, SDL_max(b->x, c->x)); 143 int min_y = SDL_min(a->y, SDL_min(b->y, c->y)); 144 int max_y = SDL_max(a->y, SDL_max(b->y, c->y)); 145 // points are in fixed point, shift back 146 r->x = min_x >> FP_BITS; 147 r->y = min_y >> FP_BITS; 148 r->w = (max_x - min_x) >> FP_BITS; 149 r->h = (max_y - min_y) >> FP_BITS; 150} 151 152/* Triangle rendering, using Barycentric coordinates (w0, w1, w2) 153 * 154 * The cross product isn't computed from scratch at each iteration, 155 * but optimized using constant step increments 156 * 157 */ 158 159#define TRIANGLE_BEGIN_LOOP \ 160 { \ 161 int x, y; \ 162 for (y = 0; y < dstrect.h; y++) { \ 163 /* y start */ \ 164 Sint64 w0 = w0_row; \ 165 Sint64 w1 = w1_row; \ 166 Sint64 w2 = w2_row; \ 167 for (x = 0; x < dstrect.w; x++) { \ 168 /* In triangle */ \ 169 if (w0 + bias_w0 >= 0 && w1 + bias_w1 >= 0 && w2 + bias_w2 >= 0) { \ 170 Uint8 *dptr = (Uint8 *)dst_ptr + x * dstbpp; 171 172// Use 64 bits precision to prevent overflow when interpolating color / texture with wide triangles 173#define TRIANGLE_GET_TEXTCOORD \ 174 int srcx = (int)(((Sint64)w0 * s2s0_x + (Sint64)w1 * s2s1_x + s2_x_area.x) / area); \ 175 int srcy = (int)(((Sint64)w0 * s2s0_y + (Sint64)w1 * s2s1_y + s2_x_area.y) / area); \ 176 if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_CLAMP) { \ 177 if (srcx < 0) { \ 178 srcx = 0; \ 179 } else if (srcx >= src_surface->w) { \ 180 srcx = src_surface->w - 1; \ 181 } \ 182 } else if (texture_address_mode_u == SDL_TEXTURE_ADDRESS_WRAP) { \ 183 srcx %= src_surface->w; \ 184 if (srcx < 0) { \ 185 srcx += (src_surface->w - 1); \ 186 } \ 187 } \ 188 if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_CLAMP) { \ 189 if (srcy < 0) { \ 190 srcy = 0; \ 191 } else if (srcy >= src_surface->h) { \ 192 srcy = src_surface->h - 1; \ 193 } \ 194 } else if (texture_address_mode_v == SDL_TEXTURE_ADDRESS_WRAP) { \ 195 srcy %= src_surface->h; \ 196 if (srcy < 0) { \ 197 srcy += (src_surface->h - 1); \ 198 } \ 199 } 200 201#define TRIANGLE_GET_MAPPED_COLOR \ 202 Uint8 r = (Uint8)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \ 203 Uint8 g = (Uint8)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \ 204 Uint8 b = (Uint8)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \ 205 Uint8 a = (Uint8)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); \ 206 Uint32 color = SDL_MapRGBA(format, palette, r, g, b, a); 207 208#define TRIANGLE_GET_COLOR \ 209 int r = (int)(((Sint64)w0 * c0.r + (Sint64)w1 * c1.r + (Sint64)w2 * c2.r) / area); \ 210 int g = (int)(((Sint64)w0 * c0.g + (Sint64)w1 * c1.g + (Sint64)w2 * c2.g) / area); \ 211 int b = (int)(((Sint64)w0 * c0.b + (Sint64)w1 * c1.b + (Sint64)w2 * c2.b) / area); \ 212 int a = (int)(((Sint64)w0 * c0.a + (Sint64)w1 * c1.a + (Sint64)w2 * c2.a) / area); 213 214#define TRIANGLE_END_LOOP \ 215 } \ 216 /* x += 1 */ \ 217 w0 += d2d1_y; \ 218 w1 += d0d2_y; \ 219 w2 += d1d0_y; \ 220 } \ 221 /* y += 1 */ \ 222 w0_row += d1d2_x; \ 223 w1_row += d2d0_x; \ 224 w2_row += d0d1_x; \ 225 dst_ptr += dst_pitch; \ 226 } \ 227 } 228 229bool SDL_SW_FillTriangle(SDL_Surface *dst, SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, SDL_BlendMode blend, SDL_Color c0, SDL_Color c1, SDL_Color c2) 230{ 231 bool result = true; 232 int dst_locked = 0; 233 234 SDL_Rect dstrect; 235 236 int dstbpp; 237 Uint8 *dst_ptr; 238 int dst_pitch; 239 240 Sint64 area; 241 int is_clockwise; 242 243 int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; 244 Sint64 w0_row, w1_row, w2_row; 245 int bias_w0, bias_w1, bias_w2; 246 247 bool is_uniform; 248 249 SDL_Surface *tmp = NULL; 250 251 if (!SDL_SurfaceValid(dst)) { 252 return false; 253 } 254 255 area = cross_product(d0, d1, d2->x, d2->y); 256 257 is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2); 258 259 // Flat triangle 260 if (area == 0) { 261 return true; 262 } 263 264 // Lock the destination, if needed 265 if (SDL_MUSTLOCK(dst)) { 266 if (!SDL_LockSurface(dst)) { 267 result = false; 268 goto end; 269 } else { 270 dst_locked = 1; 271 } 272 } 273 274 bounding_rect_fixedpoint(d0, d1, d2, &dstrect); 275 276 { 277 // Clip triangle rect with surface rect 278 SDL_Rect rect; 279 rect.x = 0; 280 rect.y = 0; 281 rect.w = dst->w; 282 rect.h = dst->h; 283 SDL_GetRectIntersection(&dstrect, &rect, &dstrect); 284 } 285 286 { 287 // Clip triangle with surface clip rect 288 SDL_Rect rect; 289 SDL_GetSurfaceClipRect(dst, &rect); 290 SDL_GetRectIntersection(&dstrect, &rect, &dstrect); 291 } 292 293 if (blend != SDL_BLENDMODE_NONE) { 294 SDL_PixelFormat format = dst->format; 295 296 // need an alpha format 297 if (!SDL_ISPIXELFORMAT_ALPHA(format)) { 298 format = SDL_PIXELFORMAT_ARGB8888; 299 } 300 301 // Use an intermediate surface 302 tmp = SDL_CreateSurface(dstrect.w, dstrect.h, format); 303 if (!tmp) { 304 result = false; 305 goto end; 306 } 307 308 if (blend == SDL_BLENDMODE_MOD) { 309 Uint32 c = SDL_MapSurfaceRGBA(tmp, 255, 255, 255, 255); 310 SDL_FillSurfaceRect(tmp, NULL, c); 311 } 312 313 SDL_SetSurfaceBlendMode(tmp, blend); 314 315 dstbpp = tmp->fmt->bytes_per_pixel; 316 dst_ptr = (Uint8 *)tmp->pixels; 317 dst_pitch = tmp->pitch; 318 319 } else { 320 // Write directly to destination surface 321 dstbpp = dst->fmt->bytes_per_pixel; 322 dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; 323 dst_pitch = dst->pitch; 324 } 325 326 is_clockwise = area > 0; 327 if (area < 0) { 328 area = -area; 329 } 330 331 { 332 int val; 333 PRECOMP(d2d1_y, d1->y - d2->y) 334 PRECOMP(d0d2_y, d2->y - d0->y) 335 PRECOMP(d1d0_y, d0->y - d1->y) 336 PRECOMP(d1d2_x, d2->x - d1->x) 337 PRECOMP(d2d0_x, d0->x - d2->x) 338 PRECOMP(d0d1_x, d1->x - d0->x) 339 } 340 341 // Starting point for rendering, at the middle of a pixel 342 { 343 SDL_Point p; 344 p.x = dstrect.x; 345 p.y = dstrect.y; 346 trianglepoint_2_fixedpoint(&p); 347 p.x += (1 << FP_BITS) / 2; 348 p.y += (1 << FP_BITS) / 2; 349 w0_row = cross_product(d1, d2, p.x, p.y); 350 w1_row = cross_product(d2, d0, p.x, p.y); 351 w2_row = cross_product(d0, d1, p.x, p.y); 352 } 353 354 // Handle anti-clockwise triangles 355 if (!is_clockwise) { 356 d2d1_y *= -1; 357 d0d2_y *= -1; 358 d1d0_y *= -1; 359 d1d2_x *= -1; 360 d2d0_x *= -1; 361 d0d1_x *= -1; 362 w0_row *= -1; 363 w1_row *= -1; 364 w2_row *= -1; 365 } 366 367 // Add a bias to respect top-left rasterization rule 368 bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1); 369 bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1); 370 bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1); 371 372 if (is_uniform) { 373 Uint32 color; 374 if (tmp) { 375 color = SDL_MapSurfaceRGBA(tmp, c0.r, c0.g, c0.b, c0.a); 376 } else { 377 color = SDL_MapSurfaceRGBA(dst, c0.r, c0.g, c0.b, c0.a); 378 } 379 380 if (dstbpp == 4) { 381 TRIANGLE_BEGIN_LOOP 382 { 383 *(Uint32 *)dptr = color; 384 } 385 TRIANGLE_END_LOOP 386 } else if (dstbpp == 3) { 387 TRIANGLE_BEGIN_LOOP 388 { 389 Uint8 *s = (Uint8 *)&color; 390 dptr[0] = s[0]; 391 dptr[1] = s[1]; 392 dptr[2] = s[2]; 393 } 394 TRIANGLE_END_LOOP 395 } else if (dstbpp == 2) { 396 TRIANGLE_BEGIN_LOOP 397 { 398 *(Uint16 *)dptr = (Uint16)color; 399 } 400 TRIANGLE_END_LOOP 401 } else if (dstbpp == 1) { 402 TRIANGLE_BEGIN_LOOP 403 { 404 *dptr = (Uint8)color; 405 } 406 TRIANGLE_END_LOOP 407 } 408 } else { 409 const SDL_PixelFormatDetails *format; 410 SDL_Palette *palette; 411 if (tmp) { 412 format = tmp->fmt; 413 palette = tmp->palette; 414 } else { 415 format = dst->fmt; 416 palette = dst->palette; 417 } 418 if (dstbpp == 4) { 419 TRIANGLE_BEGIN_LOOP 420 { 421 TRIANGLE_GET_MAPPED_COLOR 422 *(Uint32 *)dptr = color; 423 } 424 TRIANGLE_END_LOOP 425 } else if (dstbpp == 3) { 426 TRIANGLE_BEGIN_LOOP 427 { 428 TRIANGLE_GET_MAPPED_COLOR 429 Uint8 *s = (Uint8 *)&color; 430 dptr[0] = s[0]; 431 dptr[1] = s[1]; 432 dptr[2] = s[2]; 433 } 434 TRIANGLE_END_LOOP 435 } else if (dstbpp == 2) { 436 TRIANGLE_BEGIN_LOOP 437 { 438 TRIANGLE_GET_MAPPED_COLOR 439 *(Uint16 *)dptr = (Uint16)color; 440 } 441 TRIANGLE_END_LOOP 442 } else if (dstbpp == 1) { 443 TRIANGLE_BEGIN_LOOP 444 { 445 TRIANGLE_GET_MAPPED_COLOR 446 *dptr = (Uint8)color; 447 } 448 TRIANGLE_END_LOOP 449 } 450 } 451 452 if (tmp) { 453 SDL_BlitSurface(tmp, NULL, dst, &dstrect); 454 SDL_DestroySurface(tmp); 455 } 456 457end: 458 if (dst_locked) { 459 SDL_UnlockSurface(dst); 460 } 461 462 return result; 463} 464 465bool SDL_SW_BlitTriangle( 466 SDL_Surface *src, 467 SDL_Point *s0, SDL_Point *s1, SDL_Point *s2, 468 SDL_Surface *dst, 469 SDL_Point *d0, SDL_Point *d1, SDL_Point *d2, 470 SDL_Color c0, SDL_Color c1, SDL_Color c2, 471 SDL_TextureAddressMode texture_address_mode_u, 472 SDL_TextureAddressMode texture_address_mode_v) 473{ 474 bool result = true; 475 SDL_Surface *src_surface = src; 476 int src_locked = 0; 477 int dst_locked = 0; 478 479 SDL_BlendMode blend; 480 481 SDL_Rect dstrect; 482 483 SDL_Point s2_x_area; 484 485 int dstbpp; 486 Uint8 *dst_ptr; 487 int dst_pitch; 488 489 const int *src_ptr; 490 int src_pitch; 491 492 Sint64 area, tmp64; 493 int is_clockwise; 494 495 int d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x; 496 int s2s0_x, s2s1_x, s2s0_y, s2s1_y; 497 498 Sint64 w0_row, w1_row, w2_row; 499 int bias_w0, bias_w1, bias_w2; 500 501 bool is_uniform; 502 503 bool has_modulation; 504 505 CHECK_PARAM(!SDL_SurfaceValid(src)) { 506 return SDL_InvalidParamError("src"); 507 } 508 CHECK_PARAM(!SDL_SurfaceValid(dst)) { 509 return SDL_InvalidParamError("dst"); 510 } 511 512 area = cross_product(d0, d1, d2->x, d2->y); 513 514 // Flat triangle 515 if (area == 0) { 516 return true; 517 } 518 519 // Lock the destination, if needed 520 if (SDL_MUSTLOCK(dst)) { 521 if (!SDL_LockSurface(dst)) { 522 result = false; 523 goto end; 524 } else { 525 dst_locked = 1; 526 } 527 } 528 529 // Lock the source, if needed 530 if (SDL_MUSTLOCK(src)) { 531 if (!SDL_LockSurface(src)) { 532 result = false; 533 goto end; 534 } else { 535 src_locked = 1; 536 } 537 } 538 539 is_uniform = COLOR_EQ(c0, c1) && COLOR_EQ(c1, c2); 540 541 bounding_rect_fixedpoint(d0, d1, d2, &dstrect); 542 543 SDL_GetSurfaceBlendMode(src, &blend); 544 545 if (is_uniform) { 546 // SDL_GetSurfaceColorMod(src, &r, &g, &b); 547 has_modulation = c0.r != 255 || c0.g != 255 || c0.b != 255 || c0.a != 255; 548 } else { 549 has_modulation = true; 550 } 551 552 { 553 // Clip triangle with surface clip rect 554 SDL_Rect rect; 555 SDL_GetSurfaceClipRect(dst, &rect); 556 SDL_GetRectIntersection(&dstrect, &rect, &dstrect); 557 } 558 559 // Set destination pointer 560 dstbpp = dst->fmt->bytes_per_pixel; 561 dst_ptr = (Uint8 *)dst->pixels + dstrect.x * dstbpp + dstrect.y * dst->pitch; 562 dst_pitch = dst->pitch; 563 564 // Set source pointer 565 src_ptr = (const int *)src->pixels; 566 src_pitch = src->pitch; 567 568 is_clockwise = area > 0; 569 if (area < 0) { 570 area = -area; 571 } 572 573 { 574 int val; 575 PRECOMP(d2d1_y, d1->y - d2->y) 576 PRECOMP(d0d2_y, d2->y - d0->y) 577 PRECOMP(d1d0_y, d0->y - d1->y) 578 PRECOMP(d1d2_x, d2->x - d1->x) 579 PRECOMP(d2d0_x, d0->x - d2->x) 580 PRECOMP(d0d1_x, d1->x - d0->x) 581 } 582 583 s2s0_x = s0->x - s2->x; 584 s2s1_x = s1->x - s2->x; 585 s2s0_y = s0->y - s2->y; 586 s2s1_y = s1->y - s2->y; 587 588 // Starting point for rendering, at the middle of a pixel 589 { 590 SDL_Point p; 591 p.x = dstrect.x; 592 p.y = dstrect.y; 593 trianglepoint_2_fixedpoint(&p); 594 p.x += (1 << FP_BITS) / 2; 595 p.y += (1 << FP_BITS) / 2; 596 w0_row = cross_product(d1, d2, p.x, p.y); 597 w1_row = cross_product(d2, d0, p.x, p.y); 598 w2_row = cross_product(d0, d1, p.x, p.y); 599 } 600 601 // Handle anti-clockwise triangles 602 if (!is_clockwise) { 603 d2d1_y *= -1; 604 d0d2_y *= -1; 605 d1d0_y *= -1; 606 d1d2_x *= -1; 607 d2d0_x *= -1; 608 d0d1_x *= -1; 609 w0_row *= -1; 610 w1_row *= -1; 611 w2_row *= -1; 612 } 613 614 // Add a bias to respect top-left rasterization rule 615 bias_w0 = (is_top_left(d1, d2, is_clockwise) ? 0 : -1); 616 bias_w1 = (is_top_left(d2, d0, is_clockwise) ? 0 : -1); 617 bias_w2 = (is_top_left(d0, d1, is_clockwise) ? 0 : -1); 618 619 /* precompute constant 's2->x * area' used in TRIANGLE_GET_TEXTCOORD */ 620 tmp64 = s2->x * area; 621 if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) { 622 s2_x_area.x = (int)tmp64; 623 } else { 624 result = SDL_SetError("triangle area overflow"); 625 goto end; 626 } 627 tmp64 = s2->y * area; 628 if (tmp64 >= INT_MIN && tmp64 <= INT_MAX) { 629 s2_x_area.y = (int)tmp64; 630 } else { 631 result = SDL_SetError("triangle area overflow"); 632 goto end; 633 } 634 635 if (blend != SDL_BLENDMODE_NONE || src->format != dst->format || has_modulation || !is_uniform) { 636 // Use SDL_BlitTriangle_Slow 637 638 SDL_BlitInfo *info = &src->map.info; 639 SDL_BlitInfo tmp_info; 640 641 SDL_zero(tmp_info); 642 643 tmp_info.src_fmt = src->fmt; 644 tmp_info.dst_fmt = dst->fmt; 645 tmp_info.flags = info->flags; 646 /* 647 tmp_info.r = info->r; 648 tmp_info.g = info->g; 649 tmp_info.b = info->b; 650 tmp_info.a = info->a; 651 */ 652 tmp_info.r = c0.r; 653 tmp_info.g = c0.g; 654 tmp_info.b = c0.b; 655 tmp_info.a = c0.a; 656 657 tmp_info.flags &= ~(SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA); 658 659 if (c0.r != 255 || c1.r != 255 || c2.r != 255 || 660 c0.g != 255 || c1.g != 255 || c2.g != 255 || 661 c0.b != 255 || c1.b != 255 || c2.b != 255) { 662 tmp_info.flags |= SDL_COPY_MODULATE_COLOR; 663 } 664 665 if (c0.a != 255 || c1.a != 255 || c2.a != 255) { 666 tmp_info.flags |= SDL_COPY_MODULATE_ALPHA; 667 } 668 669 tmp_info.colorkey = info->colorkey; 670 671 // src 672 tmp_info.src_surface = src_surface; 673 tmp_info.src = (Uint8 *)src_ptr; 674 tmp_info.src_pitch = src_pitch; 675 676 // dst 677 tmp_info.dst = dst_ptr; 678 tmp_info.dst_pitch = dst_pitch; 679 680#define CHECK_INT_RANGE(X) \ 681 if ((X) < INT_MIN || (X) > INT_MAX) { \ 682 result = SDL_SetError("integer overflow (%s = %" SDL_PRIs64 ")", #X, X); \ 683 goto end; \ 684 } 685 CHECK_INT_RANGE(area); 686 CHECK_INT_RANGE(w0_row); 687 CHECK_INT_RANGE(w1_row); 688 CHECK_INT_RANGE(w2_row); 689 SDL_BlitTriangle_Slow(&tmp_info, s2_x_area, dstrect, (int)area, bias_w0, bias_w1, bias_w2, 690 d2d1_y, d1d2_x, d0d2_y, d2d0_x, d1d0_y, d0d1_x, 691 s2s0_x, s2s1_x, s2s0_y, s2s1_y, (int)w0_row, (int)w1_row, (int)w2_row, 692 c0, c1, c2, is_uniform, texture_address_mode_u, texture_address_mode_v); 693 694 goto end; 695 } 696 697 if (dstbpp == 4) { 698 TRIANGLE_BEGIN_LOOP 699 { 700 TRIANGLE_GET_TEXTCOORD 701 Uint32 *sptr = (Uint32 *)((Uint8 *)src_ptr + srcy * src_pitch); 702 *(Uint32 *)dptr = sptr[srcx]; 703 } 704 TRIANGLE_END_LOOP 705 } else if (dstbpp == 3) { 706 TRIANGLE_BEGIN_LOOP 707 { 708 TRIANGLE_GET_TEXTCOORD 709 Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch; 710 dptr[0] = sptr[3 * srcx]; 711 dptr[1] = sptr[3 * srcx + 1]; 712 dptr[2] = sptr[3 * srcx + 2]; 713 } 714 TRIANGLE_END_LOOP 715 } else if (dstbpp == 2) { 716 TRIANGLE_BEGIN_LOOP 717 { 718 TRIANGLE_GET_TEXTCOORD 719 Uint16 *sptr = (Uint16 *)((Uint8 *)src_ptr + srcy * src_pitch); 720 *(Uint16 *)dptr = sptr[srcx]; 721 } 722 TRIANGLE_END_LOOP 723 } else if (dstbpp == 1) { 724 TRIANGLE_BEGIN_LOOP 725 { 726 TRIANGLE_GET_TEXTCOORD 727 Uint8 *sptr = (Uint8 *)src_ptr + srcy * src_pitch; 728 *dptr = sptr[srcx]; 729 } 730 TRIANGLE_END_LOOP 731 } 732 733end: 734 if (dst_locked) { 735 SDL_UnlockSurface(dst); 736 } 737 if (src_locked) { 738 SDL_UnlockSurface(src); 739 } 740 741 return result; 742} 743 744#define FORMAT_ALPHA 0 745#define FORMAT_NO_ALPHA -1 746#define FORMAT_INDEX8 -2 747#define FORMAT_2101010 1 748#define FORMAT_INDEXED(format) format == FORMAT_INDEX8 749#define FORMAT_HAS_ALPHA(format) format == 0 750#define FORMAT_HAS_NO_ALPHA(format) format < 0 751static int detect_format(const SDL_PixelFormatDetails *pf) 752{ 753 if (SDL_ISPIXELFORMAT_INDEXED(pf->format)) { 754 return FORMAT_INDEX8; 755 } if (pf->format == SDL_PIXELFORMAT_ARGB2101010) { 756 return FORMAT_2101010; 757 } else if (pf->Amask) { 758 return FORMAT_ALPHA; 759 } else { 760 return FORMAT_NO_ALPHA; 761 } 762} 763 764static void SDL_BlitTriangle_Slow(SDL_BlitInfo *info, 765 SDL_Point s2_x_area, SDL_Rect dstrect, int area, int bias_w0, int bias_w1, int bias_w2, 766 int d2d1_y, int d1d2_x, int d0d2_y, int d2d0_x, int d1d0_y, int d0d1_x, 767 int s2s0_x, int s2s1_x, int s2s0_y, int s2s1_y, int w0_row, int w1_row, int w2_row, 768 SDL_Color c0, SDL_Color c1, SDL_Color c2, bool is_uniform, 769 SDL_TextureAddressMode texture_address_mode_u, 770 SDL_TextureAddressMode texture_address_mode_v) 771{ 772 SDL_Surface *src_surface = info->src_surface; 773 SDL_Palette *palette = src_surface->palette; 774 const int flags = info->flags; 775 Uint32 modulateR = info->r; 776 Uint32 modulateG = info->g; 777 Uint32 modulateB = info->b; 778 Uint32 modulateA = info->a; 779 Uint32 srcpixel; 780 Uint32 srcR, srcG, srcB, srcA; 781 Uint32 dstpixel; 782 Uint32 dstR, dstG, dstB, dstA; 783 const SDL_PixelFormatDetails *src_fmt = info->src_fmt; 784 const SDL_PixelFormatDetails *dst_fmt = info->dst_fmt; 785 int srcbpp = src_fmt->bytes_per_pixel; 786 int dstbpp = dst_fmt->bytes_per_pixel; 787 int srcfmt_val; 788 int dstfmt_val; 789 Uint32 rgbmask = ~src_fmt->Amask; 790 Uint32 ckey = info->colorkey & rgbmask; 791 792 Uint8 *dst_ptr = info->dst; 793 int dst_pitch = info->dst_pitch; 794 795 srcfmt_val = detect_format(src_fmt); 796 dstfmt_val = detect_format(dst_fmt); 797 798 TRIANGLE_BEGIN_LOOP 799 { 800 Uint8 *src; 801 Uint8 *dst = dptr; 802 TRIANGLE_GET_TEXTCOORD 803 src = (info->src + (srcy * info->src_pitch) + (srcx * srcbpp)); 804 if (FORMAT_INDEXED(srcfmt_val)) { 805 srcpixel = *src; 806 const SDL_Color *color = &palette->colors[srcpixel]; 807 srcR = color->r; 808 srcG = color->g; 809 srcB = color->b; 810 srcA = color->a; 811 } else if (FORMAT_HAS_ALPHA(srcfmt_val)) { 812 DISEMBLE_RGBA(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB, srcA); 813 } else if (FORMAT_HAS_NO_ALPHA(srcfmt_val)) { 814 DISEMBLE_RGB(src, srcbpp, src_fmt, srcpixel, srcR, srcG, srcB); 815 srcA = 0xFF; 816 } else { 817 // SDL_PIXELFORMAT_ARGB2101010 818 srcpixel = *((Uint32 *)(src)); 819 RGBA_FROM_ARGB2101010(srcpixel, srcR, srcG, srcB, srcA); 820 } 821 if (flags & SDL_COPY_COLORKEY) { 822 // srcpixel isn't set for 24 bpp 823 if (srcbpp == 3) { 824 srcpixel = (srcR << src_fmt->Rshift) | 825 (srcG << src_fmt->Gshift) | (srcB << src_fmt->Bshift); 826 } 827 if ((srcpixel & rgbmask) == ckey) { 828 continue; 829 } 830 } 831 if ((flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL))) { 832 if (FORMAT_HAS_ALPHA(dstfmt_val)) { 833 DISEMBLE_RGBA(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB, dstA); 834 } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { 835 DISEMBLE_RGB(dst, dstbpp, dst_fmt, dstpixel, dstR, dstG, dstB); 836 dstA = 0xFF; 837 } else { 838 // SDL_PIXELFORMAT_ARGB2101010 839 dstpixel = *((Uint32 *) (dst)); 840 RGBA_FROM_ARGB2101010(dstpixel, dstR, dstG, dstB, dstA); 841 } 842 } else { 843 // don't care 844 dstR = dstG = dstB = dstA = 0; 845 } 846 847 if (!is_uniform) { 848 TRIANGLE_GET_COLOR 849 modulateR = r; 850 modulateG = g; 851 modulateB = b; 852 modulateA = a; 853 } 854 855 if (flags & SDL_COPY_MODULATE_COLOR) { 856 srcR = (srcR * modulateR) / 255; 857 srcG = (srcG * modulateG) / 255; 858 srcB = (srcB * modulateB) / 255; 859 } 860 if (flags & SDL_COPY_MODULATE_ALPHA) { 861 srcA = (srcA * modulateA) / 255; 862 } 863 if (flags & (SDL_COPY_BLEND | SDL_COPY_ADD)) { 864 // This goes away if we ever use premultiplied alpha 865 if (srcA < 255) { 866 srcR = (srcR * srcA) / 255; 867 srcG = (srcG * srcA) / 255; 868 srcB = (srcB * srcA) / 255; 869 } 870 } 871 switch (flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) { 872 case 0: 873 dstR = srcR; 874 dstG = srcG; 875 dstB = srcB; 876 dstA = srcA; 877 break; 878 case SDL_COPY_BLEND: 879 dstR = srcR + ((255 - srcA) * dstR) / 255; 880 dstG = srcG + ((255 - srcA) * dstG) / 255; 881 dstB = srcB + ((255 - srcA) * dstB) / 255; 882 dstA = srcA + ((255 - srcA) * dstA) / 255; 883 break; 884 case SDL_COPY_ADD: 885 dstR = srcR + dstR; 886 if (dstR > 255) { 887 dstR = 255; 888 } 889 dstG = srcG + dstG; 890 if (dstG > 255) { 891 dstG = 255; 892 } 893 dstB = srcB + dstB; 894 if (dstB > 255) { 895 dstB = 255; 896 } 897 break; 898 case SDL_COPY_MOD: 899 dstR = (srcR * dstR) / 255; 900 dstG = (srcG * dstG) / 255; 901 dstB = (srcB * dstB) / 255; 902 break; 903 case SDL_COPY_MUL: 904 dstR = ((srcR * dstR) + (dstR * (255 - srcA))) / 255; 905 if (dstR > 255) { 906 dstR = 255; 907 } 908 dstG = ((srcG * dstG) + (dstG * (255 - srcA))) / 255; 909 if (dstG > 255) { 910 dstG = 255; 911 } 912 dstB = ((srcB * dstB) + (dstB * (255 - srcA))) / 255; 913 if (dstB > 255) { 914 dstB = 255; 915 } 916 break; 917 } 918 if (FORMAT_HAS_ALPHA(dstfmt_val)) { 919 ASSEMBLE_RGBA(dst, dstbpp, dst_fmt, dstR, dstG, dstB, dstA); 920 } else if (FORMAT_HAS_NO_ALPHA(dstfmt_val)) { 921 ASSEMBLE_RGB(dst, dstbpp, dst_fmt, dstR, dstG, dstB); 922 } else { 923 // SDL_PIXELFORMAT_ARGB2101010 924 Uint32 pixelvalue; 925 ARGB2101010_FROM_RGBA(pixelvalue, dstR, dstG, dstB, dstA); 926 *(Uint32 *)dst = pixelvalue; 927 } 928 } 929 TRIANGLE_END_LOOP 930} 931 932#endif // SDL_VIDEO_RENDER_SW 933
[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.