Don't call InvertPixelArray with negative width and/or height.
[tangerine.git] / workbench / libs / muimaster / imspec_gradient.c
blobcd66adfe51e7ff4539fd61a1ef3beba31e857ba2
1 /*
2 Copyright 2003, The AROS Development Team.
3 All rights reserved.
5 $Id$
6 */
8 #include <math.h>
9 #include <intuition/imageclass.h>
10 #include <cybergraphx/cybergraphics.h>
11 #include <proto/graphics.h>
12 #include <proto/cybergraphics.h>
14 #include <stdio.h>
15 #include <proto/dos.h>
16 #include <proto/exec.h>
17 #include <proto/utility.h>
19 #include "mui.h"
20 #include "imspec_intern.h"
21 #include "support.h"
22 #define MYDEBUG 1
23 #include "debug.h"
25 extern struct Library *MUIMasterBase;
28 sizeof(LONG)*8 gives the size in bits of the LONG type,
29 then 8+1 bits (a color component size in bits, plus one bit
30 to account for the sign of the delta) are subtracted from it,
31 the result is the number of bits which can be used for the fractional
32 part to do fixed point math with the maximum precision.
34 Using all the remaining bits for the fractional part, IN THIS SPECIAL CASE,
35 does not incurr in overflow problems for the integer part, for the way
36 we use fractional numbers in this algorithm. Basically, we first scale up
37 a number A, and then we divide A by the number B. Successively,
38 the only operation we do on the number A is adding it to the number C,
39 initially equal to 0, _at maximum_ B times, which means that overflow
40 never happens.
42 UPDATE: I've come up with a solution which makes this algorithm
43 twice as fast as before, by taking advantage of the fact that
44 a + b/c = (ac + b)/c, which means that now the number C is set
45 to an initial value different than 0. There's no need to diminish
46 the number of fractional bits as, for the way the algorithm
47 works, there's still no overflow.
51 #define SHIFT (sizeof(ULONG)*8 - (8 + 1))
53 STATIC VOID TrueDitherV
55 struct RastPort *rp,
56 WORD x1, WORD y1, WORD x2, WORD y2,
57 WORD oy1, WORD oy2,
58 ULONG *start_rgb, ULONG *end_rgb
61 LONG max_delta_y = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
62 LONG width = x2 - x1 + 1;
64 LONG delta_r = end_rgb[0] - start_rgb[0];
65 LONG delta_g = end_rgb[1] - start_rgb[1];
66 LONG delta_b = end_rgb[2] - start_rgb[2];
68 LONG step_r = (delta_r << SHIFT)/max_delta_y;
69 LONG step_g = (delta_g << SHIFT)/max_delta_y;
70 LONG step_b = (delta_b << SHIFT)/max_delta_y;
72 LONG y, offset_y = y1 - oy1;
74 LONG red = ((1 << SHIFT) >> 1) + (start_rgb[0] << SHIFT) + offset_y*step_r;
75 LONG green = ((1 << SHIFT) >> 1) + (start_rgb[1] << SHIFT) + offset_y*step_g;
76 LONG blue = ((1 << SHIFT) >> 1) + (start_rgb[2] << SHIFT) + offset_y*step_b;
78 for(y = y1; y <= y2; y++)
80 FillPixelArray(rp, x1, y, width, 1,
81 ((red >> SHIFT) << 16) + ((green >> SHIFT) << 8) + (blue >> SHIFT));
83 red += step_r;
84 green += step_g;
85 blue += step_b;
89 STATIC VOID TrueDitherH
91 struct RastPort *rp,
92 WORD x1, WORD y1, WORD x2, WORD y2,
93 WORD ox1, WORD ox2,
94 ULONG *start_rgb, ULONG *end_rgb
97 LONG max_delta_x = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
98 LONG height = y2 - y1 + 1;
100 LONG delta_r = end_rgb[0] - start_rgb[0];
101 LONG delta_g = end_rgb[1] - start_rgb[1];
102 LONG delta_b = end_rgb[2] - start_rgb[2];
104 LONG step_r = (delta_r << SHIFT)/max_delta_x;
105 LONG step_g = (delta_g << SHIFT)/max_delta_x;
106 LONG step_b = (delta_b << SHIFT)/max_delta_x;
108 LONG x, offset_x = x1 - ox1;
110 /* 1 << (SHIFT - 1) is 0.5 in fixed point math. We add it to the variable
111 so that, at the moment in which the variable is converted to integer,
112 rounding is done properly. That is, a+x, with 0 < x < 0.5, is rounded
113 down to a, and a+x, with 0.5 <= x < 1, is rounded up to a+1. */
115 LONG red = ((1 << SHIFT) >> 1) + (start_rgb[0] << SHIFT) + offset_x*step_r;
116 LONG green = ((1 << SHIFT) >> 1) + (start_rgb[1] << SHIFT) + offset_x*step_g;
117 LONG blue = ((1 << SHIFT) >> 1) + (start_rgb[2] << SHIFT) + offset_x*step_b;
119 for(x = x1; x <= x2; x++)
121 FillPixelArray(rp, x, y1, 1, height,
122 ((red >> SHIFT) << 16) + ((green >> SHIFT) << 8) + (blue >> SHIFT));
124 red += step_r;
125 green += step_g;
126 blue += step_b;
130 struct myrgb
132 int red,green,blue;
135 void FillPixelArrayGradientRelative(struct RastPort *rp, int xt, int yt, int xb, int yb, int xp, int yp, int w, int h, ULONG *start_rgb, ULONG *end_rgb, int angle, int xoff, int yoff)
137 /* The basic idea of this algorithm is to calc the intersection between the
138 * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line starting
139 * at (x,y) (every pixel inside the rectangle) and angle angle with direction vector (vx,vy).
141 * Having the intersection point we then know the color of the pixel.
143 * TODO: Turn the algorithm into a incremental one
144 * Remove the use of floating point variables
146 double rad = angle*M_PI/180;
147 double cosarc = cos(rad);
148 double sinarc = sin(rad);
150 struct myrgb startRGB,endRGB;
151 struct NewImage *ni = NULL;
153 int diffR, diffG, diffB;
155 int r,t; /* some helper variables to short the code */
156 int l,y,c,x;
157 int y1; /* The intersection point */
158 int incr_y1; /* increment of y1 */
159 int xs,ys,xw,yw;
160 int xadd,ystart,yadd;
161 // double vx = -cosarc;
162 // double vy = sinarc;
163 int vx = (int)(-cosarc*0xff);
164 int vy = (int)(sinarc*0xff);
166 int width = xb - xt + 1;
167 int height = yb - yt + 1;
169 if ((w <= 0) || (h <= 0)) return;
170 UBYTE *buf = AllocVec(w*h*3, 0);
171 if (buf == NULL) return;
173 startRGB.red = start_rgb[0];
174 startRGB.green = start_rgb[1];
175 startRGB.blue = start_rgb[2];
177 endRGB.red = end_rgb[0];
178 endRGB.green = end_rgb[1];
179 endRGB.blue = end_rgb[2];
181 diffR = endRGB.red - startRGB.red;
182 diffG = endRGB.green - startRGB.green;
183 diffB = endRGB.blue - startRGB.blue;
185 /* Normalize the angle */
186 if (angle < 0) angle = 360 - ((-angle)%360);
187 if (angle >= 0) angle = angle % 360;
189 if (angle <= 90 || (angle > 180 && angle <= 270))
191 /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
192 xs = 0;
193 ys = 0;
194 xw = width;
195 yw = height;
196 } else
198 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
199 xs = 0;
200 ys = height;
201 xw = width;
202 yw = -height;
205 if (angle > 90 && angle <= 270)
207 /* for these angle we have y1 = height - y1. Instead of
209 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
211 * we can write
213 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
215 * so height - y1 can be expressed with the normal formular adapting some parameters.
217 * Note that if one would exchanging startRGB/endRGB the values would only work
218 * for linear color gradients
220 xadd = -1;
221 yadd = -1;
222 ystart = height;
224 xs = -xs;
225 ys = -ys + height;
226 } else
228 xadd = 1;
229 yadd = 1;
230 ystart = 0;
233 r = -vy*(yw*xs-xw*ys);
234 t = -yw*vx + xw*vy;
236 /* The formular as shown above is
238 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
240 * We see that only yw*(vy*x-vx*y) changes during the loop.
242 * We write
244 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
245 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
247 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
251 incr_y1 = yw*vy*xadd;
252 UBYTE *bufptr = buf;
253 for (l = 0, y = ystart + ((yp - yt)* yadd); l < h; l++, y+=yadd)
256 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
257 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
258 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
259 * vx nothing is left, currently 9 bits are used for vx or vy */
260 int y1_mul_t_accu = r - yw*vx*y;
263 y1_mul_t_accu += (incr_y1 * (xp - xt));
265 for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x+=xadd)
267 int red,green,blue;
269 /* Calculate the intersection of two lines, this is not the fastet way to do but
270 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
271 * and making it incremental)...update: it's now incremental and no FFP is used
272 * but it probably can be optimized more by removing some more of the divisions and
273 * further specialize the stuff here (use of three accus). */
274 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
275 y1 = y1_mul_t_accu / t;
277 red = startRGB.red + (int)(diffR*y1/height);
278 green = startRGB.green + (int)(diffG*y1/height);
279 blue = startRGB.blue + (int)(diffB*y1/height);
280 /* By using full 32 bits this can be made faster as well */
281 *bufptr++ = red;
282 *bufptr++ = green;
283 *bufptr++ = blue;
285 y1_mul_t_accu += incr_y1;
287 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
288 * to WritePixelArray() can be made also faster */
290 WritePixelArray(buf,0,0,w*3, rp,0,0,w,h,RECTFMT_RGB);
291 FreeVec(buf);
295 /*****************************************************************
296 Fill the given rectangle with a angle oriented gradient. The
297 unit angle uses are degrees
298 ******************************************************************/
299 STATIC int FillPixelArrayGradient(struct RastPort *rp, int xt, int yt, int xb, int yb, ULONG *start_rgb, ULONG *end_rgb, int angle)
301 /* The basic idea of this algorithm is to calc the intersection between the
302 * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line starting
303 * at (x,y) (every pixel inside the rectangle) and angle angle with direction vector (vx,vy).
305 * Having the intersection point we then know the color of the pixel.
307 * TODO: Turn the algorithm into a incremental one
308 * Remove the use of floating point variables
311 double rad = angle*M_PI/180;
312 double cosarc = cos(rad);
313 double sinarc = sin(rad);
315 struct myrgb startRGB,endRGB;
316 int diffR, diffG, diffB;
318 int r,t; /* some helper variables to short the code */
319 int l,y,c,x;
320 int y1; /* The intersection point */
321 int incr_y1; /* increment of y1 */
322 int xs,ys,xw,yw;
323 int xadd,ystart,yadd;
324 // double vx = -cosarc;
325 // double vy = sinarc;
326 int vx = (int)(-cosarc*0xff);
327 int vy = (int)(sinarc*0xff);
329 int width = xb - xt + 1;
330 int height = yb - yt + 1;
332 UBYTE *buf = (UBYTE*)AllocVec(width*3,0);
333 if (!buf) return 0;
335 startRGB.red = start_rgb[0];
336 startRGB.green = start_rgb[1];
337 startRGB.blue = start_rgb[2];
339 endRGB.red = end_rgb[0];
340 endRGB.green = end_rgb[1];
341 endRGB.blue = end_rgb[2];
343 diffR = endRGB.red - startRGB.red;
344 diffG = endRGB.green - startRGB.green;
345 diffB = endRGB.blue - startRGB.blue;
347 /* Normalize the angle */
348 if (angle < 0) angle = 360 - ((-angle)%360);
349 if (angle >= 0) angle = angle % 360;
351 if (angle <= 90 || (angle > 180 && angle <= 270))
353 /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
354 xs = 0;
355 ys = 0;
356 xw = width;
357 yw = height;
358 } else
360 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
361 xs = 0;
362 ys = height;
363 xw = width;
364 yw = -height;
367 if (angle > 90 && angle <= 270)
369 /* for these angle we have y1 = height - y1. Instead of
371 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
373 * we can write
375 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
377 * so height - y1 can be expressed with the normal formular adapting some parameters.
379 * Note that if one would exchanging startRGB/endRGB the values would only work
380 * for linear color gradients
382 xadd = -1;
383 yadd = -1;
384 ystart = height;
386 xs = -xs;
387 ys = -ys + height;
388 } else
390 xadd = 1;
391 yadd = 1;
392 ystart = 0;
395 r = -vy*(yw*xs-xw*ys);
396 t = -yw*vx + xw*vy;
398 /* The formular as shown above is
400 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
402 * We see that only yw*(vy*x-vx*y) changes during the loop.
404 * We write
406 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
407 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
409 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
413 incr_y1 = yw*vy*xadd;
415 for (l = 0, y = ystart; l < height; l++, y+=yadd)
417 UBYTE *bufptr = buf;
419 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
420 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
421 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
422 * vx nothing is left, currently 9 bits are used for vx or vy */
423 int y1_mul_t_accu = r - yw*vx*y;
425 for (c = 0, x = 0; c < width; c++, x+=xadd)
427 int red,green,blue;
429 /* Calculate the intersection of two lines, this is not the fastet way to do but
430 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
431 * and making it incremental)...update: it's now incremental and no FFP is used
432 * but it probably can be optimized more by removing some more of the divisions and
433 * further specialize the stuff here (use of three accus). */
434 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
435 y1 = y1_mul_t_accu / t;
437 red = startRGB.red + (int)(diffR*y1/height);
438 green = startRGB.green + (int)(diffG*y1/height);
439 blue = startRGB.blue + (int)(diffB*y1/height);
441 /* By using full 32 bits this can be made faster as well */
442 *bufptr++ = red;
443 *bufptr++ = green;
444 *bufptr++ = blue;
446 y1_mul_t_accu += incr_y1;
448 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
449 * to WritePixelArray() can be made also faster */
450 WritePixelArray(buf,0,0,width*3 /* srcMod */,
451 rp,xt,yt+l,width,1,RECTFMT_RGB);
453 FreeVec(buf);
454 return 1;
457 /***************************************************************************************************/
459 VOID zune_gradient_drawfast
461 struct MUI_ImageSpec_intern *spec,
462 struct RastPort *rp,
463 struct MUI_RenderInfo *mri,
464 WORD mode, WORD abs_l, WORD abs_t, WORD abs_r, WORD abs_b,
465 WORD x1, WORD y1, WORD x2, WORD y2,
466 WORD xoff, WORD yoff
469 ULONG *start_rgb = spec->u.gradient.start_rgb;
470 ULONG *end_rgb = spec->u.gradient.end_rgb;
472 if (!(CyberGfxBase && (mri->mri_Flags & MUIMRI_TRUECOLOR) && spec->u.gradient.obj))
474 SetAPen(rp, spec->u.gradient.start_pen);
475 RectFill(rp, x1, y1, x2, y2);
476 return;
478 if (mode == 1) return FillPixelArrayGradientRelative(rp, abs_l, abs_t, abs_r, abs_b, x1, y1, x2-x1+1, y2-y1+1, start_rgb, end_rgb, spec->u.gradient.angle, xoff, yoff);
480 switch(spec->u.gradient.angle)
482 case 0:
484 LONG oy1 = _top(spec->u.gradient.obj), oy2 = _bottom(spec->u.gradient.obj);
485 LONG delta_oy = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
486 LONG hh = (delta_oy + 1)*2;
487 LONG mid_y;
489 yoff %= hh;
491 if (yoff < 0)
492 yoff += hh;
494 oy1 -= yoff; oy2 -= yoff;
496 if (y2 > oy2)
498 mid_y = y1 + delta_oy - yoff;
500 if (yoff > delta_oy)
502 ULONG *tmp = start_rgb;
503 start_rgb = end_rgb;
504 end_rgb = tmp;
506 mid_y += delta_oy;
507 oy1 += delta_oy;
508 oy2 += delta_oy;
511 else
513 mid_y = y2;
516 TrueDitherV
519 x1, y1, x2, mid_y,
520 oy1, oy2,
521 start_rgb, end_rgb
524 if (mid_y < y2)
526 TrueDitherV
529 x1, mid_y+1, x2, y2,
530 oy1+delta_oy, oy2+delta_oy,
531 end_rgb, start_rgb
535 break;
537 case 90:
539 LONG ox1 = _left(spec->u.gradient.obj), ox2 = _right(spec->u.gradient.obj);
540 LONG delta_ox = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
541 LONG ww = (delta_ox + 1)*2;
542 LONG mid_x;
545 xoff %= ww;
546 if (xoff < 0)
547 xoff += ww;
549 ox1 -= xoff; ox2 -= xoff;
551 if (x2 > ox2)
553 mid_x = x1 + delta_ox - xoff;
555 if (xoff > delta_ox)
557 ULONG *tmp = start_rgb;
558 start_rgb = end_rgb;
559 end_rgb = tmp;
561 mid_x += delta_ox;
562 ox1 += delta_ox;
563 ox2 += delta_ox;
566 else
568 mid_x = x2;
571 TrueDitherH
574 x1, y1, mid_x, y2,
575 ox1, ox2,
576 start_rgb, end_rgb
579 if (mid_x < x2)
581 TrueDitherH
584 mid_x+1, y1, x2, y2,
585 ox1+delta_ox, ox2+delta_ox,
586 end_rgb, start_rgb
590 break;
592 default:
593 FillPixelArrayGradient(rp, x1, y1, x2, y2, start_rgb, end_rgb, spec->u.gradient.angle);
594 break;
595 } /* switch(angle) */
597 VOID zune_gradient_draw
599 struct MUI_ImageSpec_intern *spec,
600 struct MUI_RenderInfo *mri,
601 WORD x1, WORD y1, WORD x2, WORD y2,
602 WORD xoff, WORD yoff
605 zune_gradient_drawfast
607 spec,
608 mri->mri_RastPort,
609 mri, 0,
610 x1, y1, x2, y2,
611 x1, y1, x2, y2,
612 xoff, yoff
615 /*************************************************************************
616 Converts a gradient string to a internal image spec
618 The format of the string is:
619 (h|H|v|V|<angle>),<start_r>,<start_g>,<start_b>-<end_r>,<end_g>,<end_b>
620 where <angle> is given decimal. The rest represents hexadecimal 32 bit
621 numbers.
622 **************************************************************************/
623 BOOL zune_gradient_string_to_intern(CONST_STRPTR str,
624 struct MUI_ImageSpec_intern *spec)
626 LONG converted;
627 ULONG angle;
628 ULONG start_r, start_g, start_b;
629 ULONG end_r, end_g, end_b;
631 if (!str || !spec) return FALSE;
633 /* Find out about the gradient angle */
634 switch (str[0])
636 case 'H':
637 case 'h':
638 angle = 90;
639 converted = 1;
640 break;
642 case 'V':
643 case 'v':
644 angle = 0;
645 converted = 1;
646 break;
648 default:
649 converted = StrToLong((STRPTR)str,(LONG*)&angle);
650 if (converted == -1) return FALSE;
651 break;
654 str += converted;
656 /* convert the color information */
657 if (*str != ',') return FALSE;
658 str++;
659 converted = HexToLong((STRPTR)str,&start_r);
660 if (converted == -1) return FALSE;
661 str += converted;
663 if (*str != ',') return FALSE;
664 str++;
665 converted = HexToLong((STRPTR)str,&start_g);
666 if (converted == -1) return FALSE;
667 str += converted;
669 if (*str != ',') return FALSE;
670 str++;
671 converted = HexToLong((STRPTR)str,&start_b);
672 if (converted == -1) return FALSE;
673 str += converted;
675 if (*str != '-') return FALSE;
676 str++;
677 converted = HexToLong((STRPTR)str,&end_r);
678 if (converted == -1) return FALSE;
679 str += converted;
681 if (*str != ',') return FALSE;
682 str++;
683 converted = HexToLong((STRPTR)str,&end_g);
684 if (converted == -1) return FALSE;
685 str += converted;
687 if (*str != ',') return FALSE;
688 str++;
689 converted = HexToLong((STRPTR)str,&end_b);
690 if (converted == -1) return FALSE;
692 /* Fill in the spec */
693 spec->u.gradient.angle = angle;
695 spec->u.gradient.start_rgb[0] = start_r>>24;
696 spec->u.gradient.start_rgb[1] = start_g>>24;
697 spec->u.gradient.start_rgb[2] = start_b>>24;
699 spec->u.gradient.end_rgb[0] = end_r>>24;
700 spec->u.gradient.end_rgb[1] = end_g>>24;
701 spec->u.gradient.end_rgb[2] = end_b>>24;
703 return TRUE;
706 VOID zune_scaled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
707 STRPTR buf)
709 sprintf(buf, "7:%ld,%08lx,%08lx,%08lx-%08lx,%08lx,%08lx",
710 (LONG)spec->u.gradient.angle,
711 spec->u.gradient.start_rgb[0]*0x01010101,
712 spec->u.gradient.start_rgb[1]*0x01010101,
713 spec->u.gradient.start_rgb[2]*0x01010101,
714 spec->u.gradient.end_rgb[0]*0x01010101,
715 spec->u.gradient.end_rgb[1]*0x01010101,
716 spec->u.gradient.end_rgb[2]*0x01010101);
719 VOID zune_tiled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
720 STRPTR buf)
722 sprintf(buf, "8:%ld,%08lx,%08lx,%08lx-%08lx,%08lx,%08lx",
723 spec->u.gradient.angle,
724 spec->u.gradient.start_rgb[0]*0x01010101,
725 spec->u.gradient.start_rgb[1]*0x01010101,
726 spec->u.gradient.start_rgb[2]*0x01010101,
727 spec->u.gradient.end_rgb[0]*0x01010101,
728 spec->u.gradient.end_rgb[1]*0x01010101,
729 spec->u.gradient.end_rgb[2]*0x01010101);
732 BOOL zune_gradientspec_setup(struct MUI_ImageSpec_intern *spec, struct MUI_RenderInfo *mri)
734 spec->u.gradient.mri = mri;
736 if (!(mri->mri_Flags & MUIMRI_TRUECOLOR))
738 ULONG *rgbptr = spec->u.gradient.start_rgb;
739 ULONG *penptr = &spec->u.gradient.start_pen;
740 BOOL *flagptr = &spec->u.gradient.start_pen_is_allocated;
741 LONG pen, i;
743 struct TagItem obp_tags[] =
745 { OBP_FailIfBad, FALSE },
746 { TAG_DONE }
749 for(i = 0; i < 2; i++)
751 ULONG r = rgbptr[0] * 0x01010101;
752 ULONG g = rgbptr[1] * 0x01010101;
753 ULONG b = rgbptr[2] * 0x01010101;
755 pen = ObtainBestPenA(mri->mri_Colormap, r, g, b, obp_tags);
757 if (pen == -1)
759 *flagptr = FALSE;
760 *penptr = FindColor(mri->mri_Colormap, r, g, b, -1);
762 else
764 *flagptr = TRUE;
765 *penptr = pen;
768 rgbptr = spec->u.gradient.end_rgb;
769 penptr = &spec->u.gradient.end_pen;
770 flagptr = &spec->u.gradient.end_pen_is_allocated;
774 else
776 spec->u.gradient.start_pen_is_allocated = FALSE;
777 spec->u.gradient.end_pen_is_allocated = FALSE;
780 return TRUE;
783 void zune_gradientspec_cleanup(struct MUI_ImageSpec_intern *spec)
785 if (spec->u.gradient.start_pen_is_allocated)
787 ReleasePen(spec->u.gradient.mri->mri_Colormap, spec->u.gradient.start_pen);
788 spec->u.gradient.start_pen_is_allocated = FALSE;
791 if (spec->u.gradient.end_pen_is_allocated)
793 ReleasePen(spec->u.gradient.mri->mri_Colormap, spec->u.gradient.end_pen);
794 spec->u.gradient.end_pen_is_allocated = FALSE;
797 spec->u.gradient.mri = NULL;