2 Copyright 2003, The AROS Development Team.
9 #include <intuition/imageclass.h>
10 #include <cybergraphx/cybergraphics.h>
11 #include <proto/graphics.h>
12 #include <proto/cybergraphics.h>
15 #include <proto/dos.h>
16 #include <proto/exec.h>
17 #include <proto/utility.h>
20 #include "imspec_intern.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
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
56 WORD x1
, WORD y1
, WORD x2
, WORD y2
,
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
));
89 STATIC VOID TrueDitherH
92 WORD x1
, WORD y1
, WORD x2
, WORD y2
,
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
));
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 */
157 int y1
; /* The intersection point */
158 int incr_y1
; /* increment of y1 */
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 */
198 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
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);
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
233 r
= -vy
*(yw
*xs
-xw
*ys
);
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.
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
;
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
)
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 */
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
);
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 */
320 int y1
; /* The intersection point */
321 int incr_y1
; /* increment of y1 */
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);
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 */
360 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
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);
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
395 r
= -vy
*(yw
*xs
-xw
*ys
);
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.
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
)
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
)
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 */
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
);
457 /***************************************************************************************************/
459 VOID zune_gradient_drawfast
461 struct MUI_ImageSpec_intern
*spec
,
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
,
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
);
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
)
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;
494 oy1
-= yoff
; oy2
-= yoff
;
498 mid_y
= y1
+ delta_oy
- yoff
;
502 ULONG
*tmp
= start_rgb
;
530 oy1
+delta_oy
, oy2
+delta_oy
,
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;
549 ox1
-= xoff
; ox2
-= xoff
;
553 mid_x
= x1
+ delta_ox
- xoff
;
557 ULONG
*tmp
= start_rgb
;
585 ox1
+delta_ox
, ox2
+delta_ox
,
593 FillPixelArrayGradient(rp
, x1
, y1
, x2
, y2
, start_rgb
, end_rgb
, spec
->u
.gradient
.angle
);
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
,
605 zune_gradient_drawfast
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
622 **************************************************************************/
623 BOOL
zune_gradient_string_to_intern(CONST_STRPTR str
,
624 struct MUI_ImageSpec_intern
*spec
)
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 */
649 converted
= StrToLong((STRPTR
)str
,(LONG
*)&angle
);
650 if (converted
== -1) return FALSE
;
656 /* convert the color information */
657 if (*str
!= ',') return FALSE
;
659 converted
= HexToLong((STRPTR
)str
,&start_r
);
660 if (converted
== -1) return FALSE
;
663 if (*str
!= ',') return FALSE
;
665 converted
= HexToLong((STRPTR
)str
,&start_g
);
666 if (converted
== -1) return FALSE
;
669 if (*str
!= ',') return FALSE
;
671 converted
= HexToLong((STRPTR
)str
,&start_b
);
672 if (converted
== -1) return FALSE
;
675 if (*str
!= '-') return FALSE
;
677 converted
= HexToLong((STRPTR
)str
,&end_r
);
678 if (converted
== -1) return FALSE
;
681 if (*str
!= ',') return FALSE
;
683 converted
= HexToLong((STRPTR
)str
,&end_g
);
684 if (converted
== -1) return FALSE
;
687 if (*str
!= ',') return FALSE
;
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;
706 VOID
zune_scaled_gradient_intern_to_string(struct MUI_ImageSpec_intern
*spec
,
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
,
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
;
743 struct TagItem obp_tags
[] =
745 { OBP_FailIfBad
, FALSE
},
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
);
760 *penptr
= FindColor(mri
->mri_Colormap
, r
, g
, b
, -1);
768 rgbptr
= spec
->u
.gradient
.end_rgb
;
769 penptr
= &spec
->u
.gradient
.end_pen
;
770 flagptr
= &spec
->u
.gradient
.end_pen_is_allocated
;
776 spec
->u
.gradient
.start_pen_is_allocated
= FALSE
;
777 spec
->u
.gradient
.end_pen_is_allocated
= FALSE
;
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
;