[WIN32K]
[reactos.git] / subsystems / win32 / 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 along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 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 /* Horizontal/Vertical gradients */
47 #define HVINITCOL(Col, id) \
48 c[id] = v1->Col >> 8; \
49 dc[id] = abs((v2->Col >> 8) - c[id]); \
50 ec[id] = -(dy >> 1); \
51 ic[id] = LINC[(v2->Col >> 8) > c[id]]
52 #define HVSTEPCOL(id) \
53 ec[id] += dc[id]; \
54 while(ec[id] > 0) \
55 { \
56 c[id] += ic[id]; \
57 ec[id] -= dy; \
58 }
59
60 /* FUNCTIONS ******************************************************************/
61
62 BOOL FASTCALL
63 IntEngGradientFillRect(
64 IN SURFOBJ *psoDest,
65 IN CLIPOBJ *pco,
66 IN XLATEOBJ *pxlo,
67 IN TRIVERTEX *pVertex,
68 IN ULONG nVertex,
69 IN PGRADIENT_RECT gRect,
70 IN RECTL *prclExtents,
71 IN POINTL *pptlDitherOrg,
72 IN BOOL Horizontal)
73 {
74 SURFOBJ *psoOutput;
75 TRIVERTEX *v1, *v2;
76 RECTL rcGradient, rcSG;
77 RECT_ENUM RectEnum;
78 BOOL EnumMore;
79 ULONG i;
80 POINTL Translate;
81 INTENG_ENTER_LEAVE EnterLeave;
82 LONG y, dy, c[3], dc[3], ec[3], ic[3];
83
84 v1 = (pVertex + gRect->UpperLeft);
85 v2 = (pVertex + gRect->LowerRight);
86
87 rcGradient.left = min(v1->x, v2->x);
88 rcGradient.right = max(v1->x, v2->x);
89 rcGradient.top = min(v1->y, v2->y);
90 rcGradient.bottom = max(v1->y, v2->y);
91 rcSG = rcGradient;
92 RECTL_vOffsetRect(&rcSG, pptlDitherOrg->x, pptlDitherOrg->y);
93
94 if(Horizontal)
95 {
96 dy = abs(rcGradient.right - rcGradient.left);
97 }
98 else
99 {
100 dy = abs(rcGradient.bottom - rcGradient.top);
101 }
102
103 if(!IntEngEnter(&EnterLeave, psoDest, &rcSG, FALSE, &Translate, &psoOutput))
104 {
105 return FALSE;
106 }
107
108 if((v1->Red != v2->Red || v1->Green != v2->Green || v1->Blue != v2->Blue) && dy > 1)
109 {
110 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
111 do
112 {
113 RECTL FillRect;
114 ULONG Color;
115
116 if(Horizontal)
117 {
118 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
119 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
120 {
121 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
122 {
123 HVINITCOL(Red, 0);
124 HVINITCOL(Green, 1);
125 HVINITCOL(Blue, 2);
126
127 for(y = rcSG.left; y < FillRect.right; y++)
128 {
129 if(y >= FillRect.left)
130 {
131 Color = XLATEOBJ_iXlate(pxlo, RGB(c[0], c[1], c[2]));
132 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_VLine(
133 psoOutput, y, FillRect.top, FillRect.bottom, Color);
134 }
135 HVSTEPCOL(0);
136 HVSTEPCOL(1);
137 HVSTEPCOL(2);
138 }
139 }
140 }
141
142 continue;
143 }
144
145 /* vertical */
146 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
147 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
148 {
149 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
150 {
151 HVINITCOL(Red, 0);
152 HVINITCOL(Green, 1);
153 HVINITCOL(Blue, 2);
154
155 for(y = rcSG.top; y < FillRect.bottom; y++)
156 {
157 if(y >= FillRect.top)
158 {
159 Color = XLATEOBJ_iXlate(pxlo, RGB(c[0], c[1], c[2]));
160 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(
161 psoOutput, FillRect.left, FillRect.right, y, Color);
162 }
163 HVSTEPCOL(0);
164 HVSTEPCOL(1);
165 HVSTEPCOL(2);
166 }
167 }
168 }
169
170 } while(EnumMore);
171
172 return IntEngLeave(&EnterLeave);
173 }
174
175 /* rectangle has only one color, no calculation required */
176 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
177 do
178 {
179 RECTL FillRect;
180 ULONG Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red, v1->Green, v1->Blue));
181
182 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
183 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
184 {
185 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
186 {
187 for(; FillRect.top < FillRect.bottom; FillRect.top++)
188 {
189 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(
190 psoOutput, FillRect.left, FillRect.right, FillRect.top, Color);
191 }
192 }
193 }
194 } while(EnumMore);
195
196 return IntEngLeave(&EnterLeave);
197 }
198
199 /* Fill triangle with solid color */
200 #define S_FILLLINE(linefrom,lineto) \
201 if(sx[lineto] < sx[linefrom]) \
202 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[lineto], FillRect.left), min(sx[linefrom], FillRect.right), sy, Color); \
203 else \
204 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(psoOutput, max(sx[linefrom], FillRect.left), min(sx[lineto], FillRect.right), sy, Color);
205 #define S_DOLINE(a,b,line) \
206 ex[line] += dx[line]; \
207 while(ex[line] > 0 && x[line] != destx[line]) \
208 { \
209 x[line] += incx[line]; \
210 sx[line] += incx[line]; \
211 ex[line] -= dy[line]; \
212 }
213 #define S_GOLINE(a,b,line) \
214 if(y >= a->y && y <= b->y) \
215 {
216 #define S_ENDLINE(a,b,line) \
217 }
218 #define S_INITLINE(a,b,line) \
219 x[line] = a->x; \
220 sx[line] = a->x + pptlDitherOrg->x; \
221 dx[line] = abs(b->x - a->x); \
222 dy[line] = abs(b->y - a->y); \
223 incx[line] = LINC[b->x > a->x]; \
224 ex[line] = -(dy[line]>>1); \
225 destx[line] = b->x
226
227 /* Fill triangle with gradient */
228 #define INITCOL(a,b,line,col,id) \
229 c[line][id] = a->col >> 8; \
230 dc[line][id] = abs((b->col >> 8) - c[line][id]); \
231 ec[line][id] = -(dy[line]>>1); \
232 ic[line][id] = LINC[(b->col >> 8) > c[line][id]]
233 #define STEPCOL(a,b,line,col,id) \
234 ec[line][id] += dc[line][id]; \
235 while(ec[line][id] > 0) \
236 { \
237 c[line][id] += ic[line][id]; \
238 ec[line][id] -= dy[line]; \
239 }
240 #define FINITCOL(linefrom,lineto,colid) \
241 gc[colid] = c[linefrom][colid]; \
242 gd[colid] = abs(c[lineto][colid] - gc[colid]); \
243 ge[colid] = -(gx >> 1); \
244 gi[colid] = LINC[c[lineto][colid] > gc[colid]]
245 #define FDOCOL(linefrom,lineto,colid) \
246 ge[colid] += gd[colid]; \
247 while(ge[colid] > 0) \
248 { \
249 gc[colid] += gi[colid]; \
250 ge[colid] -= gx; \
251 }
252 #define FILLLINE(linefrom,lineto) \
253 gx = abs(sx[lineto] - sx[linefrom]); \
254 gxi = LINC[sx[linefrom] < sx[lineto]]; \
255 FINITCOL(linefrom, lineto, 0); \
256 FINITCOL(linefrom, lineto, 1); \
257 FINITCOL(linefrom, lineto, 2); \
258 for(g = sx[linefrom]; g != sx[lineto]; g += gxi) \
259 { \
260 if(InY && g >= FillRect.left && g < FillRect.right) \
261 { \
262 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
263 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_PutPixel(psoOutput, g, sy, Color); \
264 } \
265 FDOCOL(linefrom, lineto, 0); \
266 FDOCOL(linefrom, lineto, 1); \
267 FDOCOL(linefrom, lineto, 2); \
268 }
269 #define DOLINE(a,b,line) \
270 STEPCOL(a, b, line, Red, 0); \
271 STEPCOL(a, b, line, Green, 1); \
272 STEPCOL(a, b, line, Blue, 2); \
273 ex[line] += dx[line]; \
274 while(ex[line] > 0 && x[line] != destx[line]) \
275 { \
276 x[line] += incx[line]; \
277 sx[line] += incx[line]; \
278 ex[line] -= dy[line]; \
279 }
280 #define GOLINE(a,b,line) \
281 if(y >= a->y && y <= b->y) \
282 {
283 #define ENDLINE(a,b,line) \
284 }
285 #define INITLINE(a,b,line) \
286 x[line] = a->x; \
287 sx[line] = a->x + pptlDitherOrg->x; \
288 dx[line] = abs(b->x - a->x); \
289 dy[line] = abs(b->y - a->y); \
290 incx[line] = LINC[b->x > a->x]; \
291 ex[line] = -(dy[line]>>1); \
292 destx[line] = b->x
293 #define DOINIT(a, b, line) \
294 INITLINE(a, b, line); \
295 INITCOL(a, b, line, Red, 0); \
296 INITCOL(a, b, line, Green, 1); \
297 INITCOL(a, b, line, Blue, 2);
298 #define SMALLER(a,b) (a->y < b->y) || (a->y == b->y && a->x < b->x)
299 #define SWAP(a,b,c) c = a;\
300 a = b;\
301 a = c
302 #define NLINES 3
303 BOOL FASTCALL
304 IntEngGradientFillTriangle(
305 IN SURFOBJ *psoDest,
306 IN CLIPOBJ *pco,
307 IN XLATEOBJ *pxlo,
308 IN TRIVERTEX *pVertex,
309 IN ULONG nVertex,
310 IN PGRADIENT_TRIANGLE gTriangle,
311 IN RECTL *prclExtents,
312 IN POINTL *pptlDitherOrg)
313 {
314 SURFOBJ *psoOutput;
315 PTRIVERTEX v1, v2, v3;
316 //RECT_ENUM RectEnum;
317 //BOOL EnumMore;
318 //ULONG i;
319 POINTL Translate;
320 INTENG_ENTER_LEAVE EnterLeave;
321 RECTL FillRect;
322 //ULONG Color;
323
324 //BOOL sx[NLINES];
325 //LONG x[NLINES], dx[NLINES], dy[NLINES], incx[NLINES], ex[NLINES], destx[NLINES];
326 //LONG c[NLINES][3], dc[NLINES][3], ec[NLINES][3], ic[NLINES][3]; /* colors on lines */
327 //LONG g, gx, gxi, gc[3], gd[3], ge[3], gi[3]; /* colors in triangle */
328 //LONG sy, y, bt;
329
330 v1 = (pVertex + gTriangle->Vertex1);
331 v2 = (pVertex + gTriangle->Vertex2);
332 v3 = (pVertex + gTriangle->Vertex3);
333
334 /* bubble sort */
335 if(SMALLER(v2,v1))
336 {
337 TRIVERTEX *t;
338 SWAP(v1,v2,t);
339 }
340 if(SMALLER(v3,v2))
341 {
342 TRIVERTEX *t;
343 SWAP(v2,v3,t);
344 if(SMALLER(v2,v1))
345 {
346 SWAP(v1,v2,t);
347 }
348 }
349
350 DPRINT1("Triangle: (%i,%i) (%i,%i) (%i,%i)\n", v1->x, v1->y, v2->x, v2->y, v3->x, v3->y);
351 /* FIXME: commented out because of an endless loop - fix triangles first */
352 DPRINT1("FIXME: IntEngGradientFillTriangle is broken\n");
353
354 if(!IntEngEnter(&EnterLeave, psoDest, &FillRect, FALSE, &Translate, &psoOutput))
355 {
356 return FALSE;
357 }
358
359 //if(VCMPCLRS(v1, v2, v3))
360 //{
361 // CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
362 // do
363 // {
364 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
365 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
366 // {
367 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
368 // {
369 // BOOL InY;
370
371 // DOINIT(v1, v3, 0);
372 // DOINIT(v1, v2, 1);
373 // DOINIT(v2, v3, 2);
374
375 // y = v1->y;
376 // sy = v1->y + pptlDitherOrg->y;
377 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
378
379 // while(sy < bt)
380 // {
381 // InY = !(sy < FillRect.top || sy >= FillRect.bottom);
382 // GOLINE(v1, v3, 0);
383 // DOLINE(v1, v3, 0);
384 // ENDLINE(v1, v3, 0);
385
386 // GOLINE(v1, v2, 1);
387 // DOLINE(v1, v2, 1);
388 // FILLLINE(0, 1);
389 // ENDLINE(v1, v2, 1);
390
391 // GOLINE(v2, v3, 2);
392 // DOLINE(v2, v3, 2);
393 // FILLLINE(0, 2);
394 // ENDLINE(23, v3, 2);
395
396 // y++;
397 // sy++;
398 // }
399 // }
400 // }
401 // } while(EnumMore);
402
403 // return IntEngLeave(&EnterLeave);
404 //}
405
406 ///* fill triangle with one solid color */
407
408 //Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red >> 8, v1->Green >> 8, v1->Blue >> 8));
409 //CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
410 //do
411 //{
412 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
413 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
414 // {
415 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
416 // {
417 // S_INITLINE(v1, v3, 0);
418 // S_INITLINE(v1, v2, 1);
419 // S_INITLINE(v2, v3, 2);
420
421 // y = v1->y;
422 // sy = v1->y + pptlDitherOrg->y;
423 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
424
425 // while(sy < bt)
426 // {
427 // S_GOLINE(v1, v3, 0);
428 // S_DOLINE(v1, v3, 0);
429 // S_ENDLINE(v1, v3, 0);
430
431 // S_GOLINE(v1, v2, 1);
432 // S_DOLINE(v1, v2, 1);
433 // S_FILLLINE(0, 1);
434 // S_ENDLINE(v1, v2, 1);
435
436 // S_GOLINE(v2, v3, 2);
437 // S_DOLINE(v2, v3, 2);
438 // S_FILLLINE(0, 2);
439 // S_ENDLINE(23, v3, 2);
440
441 // y++;
442 // sy++;
443 // }
444 // }
445 // }
446 //} while(EnumMore);
447
448 return IntEngLeave(&EnterLeave);
449 }
450
451
452 static BOOL
453 IntEngIsNULLTriangle(TRIVERTEX *pVertex, GRADIENT_TRIANGLE *gt)
454 {
455 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex2)))
456 return TRUE;
457 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex3)))
458 return TRUE;
459 if(COMPAREVERTEX(VERTEX(Vertex2), VERTEX(Vertex3)))
460 return TRUE;
461 return FALSE;
462 }
463
464
465 BOOL APIENTRY
466 EngGradientFill(
467 IN SURFOBJ *psoDest,
468 IN CLIPOBJ *pco,
469 IN XLATEOBJ *pxlo,
470 IN TRIVERTEX *pVertex,
471 IN ULONG nVertex,
472 IN PVOID pMesh,
473 IN ULONG nMesh,
474 IN RECTL *prclExtents,
475 IN POINTL *pptlDitherOrg,
476 IN ULONG ulMode)
477 {
478 ULONG i;
479 BOOL ret = FALSE;
480
481 if (!pco)
482 {
483 pco = IntEngCreateClipRegion(0, 0, prclExtents);
484 if (!pco)
485 {
486 return FALSE;
487 }
488 }
489
490 switch(ulMode)
491 {
492 case GRADIENT_FILL_RECT_H:
493 case GRADIENT_FILL_RECT_V:
494 {
495 PGRADIENT_RECT gr = (PGRADIENT_RECT)pMesh;
496 for(i = 0; i < nMesh; i++, gr++)
497 {
498 if(!IntEngGradientFillRect(psoDest, pco, pxlo, pVertex, nVertex, gr, prclExtents,
499 pptlDitherOrg, (ulMode == GRADIENT_FILL_RECT_H)))
500 {
501 break;
502 }
503 }
504 ret = TRUE;
505 break;
506 }
507 case GRADIENT_FILL_TRIANGLE:
508 {
509 PGRADIENT_TRIANGLE gt = (PGRADIENT_TRIANGLE)pMesh;
510 for(i = 0; i < nMesh; i++, gt++)
511 {
512 if(IntEngIsNULLTriangle(pVertex, gt))
513 {
514 /* skip empty triangles */
515 continue;
516 }
517 if(!IntEngGradientFillTriangle(psoDest, pco, pxlo, pVertex, nVertex, gt, prclExtents,
518 pptlDitherOrg))
519 {
520 break;
521 }
522 }
523 ret = TRUE;
524 break;
525 }
526 }
527
528 return ret;
529 }
530
531 BOOL APIENTRY
532 IntEngGradientFill(
533 IN SURFOBJ *psoDest,
534 IN CLIPOBJ *pco,
535 IN XLATEOBJ *pxlo,
536 IN TRIVERTEX *pVertex,
537 IN ULONG nVertex,
538 IN PVOID pMesh,
539 IN ULONG nMesh,
540 IN RECTL *prclExtents,
541 IN POINTL *pptlDitherOrg,
542 IN ULONG ulMode)
543 {
544 BOOL Ret;
545 SURFACE *psurf;
546 ASSERT(psoDest);
547
548 psurf = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
549 ASSERT(psurf);
550
551 if(psurf->flHooks & HOOK_GRADIENTFILL)
552 {
553 Ret = GDIDEVFUNCS(psoDest).GradientFill(
554 psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh,
555 prclExtents, pptlDitherOrg, ulMode);
556 }
557 else
558 {
559 Ret = EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
560 pptlDitherOrg, ulMode);
561 }
562
563 return Ret;
564 }