2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: GDI Driver Gradient Functions
5 * FILE: subsys/win32k/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 ******************************************************************/
42 IntEngGradientFillRect(
46 IN TRIVERTEX
*pVertex
,
48 IN PGRADIENT_RECT gRect
,
49 IN RECTL
*prclExtents
,
50 IN POINTL
*pptlDitherOrg
,
55 RECTL rcGradient
, rcSG
;
60 INTENG_ENTER_LEAVE EnterLeave
;
61 LONG y
, dy
, c
[3], dc
[3], ec
[3], ic
[3];
63 v1
= (pVertex
+ gRect
->UpperLeft
);
64 v2
= (pVertex
+ gRect
->LowerRight
);
66 rcGradient
.left
= min(v1
->x
, v2
->x
);
67 rcGradient
.right
= max(v1
->x
, v2
->x
);
68 rcGradient
.top
= min(v1
->y
, v2
->y
);
69 rcGradient
.bottom
= max(v1
->y
, v2
->y
);
71 RECTL_vOffsetRect(&rcSG
, pptlDitherOrg
->x
, pptlDitherOrg
->y
);
75 dy
= abs(rcGradient
.right
- rcGradient
.left
);
79 dy
= abs(rcGradient
.bottom
- rcGradient
.top
);
82 if(!IntEngEnter(&EnterLeave
, psoDest
, &rcSG
, FALSE
, &Translate
, &psoOutput
))
87 if((v1
->Red
!= v2
->Red
|| v1
->Green
!= v2
->Green
|| v1
->Blue
!= v2
->Blue
) && dy
> 1)
89 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
97 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
98 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
100 if(RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
106 for(y
= rcSG
.left
; y
< FillRect
.right
; y
++)
108 if(y
>= FillRect
.left
)
110 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
111 DibFunctionsForBitmapFormat
[psoOutput
->iBitmapFormat
].DIB_VLine(
112 psoOutput
, y
+ Translate
.x
, FillRect
.top
+ Translate
.y
, FillRect
.bottom
+ Translate
.y
, Color
);
125 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
126 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
128 if(RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
134 for(y
= rcSG
.top
; y
< FillRect
.bottom
; y
++)
136 if(y
>= FillRect
.top
)
138 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
139 DibFunctionsForBitmapFormat
[psoOutput
->iBitmapFormat
].DIB_HLine(
140 psoOutput
, FillRect
.left
+ Translate
.x
, FillRect
.right
+ Translate
.x
, y
+ Translate
.y
, Color
);
151 return IntEngLeave(&EnterLeave
);
154 /* rectangle has only one color, no calculation required */
155 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
159 ULONG Color
= XLATEOBJ_iXlate(pxlo
, RGB(v1
->Red
, v1
->Green
, v1
->Blue
));
161 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
162 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
164 if(RECTL_bIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
166 for(; FillRect
.top
< FillRect
.bottom
; FillRect
.top
++)
168 DibFunctionsForBitmapFormat
[psoOutput
->iBitmapFormat
].DIB_HLine(
169 psoOutput
, FillRect
.left
+ Translate
.x
, FillRect
.right
+ Translate
.x
, FillRect
.top
+ Translate
.y
, Color
);
175 return IntEngLeave(&EnterLeave
);
178 /* Fill triangle with solid color */
179 #define S_FILLLINE(linefrom,lineto) \
180 if(sx[lineto] < sx[linefrom]) \
181 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[lineto], FillRect.left), min(sx[linefrom], FillRect.right), sy, Color); \
183 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color);
184 #define S_DOLINE(a,b,line) \
185 ex[line] += dx[line]; \
186 while(ex[line] > 0 && x[line] != destx[line]) \
188 x[line] += incx[line]; \
189 sx[line] += incx[line]; \
190 ex[line] -= dy[line]; \
192 #define S_GOLINE(a,b,line) \
193 if(y >= a->y && y <= b->y) \
195 #define S_ENDLINE(a,b,line) \
197 #define S_INITLINE(a,b,line) \
199 sx[line] = a->x + pptlDitherOrg->x; \
200 dx[line] = abs(b->x - a->x); \
201 dy[line] = abs(b->y - a->y); \
202 incx[line] = LINC[b->x > a->x]; \
203 ex[line] = -(dy[line]>>1); \
206 /* Fill triangle with gradient */
207 #define INITCOL(a,b,line,col,id) \
208 c[line][id] = a->col >> 8; \
209 dc[line][id] = abs((b->col >> 8) - c[line][id]); \
210 ec[line][id] = -(dy[line]>>1); \
211 ic[line][id] = LINC[(b->col >> 8) > c[line][id]]
212 #define STEPCOL(a,b,line,col,id) \
213 ec[line][id] += dc[line][id]; \
214 while(ec[line][id] > 0) \
216 c[line][id] += ic[line][id]; \
217 ec[line][id] -= dy[line]; \
219 #define FINITCOL(linefrom,lineto,colid) \
220 gc[colid] = c[linefrom][colid]; \
221 gd[colid] = abs(c[lineto][colid] - gc[colid]); \
222 ge[colid] = -(gx >> 1); \
223 gi[colid] = LINC[c[lineto][colid] > gc[colid]]
224 #define FDOCOL(linefrom,lineto,colid) \
225 ge[colid] += gd[colid]; \
226 while(ge[colid] > 0) \
228 gc[colid] += gi[colid]; \
231 #define FILLLINE(linefrom,lineto) \
232 gx = abs(sx[lineto] - sx[linefrom]); \
233 gxi = LINC[sx[linefrom] < sx[lineto]]; \
234 FINITCOL(linefrom, lineto, 0); \
235 FINITCOL(linefrom, lineto, 1); \
236 FINITCOL(linefrom, lineto, 2); \
237 for(g = sx[linefrom]; g != sx[lineto]; g += gxi) \
239 if(InY && g >= FillRect.left && g < FillRect.right) \
241 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
242 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_PutPixel(psoOutput, g, sy, Color); \
244 FDOCOL(linefrom, lineto, 0); \
245 FDOCOL(linefrom, lineto, 1); \
246 FDOCOL(linefrom, lineto, 2); \
248 #define DOLINE(a,b,line) \
249 STEPCOL(a, b, line, Red, 0); \
250 STEPCOL(a, b, line, Green, 1); \
251 STEPCOL(a, b, line, Blue, 2); \
252 ex[line] += dx[line]; \
253 while(ex[line] > 0 && x[line] != destx[line]) \
255 x[line] += incx[line]; \
256 sx[line] += incx[line]; \
257 ex[line] -= dy[line]; \
259 #define GOLINE(a,b,line) \
260 if(y >= a->y && y <= b->y) \
262 #define ENDLINE(a,b,line) \
264 #define INITLINE(a,b,line) \
266 sx[line] = a->x + pptlDitherOrg->x; \
267 dx[line] = abs(b->x - a->x); \
268 dy[line] = abs(b->y - a->y); \
269 incx[line] = LINC[b->x > a->x]; \
270 ex[line] = -(dy[line]>>1); \
272 #define DOINIT(a, b, line) \
273 INITLINE(a, b, line); \
274 INITCOL(a, b, line, Red, 0); \
275 INITCOL(a, b, line, Green, 1); \
276 INITCOL(a, b, line, Blue, 2);
277 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x)
278 #define SWAP(a,b,c) c = a;\
283 IntEngGradientFillTriangle(
287 IN TRIVERTEX
*pVertex
,
289 IN PGRADIENT_TRIANGLE gTriangle
,
290 IN RECTL
*prclExtents
,
291 IN POINTL
*pptlDitherOrg
)
294 PTRIVERTEX v1
, v2
, v3
;
295 //RECT_ENUM RectEnum;
299 INTENG_ENTER_LEAVE EnterLeave
;
300 RECTL FillRect
= { 0, 0, 0, 0 };
304 //LONG x[NLINES], dx[NLINES], dy[NLINES], incx[NLINES], ex[NLINES], destx[NLINES];
305 //LONG c[NLINES][3], dc[NLINES][3], ec[NLINES][3], ic[NLINES][3]; /* colors on lines */
306 //LONG g, gx, gxi, gc[3], gd[3], ge[3], gi[3]; /* colors in triangle */
309 v1
= (pVertex
+ gTriangle
->Vertex1
);
310 v2
= (pVertex
+ gTriangle
->Vertex2
);
311 v3
= (pVertex
+ gTriangle
->Vertex3
);
329 DPRINT1("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1
->x
, v1
->y
, v2
->x
, v2
->y
, v3
->x
, v3
->y
);
330 /* FIXME: commented out because of an endless loop - fix triangles first */
331 DPRINT1("FIXME: IntEngGradientFillTriangle is broken\n");
333 if(!IntEngEnter(&EnterLeave
, psoDest
, &FillRect
, FALSE
, &Translate
, &psoOutput
))
338 //if(VCMPCLRS(v1, v2, v3))
340 // CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
343 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
344 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
346 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
350 // DOINIT(v1, v3, 0);
351 // DOINIT(v1, v2, 1);
352 // DOINIT(v2, v3, 2);
355 // sy = v1->y + pptlDitherOrg->y;
356 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
360 // InY = !(sy < FillRect.top || sy >= FillRect.bottom);
361 // GOLINE(v1, v3, 0);
362 // DOLINE(v1, v3, 0);
363 // ENDLINE(v1, v3, 0);
365 // GOLINE(v1, v2, 1);
366 // DOLINE(v1, v2, 1);
368 // ENDLINE(v1, v2, 1);
370 // GOLINE(v2, v3, 2);
371 // DOLINE(v2, v3, 2);
373 // ENDLINE(23, v3, 2);
380 // } while(EnumMore);
382 // return IntEngLeave(&EnterLeave);
385 ///* fill triangle with one solid color */
387 //Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8));
388 //CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
391 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
392 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
394 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
396 // S_INITLINE(v1, v3, 0);
397 // S_INITLINE(v1, v2, 1);
398 // S_INITLINE(v2, v3, 2);
401 // sy = v1->y + pptlDitherOrg->y;
402 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
406 // S_GOLINE(v1, v3, 0);
407 // S_DOLINE(v1, v3, 0);
408 // S_ENDLINE(v1, v3, 0);
410 // S_GOLINE(v1, v2, 1);
411 // S_DOLINE(v1, v2, 1);
413 // S_ENDLINE(v1, v2, 1);
415 // S_GOLINE(v2, v3, 2);
416 // S_DOLINE(v2, v3, 2);
418 // S_ENDLINE(23, v3, 2);
427 return IntEngLeave(&EnterLeave
);
432 IntEngIsNULLTriangle(TRIVERTEX
*pVertex
, GRADIENT_TRIANGLE
*gt
)
434 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex2
)))
436 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex3
)))
438 if(COMPAREVERTEX(VERTEX(Vertex2
), VERTEX(Vertex3
)))
449 IN TRIVERTEX
*pVertex
,
453 IN RECTL
*prclExtents
,
454 IN POINTL
*pptlDitherOrg
,
462 pco
= IntEngCreateClipRegion(0, 0, prclExtents
);
471 case GRADIENT_FILL_RECT_H
:
472 case GRADIENT_FILL_RECT_V
:
474 PGRADIENT_RECT gr
= (PGRADIENT_RECT
)pMesh
;
475 for(i
= 0; i
< nMesh
; i
++, gr
++)
477 if(!IntEngGradientFillRect(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gr
, prclExtents
,
478 pptlDitherOrg
, (ulMode
== GRADIENT_FILL_RECT_H
)))
486 case GRADIENT_FILL_TRIANGLE
:
488 PGRADIENT_TRIANGLE gt
= (PGRADIENT_TRIANGLE
)pMesh
;
489 for(i
= 0; i
< nMesh
; i
++, gt
++)
491 if(IntEngIsNULLTriangle(pVertex
, gt
))
493 /* skip empty triangles */
496 if(!IntEngGradientFillTriangle(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gt
, prclExtents
,
515 IN TRIVERTEX
*pVertex
,
519 IN RECTL
*prclExtents
,
520 IN POINTL
*pptlDitherOrg
,
527 psurf
= CONTAINING_RECORD(psoDest
, SURFACE
, SurfObj
);
530 if(psurf
->flags
& HOOK_GRADIENTFILL
)
532 Ret
= GDIDEVFUNCS(psoDest
).GradientFill(
533 psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
,
534 prclExtents
, pptlDitherOrg
, ulMode
);
538 Ret
= EngGradientFill(psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
, prclExtents
,
539 pptlDitherOrg
, ulMode
);