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
14 /* MACROS *********************************************************************/
16 const LONG LINC
[2] = {-1, 1};
18 #define VERTEX(n) (pVertex + gt->n)
19 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y)
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))
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) \
39 /* FUNCTIONS ******************************************************************/
43 IntEngGradientFillRect(
47 IN TRIVERTEX
*pVertex
,
49 IN PGRADIENT_RECT gRect
,
50 IN RECTL
*prclExtents
,
51 IN POINTL
*pptlDitherOrg
,
56 RECTL rcGradient
, rcSG
;
61 INTENG_ENTER_LEAVE EnterLeave
;
62 LONG y
, dy
, c
[3], dc
[3], ec
[3], ic
[3];
64 v1
= (pVertex
+ gRect
->UpperLeft
);
65 v2
= (pVertex
+ gRect
->LowerRight
);
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
);
72 RECTL_vOffsetRect(&rcSG
, pptlDitherOrg
->x
, pptlDitherOrg
->y
);
76 dy
= abs(rcGradient
.right
- rcGradient
.left
);
80 dy
= abs(rcGradient
.bottom
- rcGradient
.top
);
83 if(!IntEngEnter(&EnterLeave
, psoDest
, &rcSG
, FALSE
, &Translate
, &psoOutput
))
88 if((v1
->Red
!= v2
->Red
|| v1
->Green
!= v2
->Green
|| v1
->Blue
!= v2
->Blue
) && dy
> 1)
90 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
98 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
99 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
101 if (RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
107 for (y
= rcSG
.left
; y
< FillRect
.right
; y
++)
109 if (y
>= FillRect
.left
)
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
);
126 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
127 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
129 if (RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
135 for (y
= rcSG
.top
; y
< FillRect
.bottom
; y
++)
137 if (y
>= FillRect
.top
)
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
,
156 return IntEngLeave(&EnterLeave
);
159 /* rectangle has only one color, no calculation required */
160 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
164 ULONG Color
= XLATEOBJ_iXlate(pxlo
, RGB(v1
->Red
>> 8, v1
->Green
>> 8, v1
->Blue
>> 8));
166 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
167 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
169 if (RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
171 for (; FillRect
.top
< FillRect
.bottom
; FillRect
.top
++)
173 DibFunctionsForBitmapFormat
[psoOutput
->iBitmapFormat
].DIB_HLine(psoOutput
,
174 FillRect
.left
+ Translate
.x
,
175 FillRect
.right
+ Translate
.x
,
176 FillRect
.top
+ Translate
.y
,
184 return IntEngLeave(&EnterLeave
);
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); \
192 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color);
194 #define S_DOLINE(a,b,line) \
195 ex[line] += dx[line]; \
196 while(ex[line] > 0 && x[line] != destx[line]) \
198 x[line] += incx[line]; \
199 sx[line] += incx[line]; \
200 ex[line] -= dy[line]; \
203 #define S_GOLINE(a,b,line) \
204 if(y >= a->y && y <= b->y) \
207 #define S_ENDLINE(a,b,line) \
210 #define S_INITLINE(a,b,line) \
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); \
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]]
226 #define STEPCOL(a,b,line,col,id) \
227 ec[line][id] += dc[line][id]; \
228 while(ec[line][id] > 0) \
230 c[line][id] += ic[line][id]; \
231 ec[line][id] -= dy[line]; \
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]]
240 #define FDOCOL(linefrom,lineto,colid) \
241 ge[colid] += gd[colid]; \
242 while(ge[colid] > 0) \
244 gc[colid] += gi[colid]; \
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) \
256 if(InY && g >= FillRect.left && g < FillRect.right) \
258 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
259 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_PutPixel(psoOutput, g, sy, Color); \
261 FDOCOL(linefrom, lineto, 0); \
262 FDOCOL(linefrom, lineto, 1); \
263 FDOCOL(linefrom, lineto, 2); \
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]) \
273 x[line] += incx[line]; \
274 sx[line] += incx[line]; \
275 ex[line] -= dy[line]; \
278 #define GOLINE(a,b,line) \
279 if(y >= a->y && y <= b->y) \
282 #define ENDLINE(a,b,line) \
285 #define INITLINE(a,b,line) \
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); \
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);
300 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x)
302 #define SWAP(a,b,c) c = a;\
310 IntEngGradientFillTriangle(
314 IN TRIVERTEX
*pVertex
,
316 IN PGRADIENT_TRIANGLE gTriangle
,
317 IN RECTL
*prclExtents
,
318 IN POINTL
*pptlDitherOrg
)
321 PTRIVERTEX v1
, v2
, v3
;
326 INTENG_ENTER_LEAVE EnterLeave
;
327 RECTL FillRect
= { 0, 0, 0, 0 };
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 */
336 v1
= (pVertex
+ gTriangle
->Vertex1
);
337 v2
= (pVertex
+ gTriangle
->Vertex2
);
338 v3
= (pVertex
+ gTriangle
->Vertex3
);
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");
361 if (!IntEngEnter(&EnterLeave
, psoDest
, &FillRect
, FALSE
, &Translate
, &psoOutput
))
366 if (VCMPCLRS(v1
, v2
, v3
))
368 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
371 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
372 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= prclExtents
->bottom
; i
++)
374 if (RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], prclExtents
))
383 sy
= v1
->y
+ pptlDitherOrg
->y
;
384 bt
= min(v3
->y
+ pptlDitherOrg
->y
, FillRect
.bottom
);
388 InY
= !(sy
< FillRect
.top
|| sy
>= FillRect
.bottom
);
410 return IntEngLeave(&EnterLeave
);
413 /* fill triangle with one solid color */
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);
419 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
420 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= prclExtents
->bottom
; i
++)
422 if (RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], prclExtents
))
424 S_INITLINE(v1
, v3
, 0);
425 S_INITLINE(v1
, v2
, 1);
426 S_INITLINE(v2
, v3
, 2);
429 sy
= v1
->y
+ pptlDitherOrg
->y
;
430 bt
= min(v3
->y
+ pptlDitherOrg
->y
, FillRect
.bottom
);
436 S_ENDLINE(v1
, v3
, 0);
441 S_ENDLINE(v1
, v2
, 1);
446 S_ENDLINE(23, v3
, 2);
455 return IntEngLeave(&EnterLeave
);
461 IntEngIsNULLTriangle(TRIVERTEX
*pVertex
, GRADIENT_TRIANGLE
*gt
)
463 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex2
)))
465 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex3
)))
467 if(COMPAREVERTEX(VERTEX(Vertex2
), VERTEX(Vertex3
)))
476 _Inout_ SURFOBJ
*psoDest
,
478 _In_opt_ XLATEOBJ
*pxlo
,
479 _In_ TRIVERTEX
*pVertex
,
483 _In_ RECTL
*prclExtents
,
484 _In_ POINTL
*pptlDitherOrg
,
490 /* Check for NULL clip object */
493 /* Use the trivial one instead */
494 pco
= (CLIPOBJ
*)&gxcoTrivial
;//.coClient;
499 case GRADIENT_FILL_RECT_H
:
500 case GRADIENT_FILL_RECT_V
:
502 PGRADIENT_RECT gr
= (PGRADIENT_RECT
)pMesh
;
503 for (i
= 0; i
< nMesh
; i
++, gr
++)
505 if (!IntEngGradientFillRect(psoDest
,
513 (ulMode
== GRADIENT_FILL_RECT_H
)))
521 case GRADIENT_FILL_TRIANGLE
:
523 PGRADIENT_TRIANGLE gt
= (PGRADIENT_TRIANGLE
)pMesh
;
524 for (i
= 0; i
< nMesh
; i
++, gt
++)
526 if (IntEngIsNULLTriangle(pVertex
, gt
))
528 /* skip empty triangles */
531 if (!IntEngGradientFillTriangle(psoDest
,
557 IN TRIVERTEX
*pVertex
,
561 IN RECTL
*prclExtents
,
562 IN POINTL
*pptlDitherOrg
,
569 psurf
= CONTAINING_RECORD(psoDest
, SURFACE
, SurfObj
);
572 if (psurf
->flags
& HOOK_GRADIENTFILL
)
574 Ret
= GDIDEVFUNCS(psoDest
).GradientFill(psoDest
,
587 Ret
= EngGradientFill(psoDest
,