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.
19 /* $Id: gradient.c,v 1.7 2004/04/06 21:53:48 weiden Exp $
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
30 #include <ddk/winddi.h>
31 #include <ddk/ntddmou.h>
32 #include <include/eng.h>
33 #include <include/inteng.h>
34 #include <include/object.h>
35 #include <include/paint.h>
36 #include <include/surface.h>
37 #include <include/rect.h>
40 #include <include/mouse.h>
41 #include "../dib/dib.h"
47 #include <win32k/debug1.h>
49 /* MACROS *********************************************************************/
51 const LONG LINC
[2] = {-1, 1};
53 #define VERTEX(n) (pVertex + gt->n)
54 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y)
56 #define VCMPCLR(a,b,c,color) (a->color != b->color || a->color != c->color)
57 #define VCMPCLRS(a,b,c) \
58 !(!VCMPCLR(a,b,c,Red) || !VCMPCLR(a,b,c,Green) || !VCMPCLR(a,b,c,Blue))
60 #define MOVERECT(r,x,y) \
61 r.left += x; r.right += x; \
62 r.top += y; r.bottom += y
65 /* Horizontal/Vertical gradients */
66 #define HVINITCOL(Col, id) \
67 c[id] = v1->Col >> 8; \
68 dc[id] = abs((v2->Col >> 8) - c[id]); \
69 ec[id] = -(dy >> 1); \
70 ic[id] = LINC[(v2->Col >> 8) > c[id]]
71 #define HVSTEPCOL(id) \
79 /* FUNCTIONS ******************************************************************/
82 IntEngGradientFillRect(
86 IN TRIVERTEX
*pVertex
,
88 IN PGRADIENT_RECT gRect
,
89 IN RECTL
*prclExtents
,
90 IN POINTL
*pptlDitherOrg
,
96 RECT rcGradient
, rcSG
;
101 INTENG_ENTER_LEAVE EnterLeave
;
102 LONG y
, dy
, c
[3], dc
[3], ec
[3], ic
[3];
104 v1
= (pVertex
+ gRect
->UpperLeft
);
105 v2
= (pVertex
+ gRect
->LowerRight
);
107 rcGradient
.left
= min(v1
->x
, v2
->x
);
108 rcGradient
.right
= max(v1
->x
, v2
->x
);
109 rcGradient
.top
= min(v1
->y
, v2
->y
);
110 rcGradient
.bottom
= max(v1
->y
, v2
->y
);
112 MOVERECT(rcSG
, pptlDitherOrg
->x
, pptlDitherOrg
->y
);
116 dy
= abs(rcGradient
.right
- rcGradient
.left
);
120 dy
= abs(rcGradient
.bottom
- rcGradient
.top
);
123 if(!IntEngEnter(&EnterLeave
, psoDest
, &rcSG
, FALSE
, &Translate
, &OutputObj
))
127 OutputGDI
= AccessInternalObjectFromUserObject(OutputObj
);
129 if((v1
->Red
!= v2
->Red
|| v1
->Green
!= v2
->Green
|| v1
->Blue
!= v2
->Blue
) && dy
> 1)
131 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
139 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
140 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
142 if(NtGdiIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
148 for(y
= rcSG
.left
; y
< FillRect
.right
; y
++)
150 if(y
>= FillRect
.left
)
152 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
153 OutputGDI
->DIB_VLine(OutputObj
, y
, FillRect
.top
, FillRect
.bottom
, Color
);
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(NtGdiIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
175 for(y
= rcSG
.top
; y
< FillRect
.bottom
; y
++)
177 if(y
>= FillRect
.top
)
179 Color
= XLATEOBJ_iXlate(pxlo
, RGB(c
[0], c
[1], c
[2]));
180 OutputGDI
->DIB_HLine(OutputObj
, FillRect
.left
, FillRect
.right
, y
, Color
);
191 return IntEngLeave(&EnterLeave
);
194 /* rectangle has only one color, no calculation required */
195 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
199 ULONG Color
= XLATEOBJ_iXlate(pxlo
, RGB(v1
->Red
, v1
->Green
, v1
->Blue
));
201 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
202 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= rcSG
.bottom
; i
++)
204 if(NtGdiIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], &rcSG
))
206 for(; FillRect
.top
< FillRect
.bottom
; FillRect
.top
++)
208 OutputGDI
->DIB_HLine(OutputObj
, FillRect
.left
, FillRect
.right
, FillRect
.top
, Color
);
214 return IntEngLeave(&EnterLeave
);
217 /* Fill triangle with solid color */
218 #define S_FILLLINE(linefrom,lineto) \
219 if(sx[lineto] < sx[linefrom]) \
220 OutputGDI->DIB_HLine(OutputObj, max(sx[lineto], FillRect.left), min(sx[linefrom], FillRect.right), sy, Color); \
222 OutputGDI->DIB_HLine(OutputObj, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color);
223 #define S_DOLINE(a,b,line) \
224 ex[line] += dx[line]; \
225 while(ex[line] > 0 && x[line] != destx[line]) \
227 x[line] += incx[line]; \
228 sx[line] += incx[line]; \
229 ex[line] -= dy[line]; \
231 #define S_GOLINE(a,b,line) \
232 if(y >= a->y && y <= b->y) \
234 #define S_ENDLINE(a,b,line) \
236 #define S_INITLINE(a,b,line) \
238 sx[line] = a->x + pptlDitherOrg->x; \
239 dx[line] = abs(b->x - a->x); \
240 dy[line] = abs(b->y - a->y); \
241 incx[line] = LINC[b->x > a->x]; \
242 ex[line] = -(dy[line]>>1); \
245 /* Fill triangle with gradient */
246 #define INITCOL(a,b,line,col,id) \
247 c[line][id] = a->col >> 8; \
248 dc[line][id] = abs((b->col >> 8) - c[line][id]); \
249 ec[line][id] = -(dy[line]>>1); \
250 ic[line][id] = LINC[(b->col >> 8) > c[line][id]]
251 #define STEPCOL(a,b,line,col,id) \
252 ec[line][id] += dc[line][id]; \
253 while(ec[line][id] > 0) \
255 c[line][id] += ic[line][id]; \
256 ec[line][id] -= dy[line]; \
258 #define FINITCOL(linefrom,lineto,colid) \
259 gc[colid] = c[linefrom][colid]; \
260 gd[colid] = abs(c[lineto][colid] - gc[colid]); \
261 ge[colid] = -(gx >> 1); \
262 gi[colid] = LINC[c[lineto][colid] > gc[colid]]
263 #define FDOCOL(linefrom,lineto,colid) \
264 ge[colid] += gd[colid]; \
265 while(ge[colid] > 0) \
267 gc[colid] += gi[colid]; \
270 #define FILLLINE(linefrom,lineto) \
271 gx = abs(sx[lineto] - sx[linefrom]); \
272 gxi = LINC[sx[linefrom] < sx[lineto]]; \
273 FINITCOL(linefrom, lineto, 0); \
274 FINITCOL(linefrom, lineto, 1); \
275 FINITCOL(linefrom, lineto, 2); \
276 for(g = sx[linefrom]; g != sx[lineto]; g += gxi) \
278 if(InY && g >= FillRect.left && g < FillRect.right) \
280 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
281 OutputGDI->DIB_PutPixel(OutputObj, g, sy, Color); \
283 FDOCOL(linefrom, lineto, 0); \
284 FDOCOL(linefrom, lineto, 1); \
285 FDOCOL(linefrom, lineto, 2); \
287 #define DOLINE(a,b,line) \
288 STEPCOL(a, b, line, Red, 0); \
289 STEPCOL(a, b, line, Green, 1); \
290 STEPCOL(a, b, line, Blue, 2); \
291 ex[line] += dx[line]; \
292 while(ex[line] > 0 && x[line] != destx[line]) \
294 x[line] += incx[line]; \
295 sx[line] += incx[line]; \
296 ex[line] -= dy[line]; \
298 #define GOLINE(a,b,line) \
299 if(y >= a->y && y <= b->y) \
301 #define ENDLINE(a,b,line) \
303 #define INITLINE(a,b,line) \
305 sx[line] = a->x + pptlDitherOrg->x; \
306 dx[line] = abs(b->x - a->x); \
307 dy[line] = abs(b->y - a->y); \
308 incx[line] = LINC[b->x > a->x]; \
309 ex[line] = -(dy[line]>>1); \
311 #define DOINIT(a, b, line) \
312 INITLINE(a, b, line); \
313 INITCOL(a, b, line, Red, 0); \
314 INITCOL(a, b, line, Green, 1); \
315 INITCOL(a, b, line, Blue, 2);
316 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x)
317 #define SWAP(a,b,c) c = a;\
322 IntEngGradientFillTriangle(
326 IN TRIVERTEX
*pVertex
,
328 IN PGRADIENT_TRIANGLE gTriangle
,
329 IN RECTL
*prclExtents
,
330 IN POINTL
*pptlDitherOrg
)
334 PTRIVERTEX v1
, v2
, v3
;
339 INTENG_ENTER_LEAVE EnterLeave
;
344 LONG x
[NLINES
], dx
[NLINES
], dy
[NLINES
], incx
[NLINES
], ex
[NLINES
], destx
[NLINES
];
345 LONG c
[NLINES
][3], dc
[NLINES
][3], ec
[NLINES
][3], ic
[NLINES
][3]; /* colors on lines */
346 LONG g
, gx
, gxi
, gc
[3], gd
[3], ge
[3], gi
[3]; /* colors in triangle */
349 v1
= (pVertex
+ gTriangle
->Vertex1
);
350 v2
= (pVertex
+ gTriangle
->Vertex2
);
351 v3
= (pVertex
+ gTriangle
->Vertex3
);
369 DbgPrint("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1
->x
, v1
->y
, v2
->x
, v2
->y
, v3
->x
, v3
->y
);
371 if(!IntEngEnter(&EnterLeave
, psoDest
, &FillRect
, FALSE
, &Translate
, &OutputObj
))
375 OutputGDI
= AccessInternalObjectFromUserObject(OutputObj
);
377 if(VCMPCLRS(v1
, v2
, v3
))
379 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
382 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
383 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= prclExtents
->bottom
; i
++)
385 if(NtGdiIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], prclExtents
))
394 sy
= v1
->y
+ pptlDitherOrg
->y
;
395 bt
= min(v3
->y
+ pptlDitherOrg
->y
, FillRect
.bottom
);
399 InY
= !(sy
< FillRect
.top
|| sy
>= FillRect
.bottom
);
421 return IntEngLeave(&EnterLeave
);
424 /* fill triangle with one solid color */
426 Color
= XLATEOBJ_iXlate(pxlo
, RGB(v1
->Red
>> 8, v1
->Green
>> 8, v1
->Blue
>> 8));
427 CLIPOBJ_cEnumStart(pco
, FALSE
, CT_RECTANGLES
, CD_RIGHTDOWN
, 0);
430 EnumMore
= CLIPOBJ_bEnum(pco
, (ULONG
) sizeof(RectEnum
), (PVOID
) &RectEnum
);
431 for (i
= 0; i
< RectEnum
.c
&& RectEnum
.arcl
[i
].top
<= prclExtents
->bottom
; i
++)
433 if(NtGdiIntersectRect(&FillRect
, &RectEnum
.arcl
[i
], prclExtents
))
435 S_INITLINE(v1
, v3
, 0);
436 S_INITLINE(v1
, v2
, 1);
437 S_INITLINE(v2
, v3
, 2);
440 sy
= v1
->y
+ pptlDitherOrg
->y
;
441 bt
= min(v3
->y
+ pptlDitherOrg
->y
, FillRect
.bottom
);
447 S_ENDLINE(v1
, v3
, 0);
452 S_ENDLINE(v1
, v2
, 1);
457 S_ENDLINE(23, v3
, 2);
466 return IntEngLeave(&EnterLeave
);
471 IntEngIsNULLTriangle(TRIVERTEX
*pVertex
, GRADIENT_TRIANGLE
*gt
)
473 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex2
)))
475 if(COMPAREVERTEX(VERTEX(Vertex1
), VERTEX(Vertex3
)))
477 if(COMPAREVERTEX(VERTEX(Vertex2
), VERTEX(Vertex3
)))
488 IN TRIVERTEX
*pVertex
,
492 IN RECTL
*prclExtents
,
493 IN POINTL
*pptlDitherOrg
,
500 case GRADIENT_FILL_RECT_H
:
501 case GRADIENT_FILL_RECT_V
:
503 PGRADIENT_RECT gr
= (PGRADIENT_RECT
)pMesh
;
504 for(i
= 0; i
< nMesh
; i
++, gr
++)
506 if(!IntEngGradientFillRect(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gr
, prclExtents
,
507 pptlDitherOrg
, (ulMode
== GRADIENT_FILL_RECT_H
)))
514 case GRADIENT_FILL_TRIANGLE
:
516 PGRADIENT_TRIANGLE gt
= (PGRADIENT_TRIANGLE
)pMesh
;
517 for(i
= 0; i
< nMesh
; i
++, gt
++)
519 if(IntEngIsNULLTriangle(pVertex
, gt
))
521 /* skip empty triangles */
524 if(!IntEngGradientFillTriangle(psoDest
, pco
, pxlo
, pVertex
, nVertex
, gt
, prclExtents
,
541 IN TRIVERTEX
*pVertex
,
545 IN RECTL
*prclExtents
,
546 IN POINTL
*pptlDitherOrg
,
552 SurfGDI
= (SURFGDI
*)AccessInternalObjectFromUserObject(psoDest
);
553 MouseSafetyOnDrawStart(psoDest
, SurfGDI
, pco
->rclBounds
.left
, pco
->rclBounds
.top
,
554 pco
->rclBounds
.right
, pco
->rclBounds
.bottom
);
555 if((psoDest
->iType
!= STYPE_BITMAP
) && SurfGDI
->GradientFill
)
557 IntLockGDIDriver(SurfGDI
);
558 Ret
= SurfGDI
->GradientFill(psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
,
559 prclExtents
, pptlDitherOrg
, ulMode
);
560 IntUnLockGDIDriver(SurfGDI
);
561 MouseSafetyOnDrawEnd(psoDest
, SurfGDI
);
564 Ret
= EngGradientFill(psoDest
, pco
, pxlo
, pVertex
, nVertex
, pMesh
, nMesh
, prclExtents
,
565 pptlDitherOrg
, ulMode
);
568 /* Dummy BitBlt to let driver know that something has changed.
569 0x00AA0029 is the Rop for D (no-op) */
572 IntLockGDIDriver(SurfGDI
);
573 SurfGDI
->BitBlt(psoDest
, NULL
, NULL
, pco
, pxlo
,
574 prclExtents
, pptlDitherOrg
, NULL
, NULL
, NULL
, ROP_NOOP
);
575 IntUnLockGDIDriver(SurfGDI
);
576 MouseSafetyOnDrawEnd(psoDest
, SurfGDI
);
579 EngBitBlt(psoDest
, NULL
, NULL
, pco
, pxlo
,
580 prclExtents
, pptlDitherOrg
, NULL
, NULL
, NULL
, ROP_NOOP
);
582 MouseSafetyOnDrawEnd(psoDest
, SurfGDI
);