Tabs to spaces, more consistent formatting.
[AROS.git] / workbench / libs / muimaster / imspec_gradient.c
blob71939dcda0e896b8cd0579b8d468674614a2d3b7
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
54 (struct RastPort *rp,
55 WORD x1, WORD y1, WORD x2, WORD y2,
56 WORD oy1, WORD oy2, ULONG * start_rgb, ULONG * end_rgb)
58 LONG max_delta_y = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
59 LONG width = x2 - x1 + 1;
61 LONG delta_r = end_rgb[0] - start_rgb[0];
62 LONG delta_g = end_rgb[1] - start_rgb[1];
63 LONG delta_b = end_rgb[2] - start_rgb[2];
65 LONG step_r = (delta_r << SHIFT) / max_delta_y;
66 LONG step_g = (delta_g << SHIFT) / max_delta_y;
67 LONG step_b = (delta_b << SHIFT) / max_delta_y;
69 LONG y, offset_y = y1 - oy1;
71 LONG red =
72 ((1 << SHIFT) >> 1) + (start_rgb[0] << SHIFT) + offset_y * step_r;
73 LONG green =
74 ((1 << SHIFT) >> 1) + (start_rgb[1] << SHIFT) + offset_y * step_g;
75 LONG blue =
76 ((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) +
82 (blue >> SHIFT));
84 red += step_r;
85 green += step_g;
86 blue += step_b;
90 STATIC VOID TrueDitherH
91 (struct RastPort *rp,
92 WORD x1, WORD y1, WORD x2, WORD y2,
93 WORD ox1, WORD ox2, ULONG *start_rgb, ULONG *end_rgb)
95 LONG max_delta_x = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
96 LONG height = y2 - y1 + 1;
98 LONG delta_r = end_rgb[0] - start_rgb[0];
99 LONG delta_g = end_rgb[1] - start_rgb[1];
100 LONG delta_b = end_rgb[2] - start_rgb[2];
102 LONG step_r = (delta_r << SHIFT) / max_delta_x;
103 LONG step_g = (delta_g << SHIFT) / max_delta_x;
104 LONG step_b = (delta_b << SHIFT) / max_delta_x;
106 LONG x, offset_x = x1 - ox1;
108 /* 1 << (SHIFT - 1) is 0.5 in fixed point math. We add it to the variable
109 so that, at the moment in which the variable is converted to integer,
110 rounding is done properly. That is, a+x, with 0 < x < 0.5, is rounded
111 down to a, and a+x, with 0.5 <= x < 1, is rounded up to a+1. */
113 LONG red =
114 ((1 << SHIFT) >> 1) + (start_rgb[0] << SHIFT) + offset_x * step_r;
115 LONG green =
116 ((1 << SHIFT) >> 1) + (start_rgb[1] << SHIFT) + offset_x * step_g;
117 LONG blue =
118 ((1 << SHIFT) >> 1) + (start_rgb[2] << SHIFT) + offset_x * step_b;
120 for (x = x1; x <= x2; x++)
122 FillPixelArray(rp, x, y1, 1, height,
123 ((red >> SHIFT) << 16) + ((green >> SHIFT) << 8) +
124 (blue >> SHIFT));
126 red += step_r;
127 green += step_g;
128 blue += step_b;
132 struct myrgb
134 int red, green, blue;
137 void FillPixelArrayGradientRelative(struct RastPort *rp, int xt, int yt,
138 int xb, int yb, int xp, int yp, int w, int h, ULONG *start_rgb,
139 ULONG *end_rgb, int angle, int xoff, int yoff)
141 /* The basic idea of this algorithm is to calc the intersection between
142 * the diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with
143 * the line starting at (x,y) (every pixel inside the rectangle) and
144 * angle angle with direction vector (vx,vy).
146 * Having the intersection point we then know the color of the pixel.
148 * TODO: Turn the algorithm into a incremental one
149 * Remove the use of floating point variables
151 double rad = angle * M_PI / 180;
152 double cosarc = cos(rad);
153 double sinarc = sin(rad);
155 struct myrgb startRGB, endRGB;
157 int diffR, diffG, diffB;
159 int r, t; /* some helper variables to shorten the code */
160 int l, y, c, x;
161 int y1; /* The intersection point */
162 int incr_y1; /* increment of y1 */
163 int xs, ys, xw, yw;
164 int xadd, ystart, yadd;
165 // double vx = -cosarc;
166 // double vy = sinarc;
167 int vx = (int)(-cosarc * 0xff);
168 int vy = (int)(sinarc * 0xff);
170 int width = xb - xt + 1;
171 int height = yb - yt + 1;
173 if ((w <= 0) || (h <= 0))
174 return;
175 UBYTE *buf = AllocVec(w * h * 3, 0);
176 if (buf == NULL)
177 return;
179 startRGB.red = start_rgb[0];
180 startRGB.green = start_rgb[1];
181 startRGB.blue = start_rgb[2];
183 endRGB.red = end_rgb[0];
184 endRGB.green = end_rgb[1];
185 endRGB.blue = end_rgb[2];
187 diffR = endRGB.red - startRGB.red;
188 diffG = endRGB.green - startRGB.green;
189 diffB = endRGB.blue - startRGB.blue;
191 /* Normalize the angle */
192 if (angle < 0)
193 angle = 360 - ((-angle) % 360);
194 if (angle >= 0)
195 angle = angle % 360;
197 if (angle <= 90 || (angle > 180 && angle <= 270))
199 /* The to be intersected diagonal goes from the top left edge to the
200 bottom right edge */
201 xs = 0;
202 ys = 0;
203 xw = width;
204 yw = height;
206 else
208 /* The to be intersected diagonal goes from the bottom left edge to
209 the top right edge */
210 xs = 0;
211 ys = height;
212 xw = width;
213 yw = -height;
216 if (angle > 90 && angle <= 270)
218 /* for these angle we have y1 = height - y1. Instead of
220 * y1 = height - (-vy*(yw* xs -xw* ys)
221 * + yw*(vy* x -vx* y)) / (-yw*vx + xw*vy);
223 * we can write
225 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height))
226 * + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
228 * so height - y1 can be expressed with the normal formula adapting
229 * some parameters.
231 * Note that if one would exchanging startRGB/endRGB the values would
232 * only work for linear color gradients
234 xadd = -1;
235 yadd = -1;
236 ystart = height;
238 xs = -xs;
239 ys = -ys + height;
241 else
243 xadd = 1;
244 yadd = 1;
245 ystart = 0;
248 r = -vy * (yw * xs - xw * ys);
249 t = -yw * vx + xw * vy;
251 /* The formula as shown above is
253 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
255 * We see that only yw*(vy*x-vx*y) changes during the loop.
257 * We write
259 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
260 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
262 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y)
263 * = yw*vy*xadd;
267 incr_y1 = yw * vy * xadd;
268 UBYTE *bufptr = buf;
269 for (l = 0, y = ystart + ((yp - yt) * yadd); l < h; l++, y += yadd)
272 /* Calculate initial y1 accu, can be brought out of the loop as
273 * well (x=0). It's probably a good idea to add here also a value of
274 * (t-1)/2 to ensure the correct rounding.
275 * This (and for r) is also a place were actually a overflow can
276 * happen |yw|=16 |y|=16. So for vx nothing is left, currently 9 bits
277 * are used for vx or vy */
278 int y1_mul_t_accu = r - yw * vx * y;
280 y1_mul_t_accu += (incr_y1 * (xp - xt));
282 for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x += xadd)
284 int red, green, blue;
286 /* Calculate the intersection of two lines, this is not the
287 * fastest way to do but it is intuitive. Note: very slow! Will
288 * be optimzed later (remove FFP usage and making it incremental)
289 * ...update: it's now incremental and no FFP is used but it
290 * probably can be optimized more by removing some more of the
291 * divisions and further specialize the stuff here (use of three
292 * accus). */
293 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy)); */
294 y1 = y1_mul_t_accu / t;
296 red = startRGB.red + (int)(diffR * y1 / height);
297 green = startRGB.green + (int)(diffG * y1 / height);
298 blue = startRGB.blue + (int)(diffB * y1 / height);
299 /* By using full 32 bits this can be made faster as well */
300 *bufptr++ = red;
301 *bufptr++ = green;
302 *bufptr++ = blue;
304 y1_mul_t_accu += incr_y1;
306 /* By bringing building the gradient array in the same format as the
307 * RastPort BitMap a call to WritePixelArray() can be made also
308 * faster */
310 WritePixelArray(buf, 0, 0, w * 3, rp, 0, 0, w, h, RECTFMT_RGB);
311 FreeVec(buf);
315 /*****************************************************************
316 Fill the given rectangle with a angle oriented gradient. The
317 unit angle uses are degrees
318 ******************************************************************/
319 STATIC int FillPixelArrayGradient(struct RastPort *rp, int xt, int yt,
320 int xb, int yb, ULONG *start_rgb, ULONG *end_rgb, int angle)
322 /* The basic idea of this algorithm is to calc the intersection between the
323 * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line
324 * starting at (x,y) (every pixel inside the rectangle) and angle angle
325 * with direction vector (vx,vy).
327 * Having the intersection point we then know the color of the pixel.
329 * TODO: Turn the algorithm into a incremental one
330 * Remove the use of floating point variables
333 double rad = angle * M_PI / 180;
334 double cosarc = cos(rad);
335 double sinarc = sin(rad);
337 struct myrgb startRGB, endRGB;
338 int diffR, diffG, diffB;
340 int r, t; /* some helper variables to shorten the code */
341 int l, y, c, x;
342 int y1; /* The intersection point */
343 int incr_y1; /* increment of y1 */
344 int xs, ys, xw, yw;
345 int xadd, ystart, yadd;
346 // double vx = -cosarc;
347 // double vy = sinarc;
348 int vx = (int)(-cosarc * 0xff);
349 int vy = (int)(sinarc * 0xff);
351 int width = xb - xt + 1;
352 int height = yb - yt + 1;
354 UBYTE *buf = (UBYTE *) AllocVec(width * 3, 0);
355 if (!buf)
356 return 0;
358 startRGB.red = start_rgb[0];
359 startRGB.green = start_rgb[1];
360 startRGB.blue = start_rgb[2];
362 endRGB.red = end_rgb[0];
363 endRGB.green = end_rgb[1];
364 endRGB.blue = end_rgb[2];
366 diffR = endRGB.red - startRGB.red;
367 diffG = endRGB.green - startRGB.green;
368 diffB = endRGB.blue - startRGB.blue;
370 /* Normalize the angle */
371 if (angle < 0)
372 angle = 360 - ((-angle) % 360);
373 if (angle >= 0)
374 angle = angle % 360;
376 if (angle <= 90 || (angle > 180 && angle <= 270))
378 /* The to be intersected diagonal goes from the top left edge to the
379 bottom right edge */
380 xs = 0;
381 ys = 0;
382 xw = width;
383 yw = height;
385 else
387 /* The to be intersected diagonal goes from the bottom left edge to
388 the top right edge */
389 xs = 0;
390 ys = height;
391 xw = width;
392 yw = -height;
395 if (angle > 90 && angle <= 270)
397 /* for these angle we have y1 = height - y1. Instead of
399 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
401 * we can write
403 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
405 * so height - y1 can be expressed with the normal formular adapting some parameters.
407 * Note that if one would exchanging startRGB/endRGB the values would only work
408 * for linear color gradients
410 xadd = -1;
411 yadd = -1;
412 ystart = height;
414 xs = -xs;
415 ys = -ys + height;
417 else
419 xadd = 1;
420 yadd = 1;
421 ystart = 0;
424 r = -vy * (yw * xs - xw * ys);
425 t = -yw * vx + xw * vy;
427 /* The formular as shown above is
429 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
431 * We see that only yw*(vy*x-vx*y) changes during the loop.
433 * We write
435 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
436 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
438 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
442 incr_y1 = yw * vy * xadd;
444 for (l = 0, y = ystart; l < height; l++, y += yadd)
446 UBYTE *bufptr = buf;
448 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
449 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
450 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
451 * vx nothing is left, currently 9 bits are used for vx or vy */
452 int y1_mul_t_accu = r - yw * vx * y;
454 for (c = 0, x = 0; c < width; c++, x += xadd)
456 int red, green, blue;
458 /* Calculate the intersection of two lines, this is not the fastet way to do but
459 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
460 * and making it incremental)...update: it's now incremental and no FFP is used
461 * but it probably can be optimized more by removing some more of the divisions and
462 * further specialize the stuff here (use of three accus). */
463 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
464 y1 = y1_mul_t_accu / t;
466 red = startRGB.red + (int)(diffR * y1 / height);
467 green = startRGB.green + (int)(diffG * y1 / height);
468 blue = startRGB.blue + (int)(diffB * y1 / height);
470 /* By using full 32 bits this can be made faster as well */
471 *bufptr++ = red;
472 *bufptr++ = green;
473 *bufptr++ = blue;
475 y1_mul_t_accu += incr_y1;
477 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
478 * to WritePixelArray() can be made also faster */
479 WritePixelArray(buf, 0, 0, width * 3 /* srcMod */ ,
480 rp, xt, yt + l, width, 1, RECTFMT_RGB);
482 FreeVec(buf);
483 return 1;
486 /***************************************************************************************************/
488 VOID zune_gradient_drawfast(struct MUI_ImageSpec_intern *spec,
489 struct RastPort *rp, struct MUI_RenderInfo *mri, WORD mode, WORD abs_l,
490 WORD abs_t, WORD abs_r, WORD abs_b, WORD x1, WORD y1, WORD x2, WORD y2,
491 WORD xoff, WORD yoff)
493 ULONG *start_rgb = spec->u.gradient.start_rgb;
494 ULONG *end_rgb = spec->u.gradient.end_rgb;
496 if (!(CyberGfxBase && (mri->mri_Flags & MUIMRI_TRUECOLOR)
497 && spec->u.gradient.obj))
499 SetAPen(rp, spec->u.gradient.start_pen);
500 RectFill(rp, x1, y1, x2, y2);
501 return;
503 if (mode == 1)
504 return FillPixelArrayGradientRelative(rp, abs_l, abs_t, abs_r,
505 abs_b, x1, y1, x2 - x1 + 1, y2 - y1 + 1, start_rgb, end_rgb,
506 spec->u.gradient.angle, xoff, yoff);
508 switch (spec->u.gradient.angle)
510 case 0:
512 LONG oy1 = _top(spec->u.gradient.obj), oy2 =
513 _bottom(spec->u.gradient.obj);
514 LONG delta_oy = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
515 LONG hh = (delta_oy + 1) * 2;
516 LONG mid_y;
518 yoff %= hh;
520 if (yoff < 0)
521 yoff += hh;
523 oy1 -= yoff;
524 oy2 -= yoff;
526 if (y2 > oy2)
528 mid_y = y1 + delta_oy - yoff;
530 if (yoff > delta_oy)
532 ULONG *tmp = start_rgb;
533 start_rgb = end_rgb;
534 end_rgb = tmp;
536 mid_y += delta_oy;
537 oy1 += delta_oy;
538 oy2 += delta_oy;
541 else
543 mid_y = y2;
546 TrueDitherV
547 (rp, x1, y1, x2, mid_y, oy1, oy2, start_rgb, end_rgb);
549 if (mid_y < y2)
551 TrueDitherV
552 (rp,
553 x1, mid_y + 1, x2, y2,
554 oy1 + delta_oy, oy2 + delta_oy, end_rgb, start_rgb);
557 break;
559 case 90:
561 LONG ox1 = _left(spec->u.gradient.obj), ox2 =
562 _right(spec->u.gradient.obj);
563 LONG delta_ox = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
564 LONG ww = (delta_ox + 1) * 2;
565 LONG mid_x;
568 xoff %= ww;
569 if (xoff < 0)
570 xoff += ww;
572 ox1 -= xoff;
573 ox2 -= xoff;
575 if (x2 > ox2)
577 mid_x = x1 + delta_ox - xoff;
579 if (xoff > delta_ox)
581 ULONG *tmp = start_rgb;
582 start_rgb = end_rgb;
583 end_rgb = tmp;
585 mid_x += delta_ox;
586 ox1 += delta_ox;
587 ox2 += delta_ox;
590 else
592 mid_x = x2;
595 TrueDitherH
596 (rp, x1, y1, mid_x, y2, ox1, ox2, start_rgb, end_rgb);
598 if (mid_x < x2)
600 TrueDitherH
601 (rp,
602 mid_x + 1, y1, x2, y2,
603 ox1 + delta_ox, ox2 + delta_ox, end_rgb, start_rgb);
606 break;
608 default:
609 FillPixelArrayGradient(rp, x1, y1, x2, y2, start_rgb, end_rgb,
610 spec->u.gradient.angle);
611 break;
612 } /* switch(angle) */
614 VOID zune_gradient_draw(struct MUI_ImageSpec_intern *spec,
615 struct MUI_RenderInfo *mri, WORD x1, WORD y1, WORD x2, WORD y2,
616 WORD xoff, WORD yoff)
618 zune_gradient_drawfast(spec, mri->mri_RastPort,
619 mri, 0, x1, y1, x2, y2, x1, y1, x2, y2, xoff, yoff);
621 /*************************************************************************
622 Converts a gradient string to a internal image spec
624 The format of the string is:
625 (h|H|v|V|<angle>),<start_r>,<start_g>,<start_b>-<end_r>,<end_g>,<end_b>
626 where <angle> is given decimal. The rest represents hexadecimal 32 bit
627 numbers.
628 **************************************************************************/
629 BOOL zune_gradient_string_to_intern(CONST_STRPTR str,
630 struct MUI_ImageSpec_intern *spec)
632 LONG converted;
633 ULONG angle;
634 ULONG start_r, start_g, start_b;
635 ULONG end_r, end_g, end_b;
637 if (!str || !spec)
638 return FALSE;
640 /* Find out about the gradient angle */
641 switch (str[0])
643 case 'H':
644 case 'h':
645 angle = 90;
646 converted = 1;
647 break;
649 case 'V':
650 case 'v':
651 angle = 0;
652 converted = 1;
653 break;
655 default:
656 converted = StrToLong((STRPTR) str, (LONG *) & angle);
657 if (converted == -1)
658 return FALSE;
659 break;
662 str += converted;
664 /* convert the color information */
665 if (*str != ',')
666 return FALSE;
667 str++;
668 converted = HexToLong((STRPTR) str, &start_r);
669 if (converted == -1)
670 return FALSE;
671 str += converted;
673 if (*str != ',')
674 return FALSE;
675 str++;
676 converted = HexToLong((STRPTR) str, &start_g);
677 if (converted == -1)
678 return FALSE;
679 str += converted;
681 if (*str != ',')
682 return FALSE;
683 str++;
684 converted = HexToLong((STRPTR) str, &start_b);
685 if (converted == -1)
686 return FALSE;
687 str += converted;
689 if (*str != '-')
690 return FALSE;
691 str++;
692 converted = HexToLong((STRPTR) str, &end_r);
693 if (converted == -1)
694 return FALSE;
695 str += converted;
697 if (*str != ',')
698 return FALSE;
699 str++;
700 converted = HexToLong((STRPTR) str, &end_g);
701 if (converted == -1)
702 return FALSE;
703 str += converted;
705 if (*str != ',')
706 return FALSE;
707 str++;
708 converted = HexToLong((STRPTR) str, &end_b);
709 if (converted == -1)
710 return FALSE;
712 /* Fill in the spec */
713 spec->u.gradient.angle = angle;
715 spec->u.gradient.start_rgb[0] = start_r >> 24;
716 spec->u.gradient.start_rgb[1] = start_g >> 24;
717 spec->u.gradient.start_rgb[2] = start_b >> 24;
719 spec->u.gradient.end_rgb[0] = end_r >> 24;
720 spec->u.gradient.end_rgb[1] = end_g >> 24;
721 spec->u.gradient.end_rgb[2] = end_b >> 24;
723 return TRUE;
726 VOID zune_scaled_gradient_intern_to_string(struct MUI_ImageSpec_intern *
727 spec, STRPTR buf)
729 sprintf(buf, "7:%d,%08x,%08x,%08x-%08x,%08x,%08x",
730 (int)spec->u.gradient.angle,
731 (unsigned int)spec->u.gradient.start_rgb[0] * 0x01010101,
732 (unsigned int)spec->u.gradient.start_rgb[1] * 0x01010101,
733 (unsigned int)spec->u.gradient.start_rgb[2] * 0x01010101,
734 (unsigned int)spec->u.gradient.end_rgb[0] * 0x01010101,
735 (unsigned int)spec->u.gradient.end_rgb[1] * 0x01010101,
736 (unsigned int)spec->u.gradient.end_rgb[2] * 0x01010101);
739 VOID zune_tiled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
740 STRPTR buf)
742 sprintf(buf, "8:%d,%08x,%08x,%08x-%08x,%08x,%08x",
743 (int)spec->u.gradient.angle,
744 (unsigned int)spec->u.gradient.start_rgb[0] * 0x01010101,
745 (unsigned int)spec->u.gradient.start_rgb[1] * 0x01010101,
746 (unsigned int)spec->u.gradient.start_rgb[2] * 0x01010101,
747 (unsigned int)spec->u.gradient.end_rgb[0] * 0x01010101,
748 (unsigned int)spec->u.gradient.end_rgb[1] * 0x01010101,
749 (unsigned int)spec->u.gradient.end_rgb[2] * 0x01010101);
752 BOOL zune_gradientspec_setup(struct MUI_ImageSpec_intern *spec,
753 struct MUI_RenderInfo *mri)
755 spec->u.gradient.mri = mri;
757 if (!(mri->mri_Flags & MUIMRI_TRUECOLOR))
759 ULONG *rgbptr = spec->u.gradient.start_rgb;
760 ULONG *penptr = &spec->u.gradient.start_pen;
761 BOOL *flagptr = &spec->u.gradient.start_pen_is_allocated;
762 LONG pen, i;
764 struct TagItem obp_tags[] = {
765 {OBP_FailIfBad, FALSE},
766 {TAG_DONE}
769 for (i = 0; i < 2; i++)
771 ULONG r = rgbptr[0] * 0x01010101;
772 ULONG g = rgbptr[1] * 0x01010101;
773 ULONG b = rgbptr[2] * 0x01010101;
775 pen = ObtainBestPenA(mri->mri_Colormap, r, g, b, obp_tags);
777 if (pen == -1)
779 *flagptr = FALSE;
780 *penptr = FindColor(mri->mri_Colormap, r, g, b, -1);
782 else
784 *flagptr = TRUE;
785 *penptr = pen;
788 rgbptr = spec->u.gradient.end_rgb;
789 penptr = &spec->u.gradient.end_pen;
790 flagptr = &spec->u.gradient.end_pen_is_allocated;
794 else
796 spec->u.gradient.start_pen_is_allocated = FALSE;
797 spec->u.gradient.end_pen_is_allocated = FALSE;
800 return TRUE;
803 void zune_gradientspec_cleanup(struct MUI_ImageSpec_intern *spec)
805 if (spec->u.gradient.start_pen_is_allocated)
807 ReleasePen(spec->u.gradient.mri->mri_Colormap,
808 spec->u.gradient.start_pen);
809 spec->u.gradient.start_pen_is_allocated = FALSE;
812 if (spec->u.gradient.end_pen_is_allocated)
814 ReleasePen(spec->u.gradient.mri->mri_Colormap,
815 spec->u.gradient.end_pen);
816 spec->u.gradient.end_pen_is_allocated = FALSE;
819 spec->u.gradient.mri = NULL;