use dmb/dsb from asm/cpu.h file.
[AROS.git] / workbench / libs / muimaster / imspec_gradient.c
blob0ce797cf6d29c2cee4982b2d808160ebcdb2898e
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)
505 FillPixelArrayGradientRelative(rp, abs_l, abs_t, abs_r,
506 abs_b, x1, y1, x2 - x1 + 1, y2 - y1 + 1, start_rgb, end_rgb,
507 spec->u.gradient.angle, xoff, yoff);
508 return;
511 switch (spec->u.gradient.angle)
513 case 0:
515 LONG oy1 = _top(spec->u.gradient.obj), oy2 =
516 _bottom(spec->u.gradient.obj);
517 LONG delta_oy = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
518 LONG hh = (delta_oy + 1) * 2;
519 LONG mid_y;
521 yoff %= hh;
523 if (yoff < 0)
524 yoff += hh;
526 oy1 -= yoff;
527 oy2 -= yoff;
529 if (y2 > oy2)
531 mid_y = y1 + delta_oy - yoff;
533 if (yoff > delta_oy)
535 ULONG *tmp = start_rgb;
536 start_rgb = end_rgb;
537 end_rgb = tmp;
539 mid_y += delta_oy;
540 oy1 += delta_oy;
541 oy2 += delta_oy;
544 else
546 mid_y = y2;
549 TrueDitherV
550 (rp, x1, y1, x2, mid_y, oy1, oy2, start_rgb, end_rgb);
552 if (mid_y < y2)
554 TrueDitherV
555 (rp,
556 x1, mid_y + 1, x2, y2,
557 oy1 + delta_oy, oy2 + delta_oy, end_rgb, start_rgb);
560 break;
562 case 90:
564 LONG ox1 = _left(spec->u.gradient.obj), ox2 =
565 _right(spec->u.gradient.obj);
566 LONG delta_ox = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
567 LONG ww = (delta_ox + 1) * 2;
568 LONG mid_x;
571 xoff %= ww;
572 if (xoff < 0)
573 xoff += ww;
575 ox1 -= xoff;
576 ox2 -= xoff;
578 if (x2 > ox2)
580 mid_x = x1 + delta_ox - xoff;
582 if (xoff > delta_ox)
584 ULONG *tmp = start_rgb;
585 start_rgb = end_rgb;
586 end_rgb = tmp;
588 mid_x += delta_ox;
589 ox1 += delta_ox;
590 ox2 += delta_ox;
593 else
595 mid_x = x2;
598 TrueDitherH
599 (rp, x1, y1, mid_x, y2, ox1, ox2, start_rgb, end_rgb);
601 if (mid_x < x2)
603 TrueDitherH
604 (rp,
605 mid_x + 1, y1, x2, y2,
606 ox1 + delta_ox, ox2 + delta_ox, end_rgb, start_rgb);
609 break;
611 default:
612 FillPixelArrayGradient(rp, x1, y1, x2, y2, start_rgb, end_rgb,
613 spec->u.gradient.angle);
614 break;
615 } /* switch(angle) */
617 VOID zune_gradient_draw(struct MUI_ImageSpec_intern *spec,
618 struct MUI_RenderInfo *mri, WORD x1, WORD y1, WORD x2, WORD y2,
619 WORD xoff, WORD yoff)
621 zune_gradient_drawfast(spec, mri->mri_RastPort,
622 mri, 0, x1, y1, x2, y2, x1, y1, x2, y2, xoff, yoff);
624 /*************************************************************************
625 Converts a gradient string to a internal image spec
627 The format of the string is:
628 (h|H|v|V|<angle>),<start_r>,<start_g>,<start_b>-<end_r>,<end_g>,<end_b>
629 where <angle> is given decimal. The rest represents hexadecimal 32 bit
630 numbers.
631 **************************************************************************/
632 BOOL zune_gradient_string_to_intern(CONST_STRPTR str,
633 struct MUI_ImageSpec_intern *spec)
635 LONG converted;
636 ULONG angle;
637 ULONG start_r, start_g, start_b;
638 ULONG end_r, end_g, end_b;
640 if (!str || !spec)
641 return FALSE;
643 /* Find out about the gradient angle */
644 switch (str[0])
646 case 'H':
647 case 'h':
648 angle = 90;
649 converted = 1;
650 break;
652 case 'V':
653 case 'v':
654 angle = 0;
655 converted = 1;
656 break;
658 default:
659 converted = StrToLong((STRPTR) str, (LONG *) & angle);
660 if (converted == -1)
661 return FALSE;
662 break;
665 str += converted;
667 /* convert the color information */
668 if (*str != ',')
669 return FALSE;
670 str++;
671 converted = HexToLong((STRPTR) str, &start_r);
672 if (converted == -1)
673 return FALSE;
674 str += converted;
676 if (*str != ',')
677 return FALSE;
678 str++;
679 converted = HexToLong((STRPTR) str, &start_g);
680 if (converted == -1)
681 return FALSE;
682 str += converted;
684 if (*str != ',')
685 return FALSE;
686 str++;
687 converted = HexToLong((STRPTR) str, &start_b);
688 if (converted == -1)
689 return FALSE;
690 str += converted;
692 if (*str != '-')
693 return FALSE;
694 str++;
695 converted = HexToLong((STRPTR) str, &end_r);
696 if (converted == -1)
697 return FALSE;
698 str += converted;
700 if (*str != ',')
701 return FALSE;
702 str++;
703 converted = HexToLong((STRPTR) str, &end_g);
704 if (converted == -1)
705 return FALSE;
706 str += converted;
708 if (*str != ',')
709 return FALSE;
710 str++;
711 converted = HexToLong((STRPTR) str, &end_b);
712 if (converted == -1)
713 return FALSE;
715 /* Fill in the spec */
716 spec->u.gradient.angle = angle;
718 spec->u.gradient.start_rgb[0] = start_r >> 24;
719 spec->u.gradient.start_rgb[1] = start_g >> 24;
720 spec->u.gradient.start_rgb[2] = start_b >> 24;
722 spec->u.gradient.end_rgb[0] = end_r >> 24;
723 spec->u.gradient.end_rgb[1] = end_g >> 24;
724 spec->u.gradient.end_rgb[2] = end_b >> 24;
726 return TRUE;
729 VOID zune_scaled_gradient_intern_to_string(struct MUI_ImageSpec_intern *
730 spec, STRPTR buf)
732 sprintf(buf, "7:%d,%08x,%08x,%08x-%08x,%08x,%08x",
733 (int)spec->u.gradient.angle,
734 (unsigned int)spec->u.gradient.start_rgb[0] * 0x01010101,
735 (unsigned int)spec->u.gradient.start_rgb[1] * 0x01010101,
736 (unsigned int)spec->u.gradient.start_rgb[2] * 0x01010101,
737 (unsigned int)spec->u.gradient.end_rgb[0] * 0x01010101,
738 (unsigned int)spec->u.gradient.end_rgb[1] * 0x01010101,
739 (unsigned int)spec->u.gradient.end_rgb[2] * 0x01010101);
742 VOID zune_tiled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
743 STRPTR buf)
745 sprintf(buf, "8:%d,%08x,%08x,%08x-%08x,%08x,%08x",
746 (int)spec->u.gradient.angle,
747 (unsigned int)spec->u.gradient.start_rgb[0] * 0x01010101,
748 (unsigned int)spec->u.gradient.start_rgb[1] * 0x01010101,
749 (unsigned int)spec->u.gradient.start_rgb[2] * 0x01010101,
750 (unsigned int)spec->u.gradient.end_rgb[0] * 0x01010101,
751 (unsigned int)spec->u.gradient.end_rgb[1] * 0x01010101,
752 (unsigned int)spec->u.gradient.end_rgb[2] * 0x01010101);
755 BOOL zune_gradientspec_setup(struct MUI_ImageSpec_intern *spec,
756 struct MUI_RenderInfo *mri)
758 spec->u.gradient.mri = mri;
760 if (!(mri->mri_Flags & MUIMRI_TRUECOLOR))
762 ULONG *rgbptr = spec->u.gradient.start_rgb;
763 ULONG *penptr = &spec->u.gradient.start_pen;
764 BOOL *flagptr = &spec->u.gradient.start_pen_is_allocated;
765 LONG pen, i;
767 struct TagItem obp_tags[] = {
768 {OBP_FailIfBad, FALSE},
769 {TAG_DONE}
772 for (i = 0; i < 2; i++)
774 ULONG r = rgbptr[0] * 0x01010101;
775 ULONG g = rgbptr[1] * 0x01010101;
776 ULONG b = rgbptr[2] * 0x01010101;
778 pen = ObtainBestPenA(mri->mri_Colormap, r, g, b, obp_tags);
780 if (pen == -1)
782 *flagptr = FALSE;
783 *penptr = FindColor(mri->mri_Colormap, r, g, b, -1);
785 else
787 *flagptr = TRUE;
788 *penptr = pen;
791 rgbptr = spec->u.gradient.end_rgb;
792 penptr = &spec->u.gradient.end_pen;
793 flagptr = &spec->u.gradient.end_pen_is_allocated;
797 else
799 spec->u.gradient.start_pen_is_allocated = FALSE;
800 spec->u.gradient.end_pen_is_allocated = FALSE;
803 return TRUE;
806 void zune_gradientspec_cleanup(struct MUI_ImageSpec_intern *spec)
808 if (spec->u.gradient.start_pen_is_allocated)
810 ReleasePen(spec->u.gradient.mri->mri_Colormap,
811 spec->u.gradient.start_pen);
812 spec->u.gradient.start_pen_is_allocated = FALSE;
815 if (spec->u.gradient.end_pen_is_allocated)
817 ReleasePen(spec->u.gradient.mri->mri_Colormap,
818 spec->u.gradient.end_pen);
819 spec->u.gradient.end_pen_is_allocated = FALSE;
822 spec->u.gradient.mri = NULL;