1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: GDI Driver Gradient Functions 5 * FILE: win32ss/gdi/eng/gradient.c 6 * PROGRAMER: Thomas Weidenmueller 7 */ 8 9 #include <win32k.h> 10 11 #define NDEBUG 12 #include <debug.h> 13 14 /* MACROS *********************************************************************/ 15 16 const LONG LINC[2] = {-1, 1}; 17 18 #define VERTEX(n) (pVertex + gt->n) 19 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y) 20 21 #define VCMPCLR(a,b,c,color) (a->color != b->color || a->color != c->color) 22 #define VCMPCLRS(a,b,c) \ 23 !(!VCMPCLR(a,b,c,Red) || !VCMPCLR(a,b,c,Green) || !VCMPCLR(a,b,c,Blue)) 24 25 /* Horizontal/Vertical gradients */ 26 #define HVINITCOL(Col, id) \ 27 c[id] = v1->Col >> 8; \ 28 dc[id] = abs((v2->Col >> 8) - c[id]); \ 29 ec[id] = -(dy >> 1); \ 30 ic[id] = LINC[(v2->Col >> 8) > c[id]] 31 #define HVSTEPCOL(id) \ 32 ec[id] += dc[id]; \ 33 while(ec[id] > 0) \ 34 { \ 35 c[id] += ic[id]; \ 36 ec[id] -= dy; \ 37 } 38 39 /* FUNCTIONS ******************************************************************/ 40 41 BOOL 42 FASTCALL 43 IntEngGradientFillRect( 44 IN SURFOBJ *psoDest, 45 IN CLIPOBJ *pco, 46 IN XLATEOBJ *pxlo, 47 IN TRIVERTEX *pVertex, 48 IN ULONG nVertex, 49 IN PGRADIENT_RECT gRect, 50 IN RECTL *prclExtents, 51 IN POINTL *pptlDitherOrg, 52 IN BOOL Horizontal) 53 { 54 SURFOBJ *psoOutput; 55 TRIVERTEX *v1, *v2; 56 RECTL rcGradient, rcSG; 57 RECT_ENUM RectEnum; 58 BOOL EnumMore; 59 ULONG i; 60 POINTL Translate; 61 INTENG_ENTER_LEAVE EnterLeave; 62 LONG y, dy, c[3], dc[3], ec[3], ic[3]; 63 64 v1 = (pVertex + gRect->UpperLeft); 65 v2 = (pVertex + gRect->LowerRight); 66 67 rcGradient.left = min(v1->x, v2->x); 68 rcGradient.right = max(v1->x, v2->x); 69 rcGradient.top = min(v1->y, v2->y); 70 rcGradient.bottom = max(v1->y, v2->y); 71 rcSG = rcGradient; 72 RECTL_vOffsetRect(&rcSG, pptlDitherOrg->x, pptlDitherOrg->y); 73 74 if(Horizontal) 75 { 76 dy = abs(rcGradient.right - rcGradient.left); 77 } 78 else 79 { 80 dy = abs(rcGradient.bottom - rcGradient.top); 81 } 82 83 if(!IntEngEnter(&EnterLeave, psoDest, &rcSG, FALSE, &Translate, &psoOutput)) 84 { 85 return FALSE; 86 } 87 88 if((v1->Red != v2->Red || v1->Green != v2->Green || v1->Blue != v2->Blue) && dy > 1) 89 { 90 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 91 do 92 { 93 RECTL FillRect; 94 ULONG Color; 95 96 if (Horizontal) 97 { 98 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 99 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++) 100 { 101 if (RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG)) 102 { 103 HVINITCOL(Red, 0); 104 HVINITCOL(Green, 1); 105 HVINITCOL(Blue, 2); 106 107 for (y = rcSG.left; y < FillRect.right; y++) 108 { 109 if (y >= FillRect.left) 110 { 111 Color = XLATEOBJ_iXlate(pxlo, RGB(c[0], c[1], c[2])); 112 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_VLine( 113 psoOutput, y + Translate.x, FillRect.top + Translate.y, FillRect.bottom + Translate.y, Color); 114 } 115 HVSTEPCOL(0); 116 HVSTEPCOL(1); 117 HVSTEPCOL(2); 118 } 119 } 120 } 121 122 continue; 123 } 124 125 /* vertical */ 126 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 127 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++) 128 { 129 if (RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG)) 130 { 131 HVINITCOL(Red, 0); 132 HVINITCOL(Green, 1); 133 HVINITCOL(Blue, 2); 134 135 for (y = rcSG.top; y < FillRect.bottom; y++) 136 { 137 if (y >= FillRect.top) 138 { 139 Color = XLATEOBJ_iXlate(pxlo, RGB(c[0], c[1], c[2])); 140 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, 141 FillRect.left + Translate.x, 142 FillRect.right + Translate.x, 143 y + Translate.y, 144 Color); 145 } 146 HVSTEPCOL(0); 147 HVSTEPCOL(1); 148 HVSTEPCOL(2); 149 } 150 } 151 } 152 153 } 154 while (EnumMore); 155 156 return IntEngLeave(&EnterLeave); 157 } 158 159 /* rectangle has only one color, no calculation required */ 160 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 161 do 162 { 163 RECTL FillRect; 164 ULONG Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8)); 165 166 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 167 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++) 168 { 169 if (RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG)) 170 { 171 for (; FillRect.top < FillRect.bottom; FillRect.top++) 172 { 173 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, 174 FillRect.left + Translate.x, 175 FillRect.right + Translate.x, 176 FillRect.top + Translate.y, 177 Color); 178 } 179 } 180 } 181 } 182 while (EnumMore); 183 184 return IntEngLeave(&EnterLeave); 185 } 186 187 /* Fill triangle with solid color */ 188 #define S_FILLLINE(linefrom,lineto) \ 189 if(sx[lineto] < sx[linefrom]) \ 190 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[lineto], FillRect.left), min(sx[linefrom], FillRect.right), sy, Color); \ 191 else \ 192 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color); 193 194 #define S_DOLINE(a,b,line) \ 195 ex[line] += dx[line]; \ 196 while(ex[line] > 0 && x[line] != destx[line]) \ 197 { \ 198 x[line] += incx[line]; \ 199 sx[line] += incx[line]; \ 200 ex[line] -= dy[line]; \ 201 } 202 203 #define S_GOLINE(a,b,line) \ 204 if(y >= a->y && y <= b->y) \ 205 { 206 207 #define S_ENDLINE(a,b,line) \ 208 } 209 210 #define S_INITLINE(a,b,line) \ 211 x[line] = a->x; \ 212 sx[line] = a->x + pptlDitherOrg->x; \ 213 dx[line] = abs(b->x - a->x); \ 214 dy[line] = abs(b->y - a->y); \ 215 incx[line] = LINC[b->x > a->x]; \ 216 ex[line] = -(dy[line]>>1); \ 217 destx[line] = b->x 218 219 /* Fill triangle with gradient */ 220 #define INITCOL(a,b,line,col,id) \ 221 c[line][id] = a->col >> 8; \ 222 dc[line][id] = abs((b->col >> 8) - c[line][id]); \ 223 ec[line][id] = -(dy[line]>>1); \ 224 ic[line][id] = LINC[(b->col >> 8) > c[line][id]] 225 226 #define STEPCOL(a,b,line,col,id) \ 227 ec[line][id] += dc[line][id]; \ 228 while(ec[line][id] > 0) \ 229 { \ 230 c[line][id] += ic[line][id]; \ 231 ec[line][id] -= dy[line]; \ 232 } 233 234 #define FINITCOL(linefrom,lineto,colid) \ 235 gc[colid] = c[linefrom][colid]; \ 236 gd[colid] = abs(c[lineto][colid] - gc[colid]); \ 237 ge[colid] = -(gx >> 1); \ 238 gi[colid] = LINC[c[lineto][colid] > gc[colid]] 239 240 #define FDOCOL(linefrom,lineto,colid) \ 241 ge[colid] += gd[colid]; \ 242 while(ge[colid] > 0) \ 243 { \ 244 gc[colid] += gi[colid]; \ 245 ge[colid] -= gx; \ 246 } 247 248 #define FILLLINE(linefrom,lineto) \ 249 gx = abs(sx[lineto] - sx[linefrom]); \ 250 gxi = LINC[sx[linefrom] < sx[lineto]]; \ 251 FINITCOL(linefrom, lineto, 0); \ 252 FINITCOL(linefrom, lineto, 1); \ 253 FINITCOL(linefrom, lineto, 2); \ 254 for(g = sx[linefrom]; g != sx[lineto]; g += gxi) \ 255 { \ 256 if(InY && g >= FillRect.left && g < FillRect.right) \ 257 { \ 258 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \ 259 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_PutPixel(psoOutput, g, sy, Color); \ 260 } \ 261 FDOCOL(linefrom, lineto, 0); \ 262 FDOCOL(linefrom, lineto, 1); \ 263 FDOCOL(linefrom, lineto, 2); \ 264 } 265 266 #define DOLINE(a,b,line) \ 267 STEPCOL(a, b, line, Red, 0); \ 268 STEPCOL(a, b, line, Green, 1); \ 269 STEPCOL(a, b, line, Blue, 2); \ 270 ex[line] += dx[line]; \ 271 while(ex[line] > 0 && x[line] != destx[line]) \ 272 { \ 273 x[line] += incx[line]; \ 274 sx[line] += incx[line]; \ 275 ex[line] -= dy[line]; \ 276 } 277 278 #define GOLINE(a,b,line) \ 279 if(y >= a->y && y <= b->y) \ 280 { 281 282 #define ENDLINE(a,b,line) \ 283 } 284 285 #define INITLINE(a,b,line) \ 286 x[line] = a->x; \ 287 sx[line] = a->x + pptlDitherOrg->x; \ 288 dx[line] = abs(b->x - a->x); \ 289 dy[line] = max(abs(b->y - a->y),1); \ 290 incx[line] = LINC[b->x > a->x]; \ 291 ex[line] = -(dy[line]>>1); \ 292 destx[line] = b->x 293 294 #define DOINIT(a, b, line) \ 295 INITLINE(a, b, line); \ 296 INITCOL(a, b, line, Red, 0); \ 297 INITCOL(a, b, line, Green, 1); \ 298 INITCOL(a, b, line, Blue, 2); 299 300 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x) 301 302 #define SWAP(a,b,c) c = a;\ 303 a = b;\ 304 b = c 305 306 #define NLINES 3 307 308 BOOL 309 FASTCALL 310 IntEngGradientFillTriangle( 311 IN SURFOBJ *psoDest, 312 IN CLIPOBJ *pco, 313 IN XLATEOBJ *pxlo, 314 IN TRIVERTEX *pVertex, 315 IN ULONG nVertex, 316 IN PGRADIENT_TRIANGLE gTriangle, 317 IN RECTL *prclExtents, 318 IN POINTL *pptlDitherOrg) 319 { 320 SURFOBJ *psoOutput; 321 PTRIVERTEX v1, v2, v3; 322 RECT_ENUM RectEnum; 323 BOOL EnumMore; 324 ULONG i; 325 POINTL Translate; 326 INTENG_ENTER_LEAVE EnterLeave; 327 RECTL FillRect = { 0, 0, 0, 0 }; 328 ULONG Color; 329 330 BOOL sx[NLINES]; 331 LONG x[NLINES], dx[NLINES], dy[NLINES], incx[NLINES], ex[NLINES], destx[NLINES]; 332 LONG c[NLINES][3], dc[NLINES][3], ec[NLINES][3], ic[NLINES][3]; /* colors on lines */ 333 LONG g, gx, gxi, gc[3], gd[3], ge[3], gi[3]; /* colors in triangle */ 334 LONG sy, y, bt; 335 336 v1 = (pVertex + gTriangle->Vertex1); 337 v2 = (pVertex + gTriangle->Vertex2); 338 v3 = (pVertex + gTriangle->Vertex3); 339 340 /* bubble sort */ 341 if (SMALLER(v2, v1)) 342 { 343 TRIVERTEX *t; 344 SWAP(v1, v2, t); 345 } 346 347 if (SMALLER(v3, v2)) 348 { 349 TRIVERTEX *t; 350 SWAP(v2, v3, t); 351 if (SMALLER(v2, v1)) 352 { 353 SWAP(v1, v2, t); 354 } 355 } 356 357 DPRINT("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1->x, v1->y, v2->x, v2->y, v3->x, v3->y); 358 /* FIXME: commented out because of an endless loop - fix triangles first */ 359 DPRINT("FIXME: IntEngGradientFillTriangle is broken\n"); 360 361 if (!IntEngEnter(&EnterLeave, psoDest, &FillRect, FALSE, &Translate, &psoOutput)) 362 { 363 return FALSE; 364 } 365 366 if (VCMPCLRS(v1, v2, v3)) 367 { 368 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 369 do 370 { 371 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 372 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++) 373 { 374 if (RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents)) 375 { 376 BOOL InY; 377 378 DOINIT(v1, v3, 0); 379 DOINIT(v1, v2, 1); 380 DOINIT(v2, v3, 2); 381 382 y = v1->y; 383 sy = v1->y + pptlDitherOrg->y; 384 bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom); 385 386 while (sy < bt) 387 { 388 InY = !(sy < FillRect.top || sy >= FillRect.bottom); 389 GOLINE(v1, v3, 0); 390 DOLINE(v1, v3, 0); 391 ENDLINE(v1, v3, 0); 392 393 GOLINE(v1, v2, 1); 394 DOLINE(v1, v2, 1); 395 FILLLINE(0, 1); 396 ENDLINE(v1, v2, 1); 397 398 GOLINE(v2, v3, 2); 399 DOLINE(v2, v3, 2); 400 FILLLINE(0, 2); 401 ENDLINE(23, v3, 2); 402 403 y++; 404 sy++; 405 } 406 } 407 } 408 } while (EnumMore); 409 410 return IntEngLeave(&EnterLeave); 411 } 412 413 /* fill triangle with one solid color */ 414 415 Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8)); 416 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0); 417 do 418 { 419 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum); 420 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++) 421 { 422 if (RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents)) 423 { 424 S_INITLINE(v1, v3, 0); 425 S_INITLINE(v1, v2, 1); 426 S_INITLINE(v2, v3, 2); 427 428 y = v1->y; 429 sy = v1->y + pptlDitherOrg->y; 430 bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom); 431 432 while (sy < bt) 433 { 434 S_GOLINE(v1, v3, 0); 435 S_DOLINE(v1, v3, 0); 436 S_ENDLINE(v1, v3, 0); 437 438 S_GOLINE(v1, v2, 1); 439 S_DOLINE(v1, v2, 1); 440 S_FILLLINE(0, 1); 441 S_ENDLINE(v1, v2, 1); 442 443 S_GOLINE(v2, v3, 2); 444 S_DOLINE(v2, v3, 2); 445 S_FILLLINE(0, 2); 446 S_ENDLINE(23, v3, 2); 447 448 y++; 449 sy++; 450 } 451 } 452 } 453 } while (EnumMore); 454 455 return IntEngLeave(&EnterLeave); 456 } 457 458 459 static 460 BOOL 461 IntEngIsNULLTriangle(TRIVERTEX *pVertex, GRADIENT_TRIANGLE *gt) 462 { 463 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex2))) 464 return TRUE; 465 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex3))) 466 return TRUE; 467 if(COMPAREVERTEX(VERTEX(Vertex2), VERTEX(Vertex3))) 468 return TRUE; 469 return FALSE; 470 } 471 472 473 BOOL 474 APIENTRY 475 EngGradientFill( 476 _Inout_ SURFOBJ *psoDest, 477 _In_ CLIPOBJ *pco, 478 _In_opt_ XLATEOBJ *pxlo, 479 _In_ TRIVERTEX *pVertex, 480 _In_ ULONG nVertex, 481 _In_ PVOID pMesh, 482 _In_ ULONG nMesh, 483 _In_ RECTL *prclExtents, 484 _In_ POINTL *pptlDitherOrg, 485 _In_ ULONG ulMode) 486 { 487 ULONG i; 488 BOOL ret = FALSE; 489 490 /* Check for NULL clip object */ 491 if (pco == NULL) 492 { 493 /* Use the trivial one instead */ 494 pco = (CLIPOBJ *)&gxcoTrivial;//.coClient; 495 } 496 497 switch(ulMode) 498 { 499 case GRADIENT_FILL_RECT_H: 500 case GRADIENT_FILL_RECT_V: 501 { 502 PGRADIENT_RECT gr = (PGRADIENT_RECT)pMesh; 503 for (i = 0; i < nMesh; i++, gr++) 504 { 505 if (!IntEngGradientFillRect(psoDest, 506 pco, 507 pxlo, 508 pVertex, 509 nVertex, 510 gr, 511 prclExtents, 512 pptlDitherOrg, 513 (ulMode == GRADIENT_FILL_RECT_H))) 514 { 515 break; 516 } 517 } 518 ret = TRUE; 519 break; 520 } 521 case GRADIENT_FILL_TRIANGLE: 522 { 523 PGRADIENT_TRIANGLE gt = (PGRADIENT_TRIANGLE)pMesh; 524 for (i = 0; i < nMesh; i++, gt++) 525 { 526 if (IntEngIsNULLTriangle(pVertex, gt)) 527 { 528 /* skip empty triangles */ 529 continue; 530 } 531 if (!IntEngGradientFillTriangle(psoDest, 532 pco, 533 pxlo, 534 pVertex, 535 nVertex, 536 gt, 537 prclExtents, 538 pptlDitherOrg)) 539 { 540 break; 541 } 542 } 543 ret = TRUE; 544 break; 545 } 546 } 547 548 return ret; 549 } 550 551 BOOL 552 APIENTRY 553 IntEngGradientFill( 554 IN SURFOBJ *psoDest, 555 IN CLIPOBJ *pco, 556 IN XLATEOBJ *pxlo, 557 IN TRIVERTEX *pVertex, 558 IN ULONG nVertex, 559 IN PVOID pMesh, 560 IN ULONG nMesh, 561 IN RECTL *prclExtents, 562 IN POINTL *pptlDitherOrg, 563 IN ULONG ulMode) 564 { 565 BOOL Ret; 566 SURFACE *psurf; 567 ASSERT(psoDest); 568 569 psurf = CONTAINING_RECORD(psoDest, SURFACE, SurfObj); 570 ASSERT(psurf); 571 572 if (psurf->flags & HOOK_GRADIENTFILL) 573 { 574 Ret = GDIDEVFUNCS(psoDest).GradientFill(psoDest, 575 pco, 576 pxlo, 577 pVertex, 578 nVertex, 579 pMesh, 580 nMesh, 581 prclExtents, 582 pptlDitherOrg, 583 ulMode); 584 } 585 else 586 { 587 Ret = EngGradientFill(psoDest, 588 pco, 589 pxlo, 590 pVertex, 591 nVertex, 592 pMesh, 593 nMesh, 594 prclExtents, 595 pptlDitherOrg, 596 ulMode); 597 } 598 599 return Ret; 600 } 601