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