[WIN32SS]
[reactos.git] / reactos / win32ss / gdi / eng / gradient.c
1 /*
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
7 */
8
9 #include <win32k.h>
10
11 #define NDEBUG
12 #include <debug.h>
13
14 /* MACROS *********************************************************************/
15
16 const LONG LINC[2] = {-1, 1};
17
18 #define VERTEX(n) (pVertex + gt->n)
19 #define COMPAREVERTEX(a, b) ((a)->x == (b)->x && (a)->y == (b)->y)
20
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))
24
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) \
32 ec[id] += dc[id]; \
33 while(ec[id] > 0) \
34 { \
35 c[id] += ic[id]; \
36 ec[id] -= dy; \
37 }
38
39 /* FUNCTIONS ******************************************************************/
40
41 BOOL FASTCALL
42 IntEngGradientFillRect(
43 IN SURFOBJ *psoDest,
44 IN CLIPOBJ *pco,
45 IN XLATEOBJ *pxlo,
46 IN TRIVERTEX *pVertex,
47 IN ULONG nVertex,
48 IN PGRADIENT_RECT gRect,
49 IN RECTL *prclExtents,
50 IN POINTL *pptlDitherOrg,
51 IN BOOL Horizontal)
52 {
53 SURFOBJ *psoOutput;
54 TRIVERTEX *v1, *v2;
55 RECTL rcGradient, rcSG;
56 RECT_ENUM RectEnum;
57 BOOL EnumMore;
58 ULONG i;
59 POINTL Translate;
60 INTENG_ENTER_LEAVE EnterLeave;
61 LONG y, dy, c[3], dc[3], ec[3], ic[3];
62
63 v1 = (pVertex + gRect->UpperLeft);
64 v2 = (pVertex + gRect->LowerRight);
65
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);
70 rcSG = rcGradient;
71 RECTL_vOffsetRect(&rcSG, pptlDitherOrg->x, pptlDitherOrg->y);
72
73 if(Horizontal)
74 {
75 dy = abs(rcGradient.right - rcGradient.left);
76 }
77 else
78 {
79 dy = abs(rcGradient.bottom - rcGradient.top);
80 }
81
82 if(!IntEngEnter(&EnterLeave, psoDest, &rcSG, FALSE, &Translate, &psoOutput))
83 {
84 return FALSE;
85 }
86
87 if((v1->Red != v2->Red || v1->Green != v2->Green || v1->Blue != v2->Blue) && dy > 1)
88 {
89 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
90 do
91 {
92 RECTL FillRect;
93 ULONG Color;
94
95 if(Horizontal)
96 {
97 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
98 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
99 {
100 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
101 {
102 HVINITCOL(Red, 0);
103 HVINITCOL(Green, 1);
104 HVINITCOL(Blue, 2);
105
106 for(y = rcSG.left; y < FillRect.right; y++)
107 {
108 if(y >= FillRect.left)
109 {
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);
113 }
114 HVSTEPCOL(0);
115 HVSTEPCOL(1);
116 HVSTEPCOL(2);
117 }
118 }
119 }
120
121 continue;
122 }
123
124 /* vertical */
125 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
126 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
127 {
128 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
129 {
130 HVINITCOL(Red, 0);
131 HVINITCOL(Green, 1);
132 HVINITCOL(Blue, 2);
133
134 for(y = rcSG.top; y < FillRect.bottom; y++)
135 {
136 if(y >= FillRect.top)
137 {
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);
141 }
142 HVSTEPCOL(0);
143 HVSTEPCOL(1);
144 HVSTEPCOL(2);
145 }
146 }
147 }
148
149 } while(EnumMore);
150
151 return IntEngLeave(&EnterLeave);
152 }
153
154 /* rectangle has only one color, no calculation required */
155 CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
156 do
157 {
158 RECTL FillRect;
159 ULONG Color = XLATEOBJ_iXlate(pxlo, RGB(v1->Red, v1->Green, v1->Blue));
160
161 EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
162 for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= rcSG.bottom; i++)
163 {
164 if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], &rcSG))
165 {
166 for(; FillRect.top < FillRect.bottom; FillRect.top++)
167 {
168 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_HLine(
169 psoOutput, FillRect.left + Translate.x, FillRect.right + Translate.x, FillRect.top + Translate.y, Color);
170 }
171 }
172 }
173 } while(EnumMore);
174
175 return IntEngLeave(&EnterLeave);
176 }
177
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); \
182 else \
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]) \
187 { \
188 x[line] += incx[line]; \
189 sx[line] += incx[line]; \
190 ex[line] -= dy[line]; \
191 }
192 #define S_GOLINE(a,b,line) \
193 if(y >= a->y && y <= b->y) \
194 {
195 #define S_ENDLINE(a,b,line) \
196 }
197 #define S_INITLINE(a,b,line) \
198 x[line] = a->x; \
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); \
204 destx[line] = b->x
205
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) \
215 { \
216 c[line][id] += ic[line][id]; \
217 ec[line][id] -= dy[line]; \
218 }
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) \
227 { \
228 gc[colid] += gi[colid]; \
229 ge[colid] -= gx; \
230 }
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) \
238 { \
239 if(InY && g >= FillRect.left && g < FillRect.right) \
240 { \
241 Color = XLATEOBJ_iXlate(pxlo, RGB(gc[0], gc[1], gc[2])); \
242 DibFunctionsForBitmapFormat[psoOutput->iBitmapFormat].DIB_PutPixel(psoOutput, g, sy, Color); \
243 } \
244 FDOCOL(linefrom, lineto, 0); \
245 FDOCOL(linefrom, lineto, 1); \
246 FDOCOL(linefrom, lineto, 2); \
247 }
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]) \
254 { \
255 x[line] += incx[line]; \
256 sx[line] += incx[line]; \
257 ex[line] -= dy[line]; \
258 }
259 #define GOLINE(a,b,line) \
260 if(y >= a->y && y <= b->y) \
261 {
262 #define ENDLINE(a,b,line) \
263 }
264 #define INITLINE(a,b,line) \
265 x[line] = a->x; \
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); \
271 destx[line] = b->x
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;\
279 a = b;\
280 b = c
281 #define NLINES 3
282 BOOL FASTCALL
283 IntEngGradientFillTriangle(
284 IN SURFOBJ *psoDest,
285 IN CLIPOBJ *pco,
286 IN XLATEOBJ *pxlo,
287 IN TRIVERTEX *pVertex,
288 IN ULONG nVertex,
289 IN PGRADIENT_TRIANGLE gTriangle,
290 IN RECTL *prclExtents,
291 IN POINTL *pptlDitherOrg)
292 {
293 SURFOBJ *psoOutput;
294 PTRIVERTEX v1, v2, v3;
295 //RECT_ENUM RectEnum;
296 //BOOL EnumMore;
297 //ULONG i;
298 POINTL Translate;
299 INTENG_ENTER_LEAVE EnterLeave;
300 RECTL FillRect = { 0, 0, 0, 0 };
301 //ULONG Color;
302
303 //BOOL sx[NLINES];
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 */
307 //LONG sy, y, bt;
308
309 v1 = (pVertex + gTriangle->Vertex1);
310 v2 = (pVertex + gTriangle->Vertex2);
311 v3 = (pVertex + gTriangle->Vertex3);
312
313 /* bubble sort */
314 if(SMALLER(v2,v1))
315 {
316 TRIVERTEX *t;
317 SWAP(v1,v2,t);
318 }
319 if(SMALLER(v3,v2))
320 {
321 TRIVERTEX *t;
322 SWAP(v2,v3,t);
323 if(SMALLER(v2,v1))
324 {
325 SWAP(v1,v2,t);
326 }
327 }
328
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");
332
333 if(!IntEngEnter(&EnterLeave, psoDest, &FillRect, FALSE, &Translate, &psoOutput))
334 {
335 return FALSE;
336 }
337
338 //if(VCMPCLRS(v1, v2, v3))
339 //{
340 // CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
341 // do
342 // {
343 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
344 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
345 // {
346 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
347 // {
348 // BOOL InY;
349
350 // DOINIT(v1, v3, 0);
351 // DOINIT(v1, v2, 1);
352 // DOINIT(v2, v3, 2);
353
354 // y = v1->y;
355 // sy = v1->y + pptlDitherOrg->y;
356 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
357
358 // while(sy < bt)
359 // {
360 // InY = !(sy < FillRect.top || sy >= FillRect.bottom);
361 // GOLINE(v1, v3, 0);
362 // DOLINE(v1, v3, 0);
363 // ENDLINE(v1, v3, 0);
364
365 // GOLINE(v1, v2, 1);
366 // DOLINE(v1, v2, 1);
367 // FILLLINE(0, 1);
368 // ENDLINE(v1, v2, 1);
369
370 // GOLINE(v2, v3, 2);
371 // DOLINE(v2, v3, 2);
372 // FILLLINE(0, 2);
373 // ENDLINE(23, v3, 2);
374
375 // y++;
376 // sy++;
377 // }
378 // }
379 // }
380 // } while(EnumMore);
381
382 // return IntEngLeave(&EnterLeave);
383 //}
384
385 ///* fill triangle with one solid color */
386
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);
389 //do
390 //{
391 // EnumMore = CLIPOBJ_bEnum(pco, (ULONG) sizeof(RectEnum), (PVOID) &RectEnum);
392 // for (i = 0; i < RectEnum.c && RectEnum.arcl[i].top <= prclExtents->bottom; i++)
393 // {
394 // if(RECTL_bIntersectRect(&FillRect, &RectEnum.arcl[i], prclExtents))
395 // {
396 // S_INITLINE(v1, v3, 0);
397 // S_INITLINE(v1, v2, 1);
398 // S_INITLINE(v2, v3, 2);
399
400 // y = v1->y;
401 // sy = v1->y + pptlDitherOrg->y;
402 // bt = min(v3->y + pptlDitherOrg->y, FillRect.bottom);
403
404 // while(sy < bt)
405 // {
406 // S_GOLINE(v1, v3, 0);
407 // S_DOLINE(v1, v3, 0);
408 // S_ENDLINE(v1, v3, 0);
409
410 // S_GOLINE(v1, v2, 1);
411 // S_DOLINE(v1, v2, 1);
412 // S_FILLLINE(0, 1);
413 // S_ENDLINE(v1, v2, 1);
414
415 // S_GOLINE(v2, v3, 2);
416 // S_DOLINE(v2, v3, 2);
417 // S_FILLLINE(0, 2);
418 // S_ENDLINE(23, v3, 2);
419
420 // y++;
421 // sy++;
422 // }
423 // }
424 // }
425 //} while(EnumMore);
426
427 return IntEngLeave(&EnterLeave);
428 }
429
430
431 static BOOL
432 IntEngIsNULLTriangle(TRIVERTEX *pVertex, GRADIENT_TRIANGLE *gt)
433 {
434 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex2)))
435 return TRUE;
436 if(COMPAREVERTEX(VERTEX(Vertex1), VERTEX(Vertex3)))
437 return TRUE;
438 if(COMPAREVERTEX(VERTEX(Vertex2), VERTEX(Vertex3)))
439 return TRUE;
440 return FALSE;
441 }
442
443
444 BOOL APIENTRY
445 EngGradientFill(
446 IN SURFOBJ *psoDest,
447 IN CLIPOBJ *pco,
448 IN XLATEOBJ *pxlo,
449 IN TRIVERTEX *pVertex,
450 IN ULONG nVertex,
451 IN PVOID pMesh,
452 IN ULONG nMesh,
453 IN RECTL *prclExtents,
454 IN POINTL *pptlDitherOrg,
455 IN ULONG ulMode)
456 {
457 ULONG i;
458 BOOL ret = FALSE;
459
460 if (!pco)
461 {
462 pco = IntEngCreateClipRegion(0, 0, prclExtents);
463 if (!pco)
464 {
465 return FALSE;
466 }
467 }
468
469 switch(ulMode)
470 {
471 case GRADIENT_FILL_RECT_H:
472 case GRADIENT_FILL_RECT_V:
473 {
474 PGRADIENT_RECT gr = (PGRADIENT_RECT)pMesh;
475 for(i = 0; i < nMesh; i++, gr++)
476 {
477 if(!IntEngGradientFillRect(psoDest, pco, pxlo, pVertex, nVertex, gr, prclExtents,
478 pptlDitherOrg, (ulMode == GRADIENT_FILL_RECT_H)))
479 {
480 break;
481 }
482 }
483 ret = TRUE;
484 break;
485 }
486 case GRADIENT_FILL_TRIANGLE:
487 {
488 PGRADIENT_TRIANGLE gt = (PGRADIENT_TRIANGLE)pMesh;
489 for(i = 0; i < nMesh; i++, gt++)
490 {
491 if(IntEngIsNULLTriangle(pVertex, gt))
492 {
493 /* skip empty triangles */
494 continue;
495 }
496 if(!IntEngGradientFillTriangle(psoDest, pco, pxlo, pVertex, nVertex, gt, prclExtents,
497 pptlDitherOrg))
498 {
499 break;
500 }
501 }
502 ret = TRUE;
503 break;
504 }
505 }
506
507 return ret;
508 }
509
510 BOOL APIENTRY
511 IntEngGradientFill(
512 IN SURFOBJ *psoDest,
513 IN CLIPOBJ *pco,
514 IN XLATEOBJ *pxlo,
515 IN TRIVERTEX *pVertex,
516 IN ULONG nVertex,
517 IN PVOID pMesh,
518 IN ULONG nMesh,
519 IN RECTL *prclExtents,
520 IN POINTL *pptlDitherOrg,
521 IN ULONG ulMode)
522 {
523 BOOL Ret;
524 SURFACE *psurf;
525 ASSERT(psoDest);
526
527 psurf = CONTAINING_RECORD(psoDest, SURFACE, SurfObj);
528 ASSERT(psurf);
529
530 if(psurf->flags & HOOK_GRADIENTFILL)
531 {
532 Ret = GDIDEVFUNCS(psoDest).GradientFill(
533 psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh,
534 prclExtents, pptlDitherOrg, ulMode);
535 }
536 else
537 {
538 Ret = EngGradientFill(psoDest, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents,
539 pptlDitherOrg, ulMode);
540 }
541
542 return Ret;
543 }