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