Revert, thx Thomas, wasnt sure.
[reactos.git] / reactos / subsys / win32k / eng / gradient.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998 - 2004 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /* $Id$
20 *
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
26 * REVISION HISTORY:
27 * 3/7/1999: Created
28 */
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* MACROS *********************************************************************/
36
37 const LONG LINC[2] = {-1, 1};
38
39 #define VERTEX(n) (pVertex + gt->n)
40 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y)
41
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))
45
46 #define MOVERECT(r,x,y) \
47 r.left += x; r.right += x; \
48 r.top += y; r.bottom += y
49
50
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) \
58 ec[id] += dc[id]; \
59 while(ec[id] > 0) \
60 { \
61 c[id] += ic[id]; \
62 ec[id] -= dy; \
63 }
64
65 /* FUNCTIONS ******************************************************************/
66
67 BOOL FASTCALL
68 IntEngGradientFillRect(
69 IN SURFOBJ *psoDest,
70 IN CLIPOBJ *pco,
71 IN XLATEOBJ *pxlo,
72 IN TRIVERTEX *pVertex,
73 IN ULONG nVertex,
74 IN PGRADIENT_RECT gRect,
75 IN RECTL *prclExtents,
76 IN POINTL *pptlDitherOrg,
77 IN BOOL Horizontal)
78 {
79 SURFOBJ *OutputObj;
80 TRIVERTEX *v1, *v2;
81 RECTL rcGradient, rcSG;
82 RECT_ENUM RectEnum;
83 BOOL EnumMore;
84 ULONG i;
85 POINTL Translate;
86 INTENG_ENTER_LEAVE EnterLeave;
87 LONG y, dy, c[3], dc[3], ec[3], ic[3];
88
89 v1 = (pVertex + gRect->UpperLeft);
90 v2 = (pVertex + gRect->LowerRight);
91
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);
96 rcSG = rcGradient;
97 MOVERECT(rcSG, pptlDitherOrg->x, pptlDitherOrg->y);
98
99 if(Horizontal)
100 {
101 dy = abs(rcGradient.right - rcGradient.left);
102 }
103 else
104 {
105 dy = abs(rcGradient.bottom - rcGradient.top);
106 }
107
108 if(!IntEngEnter(&EnterLeave, psoDest, &rcSG, FALSE, &Translate, &OutputObj))
109 {
110 return FALSE;
111 }
112
113 if((v1->Red != v2->Red || v1->Green != v2->Green || v1->Blue != v2->Blue) && dy > 1)
114 {
115 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
116 do
117 {
118 RECT FillRect;
119 ULONG Color;
120
121 if(Horizontal)
122 {
123 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
124 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
125 {
126 if(IntGdiIntersectRect(&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)&rcSG))
127 {
128 HVINITCOL(Red, 0);
129 HVINITCOL(Green, 1);
130 HVINITCOL(Blue, 2);
131
132 for(y = rcSG.left; y < FillRect.right; y++)
133 {
134 if(y >= FillRect.left)
135 {
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);
139 }
140 HVSTEPCOL(0);
141 HVSTEPCOL(1);
142 HVSTEPCOL(2);
143 }
144 }
145 }
146
147 continue;
148 }
149
150 /* vertical */
151 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
152 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
153 {
154 if(IntGdiIntersectRect(&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)&rcSG))
155 {
156 HVINITCOL(Red, 0);
157 HVINITCOL(Green, 1);
158 HVINITCOL(Blue, 2);
159
160 for(y = rcSG.top; y < FillRect.bottom; y++)
161 {
162 if(y >= FillRect.top)
163 {
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);
167 }
168 HVSTEPCOL(0);
169 HVSTEPCOL(1);
170 HVSTEPCOL(2);
171 }
172 }
173 }
174
175 } while(EnumMore);
176
177 return IntEngLeave(&EnterLeave);
178 }
179
180 /* rectangle has only one color, no calculation required */
181 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
182 do
183 {
184 RECT FillRect;
185 ULONG Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red, v1->Green, v1->Blue));
186
187 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
188 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
189 {
190 if(IntGdiIntersectRect(&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)&rcSG))
191 {
192 for(; FillRect.top < FillRect.bottom; FillRect.top++)
193 {
194 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_HLine(
195 OutputObj, FillRect.left, FillRect.right, FillRect.top, Color);
196 }
197 }
198 }
199 } while(EnumMore);
200
201 return IntEngLeave(&EnterLeave);
202 }
203
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); \
208 else \
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]) \
213 { \
214 x[line] += incx[line]; \
215 sx[line] += incx[line]; \
216 ex[line] -= dy[line]; \
217 }
218 #define S_GOLINE(a,b,line) \
219 if(y >= a->y && y <= b->y) \
220 {
221 #define S_ENDLINE(a,b,line) \
222 }
223 #define S_INITLINE(a,b,line) \
224 x[line] = a->x; \
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); \
230 destx[line] = b->x
231
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) \
241 { \
242 c[line][id] += ic[line][id]; \
243 ec[line][id] -= dy[line]; \
244 }
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) \
253 { \
254 gc[colid] += gi[colid]; \
255 ge[colid] -= gx; \
256 }
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) \
264 { \
265 if(InY && g >= FillRect.left && g < FillRect.right) \
266 { \
267 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
268 DibFunctionsForBitmapFormat[OutputObj->iBitmapFormat].DIB_PutPixel(OutputObj, g, sy, Color); \
269 } \
270 FDOCOL(linefrom, lineto, 0); \
271 FDOCOL(linefrom, lineto, 1); \
272 FDOCOL(linefrom, lineto, 2); \
273 }
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]) \
280 { \
281 x[line] += incx[line]; \
282 sx[line] += incx[line]; \
283 ex[line] -= dy[line]; \
284 }
285 #define GOLINE(a,b,line) \
286 if(y >= a->y && y <= b->y) \
287 {
288 #define ENDLINE(a,b,line) \
289 }
290 #define INITLINE(a,b,line) \
291 x[line] = a->x; \
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); \
297 destx[line] = b->x
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;\
305 a = b;\
306 a = c
307 #define NLINES 3
308 BOOL FASTCALL
309 IntEngGradientFillTriangle(
310 IN SURFOBJ *psoDest,
311 IN CLIPOBJ *pco,
312 IN XLATEOBJ *pxlo,
313 IN TRIVERTEX *pVertex,
314 IN ULONG nVertex,
315 IN PGRADIENT_TRIANGLE gTriangle,
316 IN RECTL *prclExtents,
317 IN POINTL *pptlDitherOrg)
318 {
319 SURFOBJ *OutputObj;
320 PTRIVERTEX v1, v2, v3;
321 RECT_ENUM RectEnum;
322 BOOL EnumMore;
323 ULONG i;
324 POINTL Translate;
325 INTENG_ENTER_LEAVE EnterLeave;
326 RECTL FillRect;
327 ULONG Color;
328
329 BOOL sx[NLINES];
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 */
333 LONG sy, y, bt;
334
335 v1 = (pVertex + gTriangle->Vertex1);
336 v2 = (pVertex + gTriangle->Vertex2);
337 v3 = (pVertex + gTriangle->Vertex3);
338
339 /* bubble sort */
340 if(SMALLER(v2,v1))
341 {
342 TRIVERTEX *t;
343 SWAP(v1,v2,t);
344 }
345 if(SMALLER(v3,v2))
346 {
347 TRIVERTEX *t;
348 SWAP(v2,v3,t);
349 if(SMALLER(v2,v1))
350 {
351 SWAP(v1,v2,t);
352 }
353 }
354
355 DbgPrint("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1->x, v1->y, v2->x, v2->y, v3->x, v3->y);
356
357 if(!IntEngEnter(&EnterLeave, psoDest, &FillRect, FALSE, &Translate, &OutputObj))
358 {
359 return FALSE;
360 }
361
362 if(VCMPCLRS(v1, v2, v3))
363 {
364 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
365 do
366 {
367 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
368 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
369 {
370 if(IntGdiIntersectRect((PRECT)&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)prclExtents))
371 {
372 BOOL InY;
373
374 DOINIT(v1, v3, 0);
375 DOINIT(v1, v2, 1);
376 DOINIT(v2, v3, 2);
377
378 y = v1->y;
379 sy = v1->y + pptlDitherOrg->y;
380 bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
381
382 while(sy < bt)
383 {
384 InY = !(sy < FillRect.top || sy >= FillRect.bottom);
385 GOLINE(v1, v3, 0);
386 DOLINE(v1, v3, 0);
387 ENDLINE(v1, v3, 0);
388
389 GOLINE(v1, v2, 1);
390 DOLINE(v1, v2, 1);
391 FILLLINE(0, 1);
392 ENDLINE(v1, v2, 1);
393
394 GOLINE(v2, v3, 2);
395 DOLINE(v2, v3, 2);
396 FILLLINE(0, 2);
397 ENDLINE(23, v3, 2);
398
399 y++;
400 sy++;
401 }
402 }
403 }
404 } while(EnumMore);
405
406 return IntEngLeave(&EnterLeave);
407 }
408
409 /* fill triangle with one solid color */
410
411 Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8));
412 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
413 do
414 {
415 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
416 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
417 {
418 if(IntGdiIntersectRect((PRECT)&FillRect, (PRECT)&RectEnum.arcl[i], (PRECT)prclExtents))
419 {
420 S_INITLINE(v1, v3, 0);
421 S_INITLINE(v1, v2, 1);
422 S_INITLINE(v2, v3, 2);
423
424 y = v1->y;
425 sy = v1->y + pptlDitherOrg->y;
426 bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
427
428 while(sy < bt)
429 {
430 S_GOLINE(v1, v3, 0);
431 S_DOLINE(v1, v3, 0);
432 S_ENDLINE(v1, v3, 0);
433
434 S_GOLINE(v1, v2, 1);
435 S_DOLINE(v1, v2, 1);
436 S_FILLLINE(0, 1);
437 S_ENDLINE(v1, v2, 1);
438
439 S_GOLINE(v2, v3, 2);
440 S_DOLINE(v2, v3, 2);
441 S_FILLLINE(0, 2);
442 S_ENDLINE(23, v3, 2);
443
444 y++;
445 sy++;
446 }
447 }
448 }
449 } while(EnumMore);
450
451 return IntEngLeave(&EnterLeave);
452 }
453
454
455 BOOL FASTCALL STATIC
456 IntEngIsNULLTriangle(TRIVERTEX *pVertex, GRADIENT_TRIANGLE *gt)
457 {
458 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex2)))
459 return TRUE;
460 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex3)))
461 return TRUE;
462 if(COMPAREVERTEX(VERTEX(Vertex2), VERTEX(Vertex3)))
463 return TRUE;
464 return FALSE;
465 }
466
467
468 BOOL STDCALL
469 EngGradientFill(
470 IN SURFOBJ *psoDest,
471 IN CLIPOBJ *pco,
472 IN XLATEOBJ *pxlo,
473 IN TRIVERTEX *pVertex,
474 IN ULONG nVertex,
475 IN PVOID pMesh,
476 IN ULONG nMesh,
477 IN RECTL *prclExtents,
478 IN POINTL *pptlDitherOrg,
479 IN ULONG ulMode)
480 {
481 ULONG i;
482
483 switch(ulMode)
484 {
485 case GRADIENT_FILL_RECT_H:
486 case GRADIENT_FILL_RECT_V:
487 {
488 PGRADIENT_RECT gr = (PGRADIENT_RECT)pMesh;
489 for(i = 0; i < nMesh; i++, gr++)
490 {
491 if(!IntEngGradientFillRect(psoDest, pco, pxlo, pVertex, nVertex, gr, prclExtents,
492 pptlDitherOrg, (ulMode == GRADIENT_FILL_RECT_H)))
493 {
494 return FALSE;
495 }
496 }
497 return TRUE;
498 }
499 case GRADIENT_FILL_TRIANGLE:
500 {
501 PGRADIENT_TRIANGLE gt = (PGRADIENT_TRIANGLE)pMesh;
502 for(i = 0; i < nMesh; i++, gt++)
503 {
504 if(IntEngIsNULLTriangle(pVertex, gt))
505 {
506 /* skip empty triangles */
507 continue;
508 }
509 if(!IntEngGradientFillTriangle(psoDest, pco, pxlo, pVertex, nVertex, gt, prclExtents,
510 pptlDitherOrg))
511 {
512 return FALSE;
513 }
514 }
515 return TRUE;
516 }
517 }
518 return FALSE;
519 }
520
521 BOOL STDCALL
522 IntEngGradientFill(
523 IN SURFOBJ *psoDest,
524 IN CLIPOBJ *pco,
525 IN XLATEOBJ *pxlo,
526 IN TRIVERTEX *pVertex,
527 IN ULONG nVertex,
528 IN PVOID pMesh,
529 IN ULONG nMesh,
530 IN RECTL *prclExtents,
531 IN POINTL *pptlDitherOrg,
532 IN ULONG ulMode)
533 {
534 BOOL Ret;
535 BITMAPOBJ *pboDest;
536 ASSERT(psoDest);
537 ASSERT(pco);
538
539 pboDest = CONTAINING_RECORD(psoDest, BITMAPOBJ, SurfObj);
540 ASSERT(pboDest);
541
542 BITMAPOBJ_LockBitmapBits(pboDest);
543 MouseSafetyOnDrawStart(
544 psoDest,
545 pco->rclBounds.left,
546 pco->rclBounds.top,
547 pco->rclBounds.right,
548 pco->rclBounds.bottom);
549 if(pboDest->flHooks & HOOK_GRADIENTFILL)
550 {
551 Ret = GDIDEVFUNCS(psoDest).GradientFill(
552 psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh,
553 prclExtents, pptlDitherOrg, ulMode);
554 MouseSafetyOnDrawEnd(psoDest);
555 return Ret;
556 }
557 Ret = EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
558 pptlDitherOrg, ulMode);
559 MouseSafetyOnDrawEnd(psoDest);
560 BITMAPOBJ_UnlockBitmapBits(pboDest);
561
562 return Ret;
563 }