Fixed binary search: no more infinite loops when vendor is unknown.
[tangerine.git] / workbench / libs / muimaster / imspec_gradient.c
blob07e063b1a9a77e37c968d91c850611e6b029173e
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;
152 int diffR, diffG, diffB;
154 int r,t; /* some helper variables to short the code */
155 int l,y,c,x;
156 int y1; /* The intersection point */
157 int incr_y1; /* increment of y1 */
158 int xs,ys,xw,yw;
159 int xadd,ystart,yadd;
160 // double vx = -cosarc;
161 // double vy = sinarc;
162 int vx = (int)(-cosarc*0xff);
163 int vy = (int)(sinarc*0xff);
165 int width = xb - xt + 1;
166 int height = yb - yt + 1;
168 if ((w <= 0) || (h <= 0)) return;
169 UBYTE *buf = AllocVec(w*h*3, 0);
170 if (buf == NULL) return;
172 startRGB.red = start_rgb[0];
173 startRGB.green = start_rgb[1];
174 startRGB.blue = start_rgb[2];
176 endRGB.red = end_rgb[0];
177 endRGB.green = end_rgb[1];
178 endRGB.blue = end_rgb[2];
180 diffR = endRGB.red - startRGB.red;
181 diffG = endRGB.green - startRGB.green;
182 diffB = endRGB.blue - startRGB.blue;
184 /* Normalize the angle */
185 if (angle < 0) angle = 360 - ((-angle)%360);
186 if (angle >= 0) angle = angle % 360;
188 if (angle <= 90 || (angle > 180 && angle <= 270))
190 /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
191 xs = 0;
192 ys = 0;
193 xw = width;
194 yw = height;
195 } else
197 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
198 xs = 0;
199 ys = height;
200 xw = width;
201 yw = -height;
204 if (angle > 90 && angle <= 270)
206 /* for these angle we have y1 = height - y1. Instead of
208 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
210 * we can write
212 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
214 * so height - y1 can be expressed with the normal formular adapting some parameters.
216 * Note that if one would exchanging startRGB/endRGB the values would only work
217 * for linear color gradients
219 xadd = -1;
220 yadd = -1;
221 ystart = height;
223 xs = -xs;
224 ys = -ys + height;
225 } else
227 xadd = 1;
228 yadd = 1;
229 ystart = 0;
232 r = -vy*(yw*xs-xw*ys);
233 t = -yw*vx + xw*vy;
235 /* The formular as shown above is
237 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
239 * We see that only yw*(vy*x-vx*y) changes during the loop.
241 * We write
243 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
244 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
246 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
250 incr_y1 = yw*vy*xadd;
251 UBYTE *bufptr = buf;
252 for (l = 0, y = ystart + ((yp - yt)* yadd); l < h; l++, y+=yadd)
255 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
256 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
257 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
258 * vx nothing is left, currently 9 bits are used for vx or vy */
259 int y1_mul_t_accu = r - yw*vx*y;
262 y1_mul_t_accu += (incr_y1 * (xp - xt));
264 for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x+=xadd)
266 int red,green,blue;
268 /* Calculate the intersection of two lines, this is not the fastet way to do but
269 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
270 * and making it incremental)...update: it's now incremental and no FFP is used
271 * but it probably can be optimized more by removing some more of the divisions and
272 * further specialize the stuff here (use of three accus). */
273 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
274 y1 = y1_mul_t_accu / t;
276 red = startRGB.red + (int)(diffR*y1/height);
277 green = startRGB.green + (int)(diffG*y1/height);
278 blue = startRGB.blue + (int)(diffB*y1/height);
279 /* By using full 32 bits this can be made faster as well */
280 *bufptr++ = red;
281 *bufptr++ = green;
282 *bufptr++ = blue;
284 y1_mul_t_accu += incr_y1;
286 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
287 * to WritePixelArray() can be made also faster */
289 WritePixelArray(buf,0,0,w*3, rp,0,0,w,h,RECTFMT_RGB);
290 FreeVec(buf);
294 /*****************************************************************
295 Fill the given rectangle with a angle oriented gradient. The
296 unit angle uses are degrees
297 ******************************************************************/
298 STATIC int FillPixelArrayGradient(struct RastPort *rp, int xt, int yt, int xb, int yb, ULONG *start_rgb, ULONG *end_rgb, int angle)
300 /* The basic idea of this algorithm is to calc the intersection between the
301 * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line starting
302 * at (x,y) (every pixel inside the rectangle) and angle angle with direction vector (vx,vy).
304 * Having the intersection point we then know the color of the pixel.
306 * TODO: Turn the algorithm into a incremental one
307 * Remove the use of floating point variables
310 double rad = angle*M_PI/180;
311 double cosarc = cos(rad);
312 double sinarc = sin(rad);
314 struct myrgb startRGB,endRGB;
315 int diffR, diffG, diffB;
317 int r,t; /* some helper variables to short the code */
318 int l,y,c,x;
319 int y1; /* The intersection point */
320 int incr_y1; /* increment of y1 */
321 int xs,ys,xw,yw;
322 int xadd,ystart,yadd;
323 // double vx = -cosarc;
324 // double vy = sinarc;
325 int vx = (int)(-cosarc*0xff);
326 int vy = (int)(sinarc*0xff);
328 int width = xb - xt + 1;
329 int height = yb - yt + 1;
331 UBYTE *buf = (UBYTE*)AllocVec(width*3,0);
332 if (!buf) return 0;
334 startRGB.red = start_rgb[0];
335 startRGB.green = start_rgb[1];
336 startRGB.blue = start_rgb[2];
338 endRGB.red = end_rgb[0];
339 endRGB.green = end_rgb[1];
340 endRGB.blue = end_rgb[2];
342 diffR = endRGB.red - startRGB.red;
343 diffG = endRGB.green - startRGB.green;
344 diffB = endRGB.blue - startRGB.blue;
346 /* Normalize the angle */
347 if (angle < 0) angle = 360 - ((-angle)%360);
348 if (angle >= 0) angle = angle % 360;
350 if (angle <= 90 || (angle > 180 && angle <= 270))
352 /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
353 xs = 0;
354 ys = 0;
355 xw = width;
356 yw = height;
357 } else
359 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
360 xs = 0;
361 ys = height;
362 xw = width;
363 yw = -height;
366 if (angle > 90 && angle <= 270)
368 /* for these angle we have y1 = height - y1. Instead of
370 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
372 * we can write
374 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
376 * so height - y1 can be expressed with the normal formular adapting some parameters.
378 * Note that if one would exchanging startRGB/endRGB the values would only work
379 * for linear color gradients
381 xadd = -1;
382 yadd = -1;
383 ystart = height;
385 xs = -xs;
386 ys = -ys + height;
387 } else
389 xadd = 1;
390 yadd = 1;
391 ystart = 0;
394 r = -vy*(yw*xs-xw*ys);
395 t = -yw*vx + xw*vy;
397 /* The formular as shown above is
399 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
401 * We see that only yw*(vy*x-vx*y) changes during the loop.
403 * We write
405 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
406 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
408 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
412 incr_y1 = yw*vy*xadd;
414 for (l = 0, y = ystart; l < height; l++, y+=yadd)
416 UBYTE *bufptr = buf;
418 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
419 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
420 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
421 * vx nothing is left, currently 9 bits are used for vx or vy */
422 int y1_mul_t_accu = r - yw*vx*y;
424 for (c = 0, x = 0; c < width; c++, x+=xadd)
426 int red,green,blue;
428 /* Calculate the intersection of two lines, this is not the fastet way to do but
429 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
430 * and making it incremental)...update: it's now incremental and no FFP is used
431 * but it probably can be optimized more by removing some more of the divisions and
432 * further specialize the stuff here (use of three accus). */
433 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
434 y1 = y1_mul_t_accu / t;
436 red = startRGB.red + (int)(diffR*y1/height);
437 green = startRGB.green + (int)(diffG*y1/height);
438 blue = startRGB.blue + (int)(diffB*y1/height);
440 /* By using full 32 bits this can be made faster as well */
441 *bufptr++ = red;
442 *bufptr++ = green;
443 *bufptr++ = blue;
445 y1_mul_t_accu += incr_y1;
447 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
448 * to WritePixelArray() can be made also faster */
449 WritePixelArray(buf,0,0,width*3 /* srcMod */,
450 rp,xt,yt+l,width,1,RECTFMT_RGB);
452 FreeVec(buf);
453 return 1;
456 /***************************************************************************************************/
458 VOID zune_gradient_drawfast
460 struct MUI_ImageSpec_intern *spec,
461 struct RastPort *rp,
462 struct MUI_RenderInfo *mri,
463 WORD mode, WORD abs_l, WORD abs_t, WORD abs_r, WORD abs_b,
464 WORD x1, WORD y1, WORD x2, WORD y2,
465 WORD xoff, WORD yoff
468 ULONG *start_rgb = spec->u.gradient.start_rgb;
469 ULONG *end_rgb = spec->u.gradient.end_rgb;
471 if (!(CyberGfxBase && (mri->mri_Flags & MUIMRI_TRUECOLOR) && spec->u.gradient.obj))
473 SetAPen(rp, spec->u.gradient.start_pen);
474 RectFill(rp, x1, y1, x2, y2);
475 return;
477 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);
479 switch(spec->u.gradient.angle)
481 case 0:
483 LONG oy1 = _top(spec->u.gradient.obj), oy2 = _bottom(spec->u.gradient.obj);
484 LONG delta_oy = (oy2 - oy1 > 0) ? oy2 - oy1 : 1;
485 LONG hh = (delta_oy + 1)*2;
486 LONG mid_y;
488 yoff %= hh;
490 if (yoff < 0)
491 yoff += hh;
493 oy1 -= yoff; oy2 -= yoff;
495 if (y2 > oy2)
497 mid_y = y1 + delta_oy - yoff;
499 if (yoff > delta_oy)
501 ULONG *tmp = start_rgb;
502 start_rgb = end_rgb;
503 end_rgb = tmp;
505 mid_y += delta_oy;
506 oy1 += delta_oy;
507 oy2 += delta_oy;
510 else
512 mid_y = y2;
515 TrueDitherV
518 x1, y1, x2, mid_y,
519 oy1, oy2,
520 start_rgb, end_rgb
523 if (mid_y < y2)
525 TrueDitherV
528 x1, mid_y+1, x2, y2,
529 oy1+delta_oy, oy2+delta_oy,
530 end_rgb, start_rgb
534 break;
536 case 90:
538 LONG ox1 = _left(spec->u.gradient.obj), ox2 = _right(spec->u.gradient.obj);
539 LONG delta_ox = (ox2 - ox1 > 0) ? ox2 - ox1 : 1;
540 LONG ww = (delta_ox + 1)*2;
541 LONG mid_x;
544 xoff %= ww;
545 if (xoff < 0)
546 xoff += ww;
548 ox1 -= xoff; ox2 -= xoff;
550 if (x2 > ox2)
552 mid_x = x1 + delta_ox - xoff;
554 if (xoff > delta_ox)
556 ULONG *tmp = start_rgb;
557 start_rgb = end_rgb;
558 end_rgb = tmp;
560 mid_x += delta_ox;
561 ox1 += delta_ox;
562 ox2 += delta_ox;
565 else
567 mid_x = x2;
570 TrueDitherH
573 x1, y1, mid_x, y2,
574 ox1, ox2,
575 start_rgb, end_rgb
578 if (mid_x < x2)
580 TrueDitherH
583 mid_x+1, y1, x2, y2,
584 ox1+delta_ox, ox2+delta_ox,
585 end_rgb, start_rgb
589 break;
591 default:
592 FillPixelArrayGradient(rp, x1, y1, x2, y2, start_rgb, end_rgb, spec->u.gradient.angle);
593 break;
594 } /* switch(angle) */
596 VOID zune_gradient_draw
598 struct MUI_ImageSpec_intern *spec,
599 struct MUI_RenderInfo *mri,
600 WORD x1, WORD y1, WORD x2, WORD y2,
601 WORD xoff, WORD yoff
604 zune_gradient_drawfast
606 spec,
607 mri->mri_RastPort,
608 mri, 0,
609 x1, y1, x2, y2,
610 x1, y1, x2, y2,
611 xoff, yoff
614 /*************************************************************************
615 Converts a gradient string to a internal image spec
617 The format of the string is:
618 (h|H|v|V|<angle>),<start_r>,<start_g>,<start_b>-<end_r>,<end_g>,<end_b>
619 where <angle> is given decimal. The rest represents hexadecimal 32 bit
620 numbers.
621 **************************************************************************/
622 BOOL zune_gradient_string_to_intern(CONST_STRPTR str,
623 struct MUI_ImageSpec_intern *spec)
625 LONG converted;
626 ULONG angle;
627 ULONG start_r, start_g, start_b;
628 ULONG end_r, end_g, end_b;
630 if (!str || !spec) return FALSE;
632 /* Find out about the gradient angle */
633 switch (str[0])
635 case 'H':
636 case 'h':
637 angle = 90;
638 converted = 1;
639 break;
641 case 'V':
642 case 'v':
643 angle = 0;
644 converted = 1;
645 break;
647 default:
648 converted = StrToLong((STRPTR)str,(LONG*)&angle);
649 if (converted == -1) return FALSE;
650 break;
653 str += converted;
655 /* convert the color information */
656 if (*str != ',') return FALSE;
657 str++;
658 converted = HexToLong((STRPTR)str,&start_r);
659 if (converted == -1) return FALSE;
660 str += converted;
662 if (*str != ',') return FALSE;
663 str++;
664 converted = HexToLong((STRPTR)str,&start_g);
665 if (converted == -1) return FALSE;
666 str += converted;
668 if (*str != ',') return FALSE;
669 str++;
670 converted = HexToLong((STRPTR)str,&start_b);
671 if (converted == -1) return FALSE;
672 str += converted;
674 if (*str != '-') return FALSE;
675 str++;
676 converted = HexToLong((STRPTR)str,&end_r);
677 if (converted == -1) return FALSE;
678 str += converted;
680 if (*str != ',') return FALSE;
681 str++;
682 converted = HexToLong((STRPTR)str,&end_g);
683 if (converted == -1) return FALSE;
684 str += converted;
686 if (*str != ',') return FALSE;
687 str++;
688 converted = HexToLong((STRPTR)str,&end_b);
689 if (converted == -1) return FALSE;
691 /* Fill in the spec */
692 spec->u.gradient.angle = angle;
694 spec->u.gradient.start_rgb[0] = start_r>>24;
695 spec->u.gradient.start_rgb[1] = start_g>>24;
696 spec->u.gradient.start_rgb[2] = start_b>>24;
698 spec->u.gradient.end_rgb[0] = end_r>>24;
699 spec->u.gradient.end_rgb[1] = end_g>>24;
700 spec->u.gradient.end_rgb[2] = end_b>>24;
702 return TRUE;
705 VOID zune_scaled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
706 STRPTR buf)
708 sprintf(buf, "7:%ld,%08lx,%08lx,%08lx-%08lx,%08lx,%08lx",
709 (LONG)spec->u.gradient.angle,
710 spec->u.gradient.start_rgb[0]*0x01010101,
711 spec->u.gradient.start_rgb[1]*0x01010101,
712 spec->u.gradient.start_rgb[2]*0x01010101,
713 spec->u.gradient.end_rgb[0]*0x01010101,
714 spec->u.gradient.end_rgb[1]*0x01010101,
715 spec->u.gradient.end_rgb[2]*0x01010101);
718 VOID zune_tiled_gradient_intern_to_string(struct MUI_ImageSpec_intern *spec,
719 STRPTR buf)
721 sprintf(buf, "8:%ld,%08lx,%08lx,%08lx-%08lx,%08lx,%08lx",
722 spec->u.gradient.angle,
723 spec->u.gradient.start_rgb[0]*0x01010101,
724 spec->u.gradient.start_rgb[1]*0x01010101,
725 spec->u.gradient.start_rgb[2]*0x01010101,
726 spec->u.gradient.end_rgb[0]*0x01010101,
727 spec->u.gradient.end_rgb[1]*0x01010101,
728 spec->u.gradient.end_rgb[2]*0x01010101);
731 BOOL zune_gradientspec_setup(struct MUI_ImageSpec_intern *spec, struct MUI_RenderInfo *mri)
733 spec->u.gradient.mri = mri;
735 if (!(mri->mri_Flags & MUIMRI_TRUECOLOR))
737 ULONG *rgbptr = spec->u.gradient.start_rgb;
738 ULONG *penptr = &spec->u.gradient.start_pen;
739 BOOL *flagptr = &spec->u.gradient.start_pen_is_allocated;
740 LONG pen, i;
742 struct TagItem obp_tags[] =
744 { OBP_FailIfBad, FALSE },
745 { TAG_DONE }
748 for(i = 0; i < 2; i++)
750 ULONG r = rgbptr[0] * 0x01010101;
751 ULONG g = rgbptr[1] * 0x01010101;
752 ULONG b = rgbptr[2] * 0x01010101;
754 pen = ObtainBestPenA(mri->mri_Colormap, r, g, b, obp_tags);
756 if (pen == -1)
758 *flagptr = FALSE;
759 *penptr = FindColor(mri->mri_Colormap, r, g, b, -1);
761 else
763 *flagptr = TRUE;
764 *penptr = pen;
767 rgbptr = spec->u.gradient.end_rgb;
768 penptr = &spec->u.gradient.end_pen;
769 flagptr = &spec->u.gradient.end_pen_is_allocated;
773 else
775 spec->u.gradient.start_pen_is_allocated = FALSE;
776 spec->u.gradient.end_pen_is_allocated = FALSE;
779 return TRUE;
782 void zune_gradientspec_cleanup(struct MUI_ImageSpec_intern *spec)
784 if (spec->u.gradient.start_pen_is_allocated)
786 ReleasePen(spec->u.gradient.mri->mri_Colormap, spec->u.gradient.start_pen);
787 spec->u.gradient.start_pen_is_allocated = FALSE;
790 if (spec->u.gradient.end_pen_is_allocated)
792 ReleasePen(spec->u.gradient.mri->mri_Colormap, spec->u.gradient.end_pen);
793 spec->u.gradient.end_pen_is_allocated = FALSE;
796 spec->u.gradient.mri = NULL;