2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2004 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI Driver Gradient Functions
24 * FILE: subsys/win32k/eng/gradient.c
25 * PROGRAMER: Thomas Weidenmueller
35 /* MACROS *********************************************************************/
37 const LONG LINC
[2] = {-1, 1};
39 #define VERTEX(n) (pVertex + gt->n)
40 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y)
42 #define VCMPCLR(a,b,c,color) (a->color != b->color || a->color != c->color)
43 #define VCMPCLRS(a,b,c) \
44 !(!VCMPCLR(a,b,c,Red) || !VCMPCLR(a,b,c,Green) || !VCMPCLR(a,b,c,Blue))
46 #define MOVERECT(r,x,y) \
47 r.left += x; r.right += x; \
48 r.top += y; r.bottom += y
51 /* Horizontal/Vertical gradients */
52 #define HVINITCOL(Col, id) \
53 c[id] = v1->Col >> 8; \
54 dc[id] = abs((v2->Col >> 8) - c[id]); \
55 ec[id] = -(dy >> 1); \
56 ic[id] = LINC[(v2->Col >> 8) > c[id]]
57 #define HVSTEPCOL(id) \
65 /* FUNCTIONS ******************************************************************/
68 IntEngGradientFillRect(
72 IN TRIVERTEX
*pVertex
,
74 IN PGRADIENT_RECT gRect
,
75 IN RECTL
*prclExtents
,
76 IN POINTL
*pptlDitherOrg
,
81 RECTL rcGradient
, rcSG
;
86 INTENG_ENTER_LEAVE EnterLeave
;
87 LONG y
, dy
, c
[3], dc
[3], ec
[3], ic
[3];
89 v1
= (pVertex
+ gRect
->UpperLeft
);
90 v2
= (pVertex
+ gRect
->LowerRight
);
92 rcGradient
.left
= min(v1
->x
, v2
->x
);
93 rcGradient
.right
= max(v1
->x
, v2
->x
);
94 rcGradient
.top
= min(v1
->y
, v2
->y
);
95 rcGradient
.bottom
= max(v1
->y
, v2
->y
);
97 MOVERECT(rcSG
, pptlDitherOrg
->x
, pptlDitherOrg
->y
);
101 dy
= abs(rcGradient
.right
- rcGradient
.left
);
105 dy
= abs(rcGradient
.bottom
- rcGradient
.top
);
108 if(!IntEngEnter(&EnterLeave
, psoDest
, &rcSG
, FALSE
, &Translate
, &OutputObj
))
113 if((v1
->Red
!= v2
->Red
|| v1
->Green
!= v2
->Green
|| v1
->Blue
!= v2
->Blue
) && dy
> 1)
115 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
123 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
124 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
126 if(IntGdiIntersectRect(&FillRect
, (PRECT
)&RectEnum
.arcl
[i
], (PRECT
)&rcSG
))
132 for(y
= rcSG
.left
; y
< FillRect
.right
; y
++)
134 if(y
>= FillRect
.left
)
136 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
137 DibFunctionsForBitmapFormat
[OutputObj
->iBitmapFormat
].DIB_VLine(
138 OutputObj
, y
, FillRect
.top
, FillRect
.bottom
, Color
);
151 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
152 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
154 if(IntGdiIntersectRect(&FillRect
, (PRECT
)&RectEnum
.arcl
[i
], (PRECT
)&rcSG
))
160 for(y
= rcSG
.top
; y
< FillRect
.bottom
; y
++)
162 if(y
>= FillRect
.top
)
164 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
165 DibFunctionsForBitmapFormat
[OutputObj
->iBitmapFormat
].DIB_HLine(
166 OutputObj
, FillRect
.left
, FillRect
.right
, y
, Color
);
177 return IntEngLeave(&EnterLeave
);
180 /* rectangle has only one color, no calculation required */
181 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
185 ULONG Color
= XLATEOBJ_iXlate(pxlo
, RGB(v1
->Red
, v1
->Green
, v1
->Blue
));
187 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
188 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
190 if(IntGdiIntersectRect(&FillRect
, (PRECT
)&RectEnum
.arcl
[i
], (PRECT
)&rcSG
))
192 for(; FillRect
.top
< FillRect
.bottom
; FillRect
.top
++)
194 DibFunctionsForBitmapFormat
[OutputObj
->iBitmapFormat
].DIB_HLine(
195 OutputObj
, FillRect
.left
, FillRect
.right
, FillRect
.top
, Color
);
201 return IntEngLeave(&EnterLeave
);
204 /* Fill triangle with solid color */
205 #define S_FILLLINE(linefrom,lineto) \
206 if(sx[lineto] < sx[linefrom]) \
207 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(OutputObj, max(sx[lineto], FillRect.left), min(sx[linefrom], FillRect.right), sy, Color); \
209 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(OutputObj, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color);
210 #define S_DOLINE(a,b,line) \
211 ex[line] += dx[line]; \
212 while(ex[line] > 0 && x[line] != destx[line]) \
214 x[line] += incx[line]; \
215 sx[line] += incx[line]; \
216 ex[line] -= dy[line]; \
218 #define S_GOLINE(a,b,line) \
219 if(y >= a->y && y <= b->y) \
221 #define S_ENDLINE(a,b,line) \
223 #define S_INITLINE(a,b,line) \
225 sx[line] = a->x + pptlDitherOrg->x; \
226 dx[line] = abs(b->x - a->x); \
227 dy[line] = abs(b->y - a->y); \
228 incx[line] = LINC[b->x > a->x]; \
229 ex[line] = -(dy[line]>>1); \
232 /* Fill triangle with gradient */
233 #define INITCOL(a,b,line,col,id) \
234 c[line][id] = a->col >> 8; \
235 dc[line][id] = abs((b->col >> 8) - c[line][id]); \
236 ec[line][id] = -(dy[line]>>1); \
237 ic[line][id] = LINC[(b->col >> 8) > c[line][id]]
238 #define STEPCOL(a,b,line,col,id) \
239 ec[line][id] += dc[line][id]; \
240 while(ec[line][id] > 0) \
242 c[line][id] += ic[line][id]; \
243 ec[line][id] -= dy[line]; \
245 #define FINITCOL(linefrom,lineto,colid) \
246 gc[colid] = c[linefrom][colid]; \
247 gd[colid] = abs(c[lineto][colid] - gc[colid]); \
248 ge[colid] = -(gx >> 1); \
249 gi[colid] = LINC[c[lineto][colid] > gc[colid]]
250 #define FDOCOL(linefrom,lineto,colid) \
251 ge[colid] += gd[colid]; \
252 while(ge[colid] > 0) \
254 gc[colid] += gi[colid]; \
257 #define FILLLINE(linefrom,lineto) \
258 gx = abs(sx[lineto] - sx[linefrom]); \
259 gxi = LINC[sx[linefrom] < sx[lineto]]; \
260 FINITCOL(linefrom, lineto, 0); \
261 FINITCOL(linefrom, lineto, 1); \
262 FINITCOL(linefrom, lineto, 2); \
263 for(g = sx[linefrom]; g != sx[lineto]; g += gxi) \
265 if(InY && g >= FillRect.left && g < FillRect.right) \
267 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
268 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(OutputObj, g, sy, Color); \
270 FDOCOL(linefrom, lineto, 0); \
271 FDOCOL(linefrom, lineto, 1); \
272 FDOCOL(linefrom, lineto, 2); \
274 #define DOLINE(a,b,line) \
275 STEPCOL(a, b, line, Red, 0); \
276 STEPCOL(a, b, line, Green, 1); \
277 STEPCOL(a, b, line, Blue, 2); \
278 ex[line] += dx[line]; \
279 while(ex[line] > 0 && x[line] != destx[line]) \
281 x[line] += incx[line]; \
282 sx[line] += incx[line]; \
283 ex[line] -= dy[line]; \
285 #define GOLINE(a,b,line) \
286 if(y >= a->y && y <= b->y) \
288 #define ENDLINE(a,b,line) \
290 #define INITLINE(a,b,line) \
292 sx[line] = a->x + pptlDitherOrg->x; \
293 dx[line] = abs(b->x - a->x); \
294 dy[line] = abs(b->y - a->y); \
295 incx[line] = LINC[b->x > a->x]; \
296 ex[line] = -(dy[line]>>1); \
298 #define DOINIT(a, b, line) \
299 INITLINE(a, b, line); \
300 INITCOL(a, b, line, Red, 0); \
301 INITCOL(a, b, line, Green, 1); \
302 INITCOL(a, b, line, Blue, 2);
303 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x)
304 #define SWAP(a,b,c) c = a;\
309 IntEngGradientFillTriangle(
313 IN TRIVERTEX
*pVertex
,
315 IN PGRADIENT_TRIANGLE gTriangle
,
316 IN RECTL
*prclExtents
,
317 IN POINTL
*pptlDitherOrg
)
320 PTRIVERTEX v1
, v2
, v3
;
321 //RECT_ENUM RectEnum;
325 INTENG_ENTER_LEAVE EnterLeave
;
330 //LONG x[NLINES], dx[NLINES], dy[NLINES], incx[NLINES], ex[NLINES], destx[NLINES];
331 //LONG c[NLINES][3], dc[NLINES][3], ec[NLINES][3], ic[NLINES][3]; /* colors on lines */
332 //LONG g, gx, gxi, gc[3], gd[3], ge[3], gi[3]; /* colors in triangle */
335 v1
= (pVertex
+ gTriangle
->Vertex1
);
336 v2
= (pVertex
+ gTriangle
->Vertex2
);
337 v3
= (pVertex
+ gTriangle
->Vertex3
);
355 DbgPrint("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1
->x
, v1
->y
, v2
->x
, v2
->y
, v3
->x
, v3
->y
);
356 /* FIXME: commented out because of an endless loop - fix triangles first */
357 DbgPrint("FIXME: IntEngGradientFillTriangle is broken");
359 if(!IntEngEnter(&EnterLeave
, psoDest
, &FillRect
, FALSE
, &Translate
, &OutputObj
))
364 //if(VCMPCLRS(v1, v2, v3))
366 // CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
369 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
370 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
372 // if(IntGdiIntersectRect((PRECT)&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)prclExtents))
376 // DOINIT(v1, v3, 0);
377 // DOINIT(v1, v2, 1);
378 // DOINIT(v2, v3, 2);
381 // sy = v1->y + pptlDitherOrg->y;
382 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
386 // InY = !(sy < FillRect.top || sy >= FillRect.bottom);
387 // GOLINE(v1, v3, 0);
388 // DOLINE(v1, v3, 0);
389 // ENDLINE(v1, v3, 0);
391 // GOLINE(v1, v2, 1);
392 // DOLINE(v1, v2, 1);
394 // ENDLINE(v1, v2, 1);
396 // GOLINE(v2, v3, 2);
397 // DOLINE(v2, v3, 2);
399 // ENDLINE(23, v3, 2);
406 // } while(EnumMore);
408 // return IntEngLeave(&EnterLeave);
411 ///* fill triangle with one solid color */
413 //Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8));
414 //CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
417 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
418 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
420 // if(IntGdiIntersectRect((PRECT)&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)prclExtents))
422 // S_INITLINE(v1, v3, 0);
423 // S_INITLINE(v1, v2, 1);
424 // S_INITLINE(v2, v3, 2);
427 // sy = v1->y + pptlDitherOrg->y;
428 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
432 // S_GOLINE(v1, v3, 0);
433 // S_DOLINE(v1, v3, 0);
434 // S_ENDLINE(v1, v3, 0);
436 // S_GOLINE(v1, v2, 1);
437 // S_DOLINE(v1, v2, 1);
439 // S_ENDLINE(v1, v2, 1);
441 // S_GOLINE(v2, v3, 2);
442 // S_DOLINE(v2, v3, 2);
444 // S_ENDLINE(23, v3, 2);
453 return IntEngLeave(&EnterLeave
);
458 IntEngIsNULLTriangle(TRIVERTEX
*pVertex
, GRADIENT_TRIANGLE
*gt
)
460 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex2
)))
462 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex3
)))
464 if(COMPAREVERTEX(VERTEX(Vertex2
), VERTEX(Vertex3
)))
475 IN TRIVERTEX
*pVertex
,
479 IN RECTL
*prclExtents
,
480 IN POINTL
*pptlDitherOrg
,
484 CLIPOBJ
*pcoPriv
= NULL
;
489 pco
= pcoPriv
= IntEngCreateClipRegion(0, 0, prclExtents
);
498 case GRADIENT_FILL_RECT_H
:
499 case GRADIENT_FILL_RECT_V
:
501 PGRADIENT_RECT gr
= (PGRADIENT_RECT
)pMesh
;
502 for(i
= 0; i
< nMesh
; i
++, gr
++)
504 if(!IntEngGradientFillRect(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gr
, prclExtents
,
505 pptlDitherOrg
, (ulMode
== GRADIENT_FILL_RECT_H
)))
513 case GRADIENT_FILL_TRIANGLE
:
515 PGRADIENT_TRIANGLE gt
= (PGRADIENT_TRIANGLE
)pMesh
;
516 for(i
= 0; i
< nMesh
; i
++, gt
++)
518 if(IntEngIsNULLTriangle(pVertex
, gt
))
520 /* skip empty triangles */
523 if(!IntEngGradientFillTriangle(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gt
, prclExtents
,
536 IntEngDeleteClipRegion(pcoPriv
);
547 IN TRIVERTEX
*pVertex
,
551 IN RECTL
*prclExtents
,
552 IN POINTL
*pptlDitherOrg
,
559 pboDest
= CONTAINING_RECORD(psoDest
, BITMAPOBJ
, SurfObj
);
562 BITMAPOBJ_LockBitmapBits(pboDest
);
563 MouseSafetyOnDrawStart(
567 pco
->rclBounds
.right
,
568 pco
->rclBounds
.bottom
);
569 if(pboDest
->flHooks
& HOOK_GRADIENTFILL
)
571 Ret
= GDIDEVFUNCS(psoDest
).GradientFill(
572 psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
,
573 prclExtents
, pptlDitherOrg
, ulMode
);
577 Ret
= EngGradientFill(psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
, prclExtents
,
578 pptlDitherOrg
, ulMode
);
580 MouseSafetyOnDrawEnd(psoDest
);
581 BITMAPOBJ_UnlockBitmapBits(pboDest
);