only update affected area of bitmap
[aros:aros.git] / AROS / workbench / c / Decoration / drawfuncs.c
1 /*
2     Copyright © 2011-2013, The AROS Development Team.
3     $Id$
4 */
5
6 #include <aros/debug.h>
7
8 #include <intuition/imageclass.h>
9 #include <graphics/rpattr.h>
10 #include <libraries/cybergraphics.h>
11 #include <proto/arossupport.h>
12 #include <proto/graphics.h>
13 #include <proto/cybergraphics.h>
14 #include <proto/layers.h>
15 #include <proto/exec.h>
16
17 #include <hidd/graphics.h>
18
19 #include <math.h>
20
21 #include "drawfuncs.h"
22
23 #if AROS_BIG_ENDIAN
24 #define GET_A(rgb) ((rgb >> 24) & 0xff)
25 #define GET_R(rgb) ((rgb >> 16) & 0xff)
26 #define GET_G(rgb) ((rgb >> 8) & 0xff)
27 #define GET_B(rgb) (rgb & 0xff)
28 #define SET_ARGB(a, r, g, b) a << 24 | r << 16 | g << 8 | b
29 #else
30 #define GET_A(rgb) (rgb & 0xff)
31 #define GET_R(rgb) ((rgb >> 8) & 0xff)
32 #define GET_G(rgb) ((rgb >> 16) & 0xff)
33 #define GET_B(rgb) ((rgb >> 24) & 0xff)
34 #define SET_ARGB(a, r, g, b) b << 24 | g << 16 | r << 8 | a
35 #endif
36
37 /* This function provides a number of ways to blit a NewImage onto RastPort. Please take great care when modifying it.
38  *
39  * The number of combinations of arguments is quite high. Please take time to understand it.
40  *
41  * Arguments:
42  * ni - a NewImage that is to be blitted
43  * subimageCol, subimageRow - define the initial read offset in source image based on assumption that image contains
44  *                            a number of subimages drawn in rows or columns
45  * xSrc, ySrc - define additional read offset in the source image subimage
46  * destRP - destination RastPort to blit the image to
47  * xDest, yDest - coordinates on the destination RastPort to where the imatge will be blitted
48  * widthSrc, heightSrc - width/height of region to be read from, if -1 then use the width/height of subimage
49  * widthDest, heightDest - width/height of blit on destination RastPort, if -1 then use widthSrc/heightSrc
50  *
51  */
52 static void BltScaleNewImageSubImageRastPort(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
53         LONG xSrc, LONG ySrc, struct RastPort * destRP, LONG xDest, LONG yDest,
54         LONG widthSrc, LONG heightSrc, LONG widthDest, LONG heightDest)
55 {
56     ULONG subimagewidth     = ni->w / ni->subimagescols;
57     ULONG subimageheight    = ni->h / ni->subimagesrows;
58     
59     if (subimageCol >= ni->subimagescols) return;
60     if (subimageRow >= ni->subimagesrows) return;
61
62     /* If source size not provided, use subimage size */
63     if (widthSrc < 0) widthSrc = (LONG)subimagewidth;
64     if (heightSrc < 0) heightSrc = (LONG)subimageheight;
65
66     /* If destination size not provided, use source */
67     if (widthDest < 0) widthDest = widthSrc;
68     if (heightDest < 0) heightDest = heightSrc;
69
70     /* If source and destination sizes do not match, scale */
71     if ((widthSrc != widthDest) || (heightSrc != heightDest))
72     {
73         /* FIXME: The scaled blitting needs similar optimized code paths as non-scaled */
74         ULONG * srcptr = (ni->data) + (((subimageheight * subimageRow) + ySrc) * ni->w) +
75                 ((subimagewidth * subimageCol) + xSrc); /* Go to (0,0) of source rect */
76
77         ULONG * scaleddata = ScaleBuffer(srcptr, ni->w, widthSrc, heightSrc, widthDest, heightDest);
78
79         D(bug("[Decoration] SCALED %d,%d -> %d,%d!\n", widthSrc, heightSrc, widthDest, heightDest));
80
81         WritePixelArrayAlpha(scaleddata, 0, 0, widthDest * 4, destRP, xDest, yDest, widthDest, heightDest, 0xffffffff);
82
83         FreeVec(scaleddata);
84     }
85     else /* ((widthSrc != widthDest) || (heightSrc != heightDest)) */
86     {
87         /* Detect if image can be drawn using blitting instead of alpha draw */
88         if ((!ni->subimageinbm) || (!(ni->subimageinbm[subimageCol + (subimageRow * ni->subimagescols)])))
89         {
90             WritePixelArrayAlpha(ni->data, (subimagewidth * subimageCol) + xSrc ,
91                 (subimageheight * subimageRow) + ySrc, ni->w * 4, destRP,
92                 xDest, yDest, widthSrc, heightSrc, 0xffffffff);
93         }
94         else
95         {
96             /* LUT */
97             if (ni->bitmap != NULL)
98             {
99                 if (ni->mask)
100                 {
101                     BltMaskBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
102                         (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
103                         widthSrc, heightSrc, 0xe0, (PLANEPTR) ni->mask);
104                 }
105                 else
106                 {
107                     BltBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
108                         (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
109                         widthSrc, heightSrc, 0xc0);
110                 }
111             }
112
113             /* Truecolor */
114             if (ni->bitmap2 != NULL)
115             {
116                 BltBitMapRastPort(ni->bitmap2, (subimagewidth * subimageCol) + xSrc ,
117                     (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
118                     widthSrc, heightSrc, 0xc0);
119             }
120         }
121     }
122 }
123
124 /* HELPER WRAPPERS */
125 static inline void BltNewImageSubImageRastPort(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
126         LONG xSrc, LONG ySrc, struct RastPort * destRP, LONG xDest, LONG yDest, LONG widthSrc, LONG heightSrc)
127 {
128     BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, xSrc, ySrc, destRP,
129             xDest, yDest, widthSrc, heightSrc, -1, -1);
130 }
131
132 static inline void BltNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
133     struct RastPort * destRP, LONG xDest, LONG yDest)
134 {
135     BltNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
136             xDest, yDest, -1, -1);
137 }
138
139 static inline void BltScaleNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
140     struct RastPort * destRP, LONG xDest, LONG yDest, LONG widthDest, LONG heightDest)
141 {
142     BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
143             xDest, yDest, -1, -1, widthDest, heightDest);
144 }
145 /* HELPER WRAPPERS */
146
147 static void DrawTileToImage(struct NewImage *src, struct NewImage *dest, UWORD _sx, UWORD _sy, UWORD _sw, UWORD _sh, UWORD _dx, UWORD _dy, UWORD _dw, UWORD _dh)
148 {
149
150     ULONG   dy, dx;
151     LONG    dh, height, dw, width;
152
153     if (src == NULL) return;
154     if (dest == NULL) return;
155
156     dh = _sh;
157     dy = _dy;
158     height = _dh;
159
160     while (height > 0)
161     {
162         if ((height-dh)<0) dh = height;
163         height -= dh;
164         dw = _sw;
165         width = _dw;
166         dx = _dx;
167         while (width > 0)
168         {
169             if ((width-dw)<0) dw = width;
170             width -= dw;
171             DrawPartToImage(src, dest, _sx, _sy, dw, dh, dx, dy);
172             dx += dw;
173         }
174         dy += dh;
175     }
176 }
177
178 static void TileImageToImageMenuBar(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
179 {
180     UWORD   y, h;
181
182     if (dest == NULL) return;
183     if (src == NULL) return;
184     if (srcti == NULL) return;
185     y = 0;
186
187     h = src->h;
188
189     if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
190     if (srcti->TileRight > dest->w) return;
191
192     DrawTileToImage(src, dest, srcti->TileLeft, y, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop, 0, 0, dest->w - srcti->TileRight, srcti->TileTop);
193     DrawTileToImage(src, dest, srcti->TileLeft, y + h - srcti->TileBottom, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileBottom, 0, dest->h - srcti->TileBottom, dest->w - srcti->TileRight, srcti->TileBottom);
194     DrawTileToImage(src, dest, srcti->TileLeft, y + srcti->TileTop, src->w - srcti->TileLeft - srcti->TileRight, h - srcti->TileBottom - srcti->TileTop, 0, srcti->TileTop + 0, dest->w - srcti->TileRight, dest->h - srcti->TileTop - srcti->TileBottom - 0);
195
196
197     DrawTileToImage(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dest->w - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
198     DrawTileToImage(src, dest, src->w - srcti->TileRight, y + h - srcti->TileBottom, srcti->TileRight, srcti->TileBottom, dest->w - srcti->TileRight , dest->h - srcti->TileBottom, srcti->TileRight, srcti->TileBottom);
199     DrawTileToImage(src, dest, src->w - srcti->TileRight, y + srcti->TileTop, srcti->TileRight,  h - srcti->TileBottom - srcti->TileTop, dest->w - srcti->TileRight, srcti->TileTop + 0, srcti->TileRight, dest->h - srcti->TileTop - srcti->TileBottom - 0);
200
201 }
202
203 static void TileImageToImage(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
204 {
205     UWORD   y, h;
206
207     if (dest == NULL) return;
208     if (src == NULL) return;
209     if (srcti == NULL) return;
210     y = 0;
211
212     h = src->h;
213
214     if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
215     if ((srcti->TileLeft + srcti->TileRight) > dest->w) return;
216
217     DrawTileToImage(src, dest, 0, y, srcti->TileLeft, srcti->TileTop, 0 , 0, srcti->TileLeft, srcti->TileTop);
218     DrawTileToImage(src, dest, 0, y + h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom, 0 , dest->h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom);
219     DrawTileToImage(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dest->w - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
220     DrawTileToImage(src, dest, src->w - srcti->TileRight, y + h - srcti->TileBottom, srcti->TileRight, srcti->TileBottom, dest->w - srcti->TileRight , dest->h - srcti->TileBottom, srcti->TileRight, srcti->TileBottom);
221
222     DrawTileToImage(src, dest, srcti->TileLeft, y, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop, srcti->TileLeft, 0, dest->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop);
223     DrawTileToImage(src, dest, srcti->TileLeft, y + h - srcti->TileBottom, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileBottom, srcti->TileLeft, dest->h - srcti->TileBottom, dest->w - srcti->TileLeft - srcti->TileRight, srcti->TileBottom);
224     DrawTileToImage(src, dest, 0, y + srcti->TileTop, srcti->TileLeft, h - srcti->TileBottom - srcti->TileTop, 0 , srcti->TileTop + 0, srcti->TileLeft, dest->h - srcti->TileTop - srcti->TileBottom - 0);
225     DrawTileToImage(src, dest, src->w - srcti->TileRight, y + srcti->TileTop, srcti->TileRight,  h - srcti->TileBottom - srcti->TileTop, dest->w - srcti->TileRight, srcti->TileTop + 0, srcti->TileRight, dest->h - srcti->TileTop - srcti->TileBottom - 0);
226     DrawTileToImage(src, dest, srcti->TileLeft, y + srcti->TileTop, src->w - srcti->TileLeft - srcti->TileRight, h - srcti->TileBottom - srcti->TileTop, srcti->TileLeft, srcti->TileTop + 0, dest->w - srcti->TileLeft - srcti->TileRight, dest->h - srcti->TileTop - srcti->TileBottom - 0);
227 }
228
229 static void  MixImage(struct NewImage *dst, struct NewImage *src, struct TileInfo *srcti, UWORD ratio, UWORD w, UWORD h, UWORD dx, UWORD dy)
230 {
231     ULONG  *s, *d;
232     ULONG   rgba, rgb;
233     UWORD   r, g, b;
234     UBYTE   as, rs, gs, bs, rd, gd, bd;
235     BOOL    tiled = FALSE;
236     int     x, y;
237
238     if (src == NULL) return;
239     if (dst == NULL) return;
240
241     s = src->data;
242     d = dst->data;
243
244     if (srcti) tiled = TRUE;
245
246     for (y = 0; y < h; y++)
247     {
248         for (x = 0; x < w; x++)
249         {
250             rgba = s[x+y*src->w];
251             as = GET_A(rgba);
252             rs = GET_R(rgba);
253             gs = GET_G(rgba);
254             bs = GET_B(rgba);
255             rgb = d[x+dx + (y+dy) * dst->w];
256
257             rd = GET_R(rgb);
258             gd = GET_G(rgb);
259             bd = GET_B(rgb);
260
261             r = ((rs * ratio) >> 8) + ((rd * (255 - ratio)) >> 8);
262             g = ((gs * ratio) >> 8) + ((gd * (255 - ratio)) >> 8);
263             b = ((bs * ratio) >> 8) + ((bd * (255 - ratio)) >> 8);
264
265             if (tiled) {
266                 r = ((r * as) >> 8) + ((rd * (255 - as)) >> 8);
267                 g = ((g * as) >> 8) + ((gd * (255 - as)) >> 8);
268                 b = ((b * as) >> 8) + ((bd * (255 - as)) >> 8);
269             }
270
271             r = r & 0xff;
272             g = g & 0xff;
273             b = b & 0xff;
274
275             d[x+dx + (y+dy) * dst->w] = SET_ARGB(as, r, g, b);
276         }
277     }
278 }
279
280
281 static void BlurSourceAndMixTexture(struct NewImage *pic, struct NewImage *texture, struct TileInfo * textureti, UWORD ratio)
282 {
283     int     x, y, ytw, t1, t2, b1, b2, l1, l2, r1, r2;
284     UWORD   red, green, blue, alpha= 0, rs, gs, bs, as;
285     ULONG   rgb, argb;
286     int     width, w, height, ah, aw, xpos, ypos;
287     BOOL    tiled = FALSE;
288     ULONG  *raw, tw, th;
289
290     if (pic == NULL) return;
291     if (pic->data == NULL) return;
292
293     tw = pic->w;
294     if (textureti) tiled = TRUE;
295     th = pic->h;
296     raw = pic->data;
297     height = th;
298     width = tw;
299
300     if (raw)
301     {
302         for (y = 0; y < th; y++)
303         {
304             t1 = tw;
305             t2 = tw+tw;
306             b1 = tw;
307             b2 = tw+tw;
308             if (y == 0) t1 = t2 = 0;
309             else if (y == 1) t2 = t1;
310
311             if (y == (th-1)) b1 = b2 = 0;
312             else if (y == (th-2)) b2 = b1;
313
314             ytw = y*tw;
315
316             for (x = 0; x < tw; x++)
317             {
318                 r1 = 1;
319                 r2 = 2;
320                 l1 = 1;
321                 l2 = 2;
322
323                 if (x == 0) l1 = r1 = 0;
324                 else if (x == 1) l2 = l1;
325
326                 if (x == (tw-1)) r1 = r2 = 0;
327                 else if (x == (tw-2)) r2 = r1;
328
329                 rgb = raw[x+ytw];
330                 red = GET_R(rgb);
331                 green = GET_G(rgb);
332                 blue = GET_B(rgb);
333
334                 rgb = raw[x+ytw-t2];
335                 red += GET_R(rgb);
336                 green += GET_G(rgb);
337                 blue += GET_B(rgb);
338
339                 rgb = raw[x+ytw-l1-t1];
340                 red += GET_R(rgb);
341                 green += GET_G(rgb);
342                 blue += GET_B(rgb);
343
344                 rgb = raw[x+ytw-t1];
345                 red += GET_R(rgb);
346                 green += GET_G(rgb);
347                 blue += GET_B(rgb);
348
349                 rgb = raw[x+ytw-t1];
350                 red += GET_R(rgb);
351                 green += GET_G(rgb);
352                 blue += GET_B(rgb);
353
354                 rgb = raw[x+ytw-t1+r1];
355                 red += GET_R(rgb);
356                 green += GET_G(rgb);
357                 blue += GET_B(rgb);
358
359                 rgb = raw[x+ytw-l2];
360                 red += GET_R(rgb);
361                 green += GET_G(rgb);
362                 blue += GET_B(rgb);
363
364                 rgb = raw[x+ytw-l1];
365                 red += GET_R(rgb);
366                 green += GET_G(rgb);
367                 blue += GET_B(rgb);
368
369                 rgb = raw[x+ytw+r1];
370                 red += GET_R(rgb);
371                 green += GET_G(rgb);
372                 blue += GET_B(rgb);
373
374                 rgb = raw[x+ytw+r2];
375                 red += GET_R(rgb);
376                 green += GET_G(rgb);
377                 blue += GET_B(rgb);
378
379                 rgb = raw[x+ytw+b1-l1];
380                 red += GET_R(rgb);
381                 green += GET_G(rgb);
382                 blue += GET_B(rgb);
383
384                 rgb = raw[x+ytw+b1];
385                 red += GET_R(rgb);
386                 green += GET_G(rgb);
387                 blue += GET_B(rgb);
388
389                 rgb = raw[x+ytw+b1+r1];
390                 red += GET_R(rgb);
391                 green += GET_G(rgb);
392                 blue += GET_B(rgb);
393
394                 rgb = raw[x+ytw+b2];
395                 red += GET_R(rgb);
396                 green += GET_G(rgb);
397                 blue += GET_B(rgb);
398
399                 red = red/14;
400                 green = green/14;
401                 blue = blue/14;
402                 alpha = 255;
403
404                 if (tiled)
405                 {
406                     argb = raw[x+ytw];
407                     as = 255 - GET_A(texture->data[x + y * texture->w]);
408                     rs = GET_R(argb);
409                     gs = GET_G(argb);
410                     bs = GET_B(argb);
411
412                     red = ((rs * as) >> 8) + ((red * (255 - as)) >> 8);
413                     green = ((gs * as) >> 8) + ((green * (255 - as)) >> 8);
414                     blue = ((bs * as) >> 8) + ((blue * (255 - as)) >> 8);
415
416                     raw[x+ytw] = SET_ARGB(as, red, green, blue);
417
418                 }
419                 else
420                 {
421                     raw[x+ytw] = SET_ARGB(alpha, red, green, blue);
422                 }
423             }
424         }
425     }
426     if (ratio < 100)
427     {
428         if (texture)
429         {
430             ypos = 0;
431             while (height>0)
432             {
433                 ah = texture->h;
434                 if (ah > height) ah = height;
435                 xpos = 0;
436                 w = width;
437                 while (w>0)
438                 {
439                     aw = texture->w;
440                     if (aw > w) aw = w;
441                     MixImage(pic, texture, textureti, 255 - (2.55 * ratio), aw, ah, xpos, ypos);
442                     w -= aw;
443                     xpos += aw;
444                 }
445                 height -= ah;
446                 ypos += ah;
447             }
448         }
449     }
450 }
451
452 static void RenderBackgroundTiled(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti,
453         UWORD ratio, VOID (*TileImageToImageFunc)(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest))
454 {
455     struct NewImage *ni;
456
457     if (texture)
458     {
459         ni = NewImageContainer(pic->w, pic->h);
460         if (ni)
461         {
462             if (textureti)
463             {
464                 TileImageToImageFunc(texture, textureti, ni);
465                 BlurSourceAndMixTexture(pic, ni, textureti, ratio);
466             }
467             else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
468
469             DisposeImageContainer(ni);
470         }
471         else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
472     }
473     else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
474 }
475
476 static void DrawMapTileToRP(struct NewImage *src, struct RastPort *rp, UWORD _sx, UWORD _sy, UWORD _sw, UWORD _sh, UWORD _dx, UWORD _dy, UWORD _dw, UWORD _dh)
477 {
478
479     ULONG   dy, dx;
480     LONG    dh, height, dw, width;
481
482     if (src == NULL) return;
483     if (rp == NULL) return;
484
485     dh = _sh;
486     dy = _dy;
487     height = _dh;
488
489     if (!src->ok) return;
490
491     while (height > 0)
492     {
493         if ((height-dh)<0) dh = height;
494         height -= dh;
495         dw = _sw;
496         width = _dw;
497         dx = _dx;
498         while (width > 0)
499         {
500             if ((width-dw)<0) dw = width;
501             width -= dw;
502
503             if (src->mask)
504             {
505                 BltMaskBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xe0, (PLANEPTR) src->mask);  
506             }
507             else BltBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xc0);
508
509             dx += dw;
510         }
511         dy += dh;
512     }
513 }
514
515 /******************************************************************************/
516 /******************************************************************************/
517 /******************************************************************************/
518 /******************************************************************************/
519 /******************************************************************************/
520
521 void DrawPartImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y, UWORD sx, UWORD sy, UWORD sw, UWORD sh)
522 {
523     if (ni->ok)
524     {
525         if (ni->bitmap == NULL)
526         {
527             WritePixelArray(ni->data, sx, sy, ni->w*4, rp, x, y, sw, sh, RECTFMT_ARGB);
528         }
529         else
530         {
531             BltBitMapRastPort(ni->bitmap, sx, sy, rp, x, y, sw, sh, 0xc0);
532         }
533     }
534 }
535
536 void DrawPartToImage(struct NewImage *src, struct NewImage *dest, UWORD sx, UWORD sy, UWORD sw, UWORD sh, UWORD dx, UWORD dy)
537 {
538     UWORD   x, y;
539
540     for (y = 0; y < sh; y++)
541     {
542         for (x = 0; x < sw; x++)
543         {
544             dest->data[dx  + x + (dy + y) * dest->w] = src->data[sx + x + (sy + y) * src->w];
545         }
546     }
547 }
548
549 void RenderMenuBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
550 {
551     if (texture)
552     {
553         if (textureti) RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImage);
554         else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
555     }
556     else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
557 }
558
559 void RenderMenuBarBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
560 {
561     if (texture && textureti)
562     {
563
564         /* Fill the image with the center tile */
565         DrawTileToImage(texture, pic,
566                 textureti->TileLeft, textureti->TileTop,
567                 texture->w - textureti->TileLeft - textureti->TileRight, texture->h - textureti->TileBottom - textureti->TileTop,
568                 0, 0, pic->w, pic->h);
569
570         RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImageMenuBar);
571     }
572 }
573
574 void WriteAlphaPixelArray(struct NewImage *src, struct NewLUT8Image *dst, LONG sx, LONG sy, LONG dx, LONG dy, LONG w, LONG h)
575 {
576     ULONG  *s = src->data;
577     ULONG   argb;
578     UBYTE  *d = dst->data;
579     int     x, y;
580
581     for (y = 0; y < h; y++)
582     {
583         for (x = 0; x < w; x++)
584         {
585             argb = s[sx + x + (sy + y) * src->w];
586             d[dx + x + (dy + y) * dst->w] = GET_A(argb);
587         }
588     }
589 }
590
591 void  SetImageTint(struct NewImage *dst, UWORD ratio, ULONG argb)
592 {
593
594     ULONG  *d;
595     ULONG   rgb;
596     UWORD   r, g, b, w, h;
597     UBYTE   rs, gs, bs, rd, gd, bd;
598     int     x, y;
599
600     if (dst == NULL) return;
601    
602     d = dst->data;
603
604     w = dst->w;
605     h = dst->h;
606    
607     rs = (argb >> 16) & 0xff;
608     gs = (argb >> 8) & 0xff;
609     bs = argb & 0xff;
610    
611     for (y = 0; y < h; y++)
612     {
613         for (x = 0; x < w; x++)
614         {
615             rgb = d[x + y * w];
616             rd = GET_R(rgb);
617             gd = GET_G(rgb);
618             bd = GET_B(rgb);
619             r = ((rs * ratio) >> 8) + ((rd * (255 - ratio)) >> 8);
620             g = ((gs * ratio) >> 8) + ((gd * (255 - ratio)) >> 8);
621             b = ((bs * ratio) >> 8) + ((bd * (255 - ratio)) >> 8);
622
623             r = r & 0xff;
624             g = g & 0xff;
625             b = b & 0xff;
626
627             d[x + y * w] = SET_ARGB(255, r, g, b);
628         }
629     }
630 }
631
632 /* 
633  * offx - offset between start of ni and place where image should be sample from
634  * offy - offset between start of ni and place where image should be sample from
635  * x, y, w, h - coords in rastport rp
636  */
637 void HorizVertRepeatNewImage(struct NewImage *ni, ULONG color, UWORD offx, UWORD offy, struct RastPort *rp, UWORD x, UWORD y, WORD w, WORD h)
638 {
639     ULONG   ow, oh, sy, sx, dy, dx;
640     LONG    dh, height, dw, width;
641
642     if ((w <= 0) || (h <= 0)) return;
643
644     if (!ni->ok)
645     {
646         FillPixelArray(rp, x, y, w, h, color);
647         return;
648     }
649
650     ow = ni->w;
651     oh = ni->h;
652
653     sy = offy % oh;
654     dh = oh - sy;
655     height = h;
656     dy = y;
657     while (height > 0)
658     {
659         if ((height-dh)<0) dh = height;
660         height -= dh;
661
662         sx = offx % ow;
663         dw = ow - sx;
664         width = w;
665         dx = x;
666         while (width > 0)
667         {
668             if ((width-dw)<0) dw = width;
669             width -= dw;
670
671             BltNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, dx, dy, dw, dh);
672
673             dx += dw;
674             sx = 0;
675             dw = ow;
676         }
677         dy += dh;
678         sy = 0;
679         dh = oh;
680     }
681 }
682
683 /* NOTE: fill parameter is ignored, previously it was forcing a no-alpha blit, but
684    this is already handled in BltNewImageSubImageRastPort */
685 /* dh - destination height to which subimage will be scaled to */
686 LONG WriteTiledImageTitle(BOOL fill, struct Window *win,
687     struct RastPort *rp, struct NewImage *ni, LONG sx, LONG sy, LONG sw,
688     LONG sh, LONG xp, LONG yp, LONG dw, LONG dh)
689 {
690     int     w = dw;
691     int     x = xp;
692     int     ddw;
693
694     if (!ni->ok) return x;
695
696     if ((sw == 0) || (dw == 0)) return xp;
697
698     if (win)
699     {
700         if (x > win->Width) return xp;
701         if ((x + w) > win->Width) w = win->Width - x;
702     }
703
704     while (w > 0)
705     {
706         ddw = sw;
707         if (w < ddw) ddw = w;
708
709         BltScaleNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, x, yp, ddw, -1, -1, dh);
710
711         w -= ddw;
712         x += ddw;
713     }
714     return x;
715 }
716
717 /*
718  * dh - destination height to scale to, -1 to use subimage height
719  */
720 LONG WriteVerticalScaledTiledImageHorizontal(struct RastPort *rp, struct NewImage *ni, ULONG subimage,
721         LONG sx, LONG sw, LONG xp, LONG yp, LONG sh, LONG dw, LONG dh)
722 {
723     LONG w = dw;
724     LONG x = xp;
725     LONG ddw;
726
727     if (!ni->ok) return xp;
728
729     if ((sw == 0) || (dw == 0)) return xp;
730
731     while (w > 0)
732     {
733         ddw = sw;
734         if (w < ddw) ddw = w;
735
736         BltScaleNewImageSubImageRastPort(ni, 0, subimage, sx, 0, rp, x, yp, ddw, sh, -1, dh);
737
738         w -= ddw;
739         x += ddw;
740     }
741
742     return x;
743 }
744
745 LONG WriteTiledImageHorizontal(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sx, LONG sw, LONG xp, LONG yp, LONG dw)
746 {
747     return WriteVerticalScaledTiledImageHorizontal(rp, ni, subimage, sx, sw, xp, yp, -1, dw, -1);
748 }
749
750 LONG WriteTiledImageVertical(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sy, LONG sh, LONG xp, LONG yp, LONG dh)
751 {
752     int     h = dh;
753     int     y = yp;
754     int     ddh;
755
756     if (!ni->ok) return y;
757
758     if ((sh == 0) || (dh == 0)) return yp;
759
760     while (h > 0)
761     {
762         ddh = sh;
763         if (h < ddh) ddh = h;
764
765         BltNewImageSubImageRastPort(ni, subimage, 0, 0, sy, rp, xp, y, -1, ddh);
766
767         h -= ddh;
768         y += ddh;
769     }
770     return y;
771 }
772
773 struct myrgb
774 {
775     int red,green,blue;
776 };
777
778 void FillMemoryBufferRGBGradient(UBYTE * buf, LONG pen, LONG xt, LONG yt, LONG xb, LONG yb, LONG xp, LONG yp, LONG w, LONG h, ULONG start_rgb, ULONG end_rgb, LONG angle)
779 {
780     /* The basic idea of this algorithm is to calc the intersection between the
781     * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line starting
782     * at (x,y) (every pixel inside the rectangle) and angle angle with direction vector (vx,vy).
783     *
784     * Having the intersection point we then know the color of the pixel.
785     *
786     * TODO: Turn the algorithm into a incremental one
787     *       Remove the use of floating point variables
788     */
789     double rad = angle*M_PI/180;
790     double cosarc = cos(rad);
791     double sinarc = sin(rad);
792
793     struct myrgb startRGB,endRGB;
794
795     int diffR, diffG, diffB;
796
797     int r,t; /* some helper variables to short the code */
798     int l,y,c,x;
799     int y1; /* The intersection point */
800     int incr_y1; /* increment of y1 */
801     int xs,ys,xw,yw;
802     int xadd,ystart,yadd;
803 //    double vx = -cosarc;
804 //    double vy = sinarc;
805     int vx = (int)(-cosarc*0xff);
806     int vy = (int)(sinarc*0xff);
807     
808     int width = xb - xt + 1;
809     int height = yb - yt + 1;
810
811     if (buf == NULL) return;
812
813     startRGB.red = (start_rgb >> 16) & 0xff;
814     startRGB.green = (start_rgb >> 8) & 0xff;
815     startRGB.blue = start_rgb & 0xff;
816
817     endRGB.red = (end_rgb >> 16) & 0xff;
818     endRGB.green = (end_rgb >> 8) & 0xff;
819     endRGB.blue = end_rgb & 0xff;
820
821     diffR = endRGB.red - startRGB.red;
822     diffG = endRGB.green - startRGB.green;
823     diffB = endRGB.blue - startRGB.blue;
824
825     /* Normalize the angle */
826     if (angle < 0) angle = 360 - ((-angle)%360);
827     if (angle >= 0) angle = angle % 360;
828
829     if (angle <= 90 || (angle > 180 && angle <= 270))
830     {
831         /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
832         xs = 0;
833         ys = 0;
834         xw = width;
835         yw = height;
836     } else
837     {
838         /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
839         xs = 0;
840         ys = height;
841         xw = width;
842         yw = -height;
843     }
844                 
845     if (angle > 90 && angle <= 270)
846     {
847         /* for these angle we have y1 = height - y1. Instead of
848         *
849         *  y1 = height - (-vy*(yw*  xs -xw*  ys)         + yw*(vy*  x -vx*  y))        /(-yw*vx + xw*vy);
850         *
851         * we can write
852         *
853         *  y1 =          (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
854         *
855         * so height - y1 can be expressed with the normal formular adapting some parameters.
856         *
857         * Note that if one would exchanging startRGB/endRGB the values would only work
858         * for linear color gradients
859  */
860         xadd = -1;
861         yadd = -1;
862         ystart = height;
863
864         xs = -xs;
865         ys = -ys + height;
866     }
867     else
868     {
869         xadd = 1;
870         yadd = 1;
871         ystart = 0;
872     }
873
874     r = -vy*(yw*xs-xw*ys);
875     t = -yw*vx + xw*vy;
876
877     /* The formular as shown above is
878     *
879     *    y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
880     *
881     * We see that only yw*(vy*x-vx*y) changes during the loop.
882     *
883     * We write
884     *
885     *   Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
886     *   Next Pixel:    y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
887     *
888     *   t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
889     *
890     */
891
892     incr_y1 = yw*vy*xadd;
893     UBYTE *bufptr = buf;
894     for (l = 0, y = ystart + ((yp - yt)* yadd); l < h; l++, y+=yadd)
895     {
896
897         /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
898         * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
899         * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
900  * vx nothing is left, currently 9 bits are used for vx or vy */
901         int y1_mul_t_accu = r - yw*vx*y;
902
903
904        
905         for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x+=xadd)
906         {
907             int red,green,blue;
908
909             /* Calculate the intersection of two lines, this is not the fastet way to do but
910             * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
911             * and making it incremental)...update: it's now incremental and no FFP is used
912             * but it probably can be optimized more by removing some more of the divisions and
913      * further specialize the stuff here (use of three accus). */
914             /*      y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
915             y1 = y1_mul_t_accu / t;
916                                         
917             red = startRGB.red + (int)(diffR*y1/height);
918             green = startRGB.green + (int)(diffG*y1/height);
919             blue = startRGB.blue + (int)(diffB*y1/height);
920             /* By using full 32 bits this can be made faster as well */
921             *bufptr++ = red;
922             *bufptr++ = green;
923             *bufptr++ = blue;
924
925             y1_mul_t_accu += incr_y1;
926         }
927     }
928
929 }
930     
931 void FillPixelArrayGradient(LONG pen, BOOL tc, struct RastPort *rp, LONG xt, LONG yt, LONG xb, LONG yb, LONG xp, LONG yp, LONG w, LONG h, ULONG start_rgb, ULONG end_rgb, LONG angle, LONG dx, LONG dy)
932 {
933     UBYTE * buf = NULL;
934     
935     if ((w <= 0) || (h <= 0)) return;
936
937         /* By bringing building the gradient array in the same format as the RastPort BitMap a call
938         to WritePixelArray() can be made also faster */
939     buf = AllocVec(1 * yb * 3, 0);
940     
941     FillMemoryBufferRGBGradient(buf, pen, xt, yt, xb, yb, xp, yp, 1, yb, start_rgb, end_rgb, angle);
942
943     HorizRepeatBuffer(buf, dy, pen, tc, rp, xp, yp, w, h);
944
945     FreeVec(buf);
946 }
947
948 void HorizRepeatBuffer(UBYTE * buf, LONG offy, LONG pen, BOOL tc, struct RastPort *rp, LONG x, LONG y, LONG w, LONG h)
949 {
950     UBYTE * bufblit = NULL;
951     ULONG xi, yi;
952     ULONG idxd;
953     ULONG idxs;
954
955     if ((w <= 0) || (h <= 0)) return;
956     if (!tc)
957     {
958         if (pen != -1) SetAPen(rp, pen); else SetAPen(rp, 2);
959         RectFill(rp, x, y, x + w - 1, y + h - 1);
960         return;
961     }
962
963     /* By bringing building the gradient array in the same format as the RastPort BitMap a call
964        to WritePixelArray() can be made also faster */
965     bufblit = AllocVec(w * h * 3, MEMF_ANY);
966     
967     /* Copy one column buffer into blit buffer */
968     for (yi = 0; yi < h; yi++)
969     {
970         idxs = (offy + yi) * 3; /* source index */
971         idxd = yi * 3 * w; /* dest index */
972         for (xi = 0; xi < w; xi++)
973         {
974             /* Copy RGB pixel */
975             bufblit[idxd++] = buf[idxs + 0];
976             bufblit[idxd++] = buf[idxs + 1];
977             bufblit[idxd++] = buf[idxs + 2];
978         }
979     }
980     
981     WritePixelArray(bufblit, 0, 0, w * 3, rp, x, y, w, h, RECTFMT_RGB);
982
983     FreeVec(bufblit);
984 }
985
986 void TileMapToBitmap(struct NewImage *src, struct TileInfo *srcti, struct BitMap *map, UWORD dw, UWORD dh)
987 {
988     UWORD   y, h;
989
990     if (map == NULL) return;
991     if (src == NULL) return;
992     if (srcti == NULL) return;
993     y = 0;
994
995     h = src->h;
996
997     if ((srcti->TileTop + srcti->TileBottom) > dh) return;
998     if ((srcti->TileLeft + srcti->TileRight) > dw) return;
999
1000     struct RastPort *dest = CreateRastPort();
1001
1002     if (dest != NULL)
1003     {
1004         dest->BitMap = map;
1005
1006         DrawMapTileToRP(src, dest, 0, y, srcti->TileLeft, srcti->TileTop, 0 , 0, srcti->TileLeft, srcti->TileTop);
1007         DrawMapTileToRP(src, dest, 0, y + h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom, 0 , dh - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom);
1008         DrawMapTileToRP(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dw - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
1009         DrawMapTileToRP(src, dest, src->w - srcti->TileRight, y + h - srcti->TileBottom, srcti->TileRight, srcti->TileBottom, dw - srcti->TileRight , dh - srcti->TileBottom, srcti->TileRight, srcti->TileBottom);
1010
1011         DrawMapTileToRP(src, dest, srcti->TileLeft, y, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop, srcti->TileLeft, 0, dw - srcti->TileLeft - srcti->TileRight, srcti->TileTop);
1012         DrawMapTileToRP(src, dest, srcti->TileLeft, y + h - srcti->TileBottom, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileBottom, srcti->TileLeft, dh - srcti->TileBottom, dw - srcti->TileLeft - srcti->TileRight, srcti->TileBottom);
1013         DrawMapTileToRP(src, dest, 0, y + srcti->TileTop, srcti->TileLeft, h - srcti->TileBottom - srcti->TileTop, 0 , srcti->TileTop + 0, srcti->TileLeft, dh - srcti->TileTop - srcti->TileBottom - 0);
1014         DrawMapTileToRP(src, dest, src->w - srcti->TileRight, y + srcti->TileTop, srcti->TileRight,  h - srcti->TileBottom - srcti->TileTop, dw - srcti->TileRight, srcti->TileTop + 0, srcti->TileRight, dh - srcti->TileTop - srcti->TileBottom - 0);
1015         DrawMapTileToRP(src, dest, srcti->TileLeft, y + srcti->TileTop, src->w - srcti->TileLeft - srcti->TileRight, h - srcti->TileBottom - srcti->TileTop, srcti->TileLeft, srcti->TileTop + 0, dw - srcti->TileLeft - srcti->TileRight, dh - srcti->TileTop - srcti->TileBottom - 0);
1016         FreeRastPort(dest);
1017     }
1018 }
1019
1020 struct NewImage *GetImageFromRP(struct RastPort *rp, UWORD x, UWORD y, UWORD w, UWORD h)
1021 {
1022     struct NewImage *ni;
1023
1024     ni = NewImageContainer(w, h);
1025     if (ni)
1026     {
1027         ReadPixelArray(ni->data, 0, 0, w*4, rp, x, y, w, h, RECTFMT_ARGB);
1028     }
1029     return ni;
1030 }
1031
1032 void PutImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y) {
1033
1034     if (ni)
1035     {
1036         if (ni->data) WritePixelArray(ni->data, 0, 0, ni->w*4, rp, x, y, ni->w, ni->h, RECTFMT_ARGB);
1037         DisposeImageContainer(ni);
1038     }
1039 }
1040
1041 struct ShadeData
1042 {
1043     struct NewImage     *ni;
1044     UWORD               fact;
1045     /* RectList for UnLockBitMap */
1046     ULONG               rl_num;
1047     IPTR                  rl_next;
1048     struct Rectangle rl_rect;
1049 };
1050
1051 struct layerhookmsg
1052 {
1053     struct Layer *l;
1054 /*  struct Rectangle rect; (replaced by the next line!) */
1055     WORD MinX, MinY, MaxX, MaxY;
1056     LONG OffsetX, OffsetY;
1057 };
1058
1059 ULONG CalcShade(ULONG base, UWORD fact)
1060 {
1061     int     c0, c1, c2, c3;
1062
1063     c0 = (base >> 24) & 0xff;
1064     c1 = (base >> 16) & 0xff;
1065     c2 = (base >> 8) & 0xff;
1066     c3 = base & 0xff;
1067     c0 *= fact;
1068     c1 *= fact;
1069     c2 *= fact;
1070     c3 *= fact;
1071     c0 = c0 >> 8;
1072     c1 = c1 >> 8;
1073     c2 = c2 >> 8;
1074     c3 = c3 >> 8;
1075
1076     if (c0 > 255) c0 = 255;
1077     if (c1 > 255) c1 = 255;
1078     if (c2 > 255) c2 = 255;
1079     if (c3 > 255) c3 = 255;
1080
1081     return ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0);
1082 }
1083
1084 AROS_UFH3(void, RectShadeFunc,
1085     AROS_UFHA(struct Hook *        , h,      A0),
1086     AROS_UFHA(struct RastPort *    , rp,     A2),
1087     AROS_UFHA(struct layerhookmsg *, msg,    A1))
1088 {
1089     AROS_USERFUNC_INIT
1090
1091     APTR        bm_handle;
1092     ULONG       bm_bytesperrow;
1093     IPTR        bm_baseaddress;
1094
1095     int         px, py, x, y;
1096     UWORD       offy = 0;
1097
1098     ULONG       color;
1099     HIDDT_Color col;
1100
1101     struct ShadeData *data = h->h_Data;
1102
1103     bm_handle = LockBitMapTags(rp->BitMap,
1104                     LBMI_BYTESPERROW,   &bm_bytesperrow,
1105                     LBMI_BASEADDRESS,   &bm_baseaddress,
1106                     TAG_END);
1107
1108     if (msg->MinX == msg->MaxX)
1109     {
1110         x = msg->MinX % data->ni->w; 
1111         for (py = msg->MinY; py < msg->MaxY; py++)
1112         {
1113             y = (py - offy) % data->ni->h;
1114             color = CalcShade(data->ni->data[x + y * data->ni->w], data->fact);
1115             
1116             if (bm_handle)
1117             {
1118                 col.alpha = (HIDDT_ColComp)((color >> 16) & 0x0000FF00);
1119                 col.red = (HIDDT_ColComp)((color >> 8) & 0x0000FF00);
1120                 col.green = (HIDDT_ColComp)(color & 0x0000FF00);
1121                 col.blue = (HIDDT_ColComp)((color << 8) & 0x0000FF00);
1122
1123                 HIDD_BM_MapColor(HIDD_BM_OBJ(rp->BitMap), &col);
1124                 HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), msg->MinX, py, col.pixval);
1125             }
1126             else
1127             {
1128 #if (0)
1129                 if (IS_HIDD_BM(rp->BitMap))
1130                     HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), msg->MinX, py, color);
1131                 else
1132 #endif
1133                     WriteRGBPixel(rp, msg->MinX - rp->Layer->bounds.MinX - rp->Layer->Scroll_X, py - rp->Layer->bounds.MinY - rp->Layer->Scroll_Y, color);
1134             }
1135         }
1136     }
1137     else
1138     {
1139         y = (msg->MinY - offy) % data->ni->h;
1140         for (px = msg->MinX; px < msg->MaxX; px++) {
1141             x = px % data->ni->h;
1142             color = CalcShade(data->ni->data[x + y * data->ni->w], data->fact);
1143             
1144             if (bm_handle)
1145             {
1146                 col.alpha = (HIDDT_ColComp)((color >> 16) & 0x0000FF00);
1147                 col.red = (HIDDT_ColComp)((color >> 8) & 0x0000FF00);
1148                 col.green = (HIDDT_ColComp)(color & 0x0000FF00);
1149                 col.blue = (HIDDT_ColComp)((color << 8) & 0x0000FF00);
1150
1151                 HIDDT_Pixel pixel = HIDD_BM_MapColor(HIDD_BM_OBJ(rp->BitMap), &col);
1152                 HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), px, msg->MinY, pixel);
1153             }
1154             else
1155             {
1156 #if (0)
1157                 if (IS_HIDD_BM(rp->BitMap))
1158                     HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), px, msg->MinY, color);
1159                 else
1160 #endif
1161                     WriteRGBPixel(rp, px - rp->Layer->bounds.MinX - rp->Layer->Scroll_X, msg->MinY - rp->Layer->bounds.MinY - rp->Layer->Scroll_Y, color);
1162             }
1163         }
1164     }
1165
1166     if (bm_handle)
1167     {
1168         struct TagItem bm_ultags[3] =
1169         {
1170                 {UBMI_REALLYUNLOCK, TRUE                },
1171                 {UBMI_UPDATERECTS,  (IPTR)&data->rl_num },
1172                 {TAG_DONE, 0                            }
1173         };
1174
1175         data->rl_rect.MinX = msg->MinX;
1176         data->rl_rect.MinY = msg->MinY;
1177         data->rl_rect.MaxX = msg->MaxX;
1178         data->rl_rect.MaxY = msg->MaxY;
1179
1180         UnLockBitMapTagList(bm_handle, bm_ultags);
1181     }
1182     else
1183         UpdateBitMap(rp->BitMap, msg->MinX, msg->MinY, msg->MaxX - msg->MinX + 1, msg->MaxY - msg->MinY + 1);
1184
1185     AROS_USERFUNC_EXIT
1186 }
1187
1188 void ShadeLine(LONG pen, BOOL tc, BOOL usegradients, struct RastPort *rp, struct NewImage *ni, ULONG basecolor, UWORD fact, UWORD _offy, UWORD x0, UWORD y0, UWORD x1, UWORD y1)
1189 {
1190     ULONG   color;
1191
1192     if ((x1 < x0) || (y1 < y0)) return;
1193     if (!tc)
1194     {
1195         SetAPen(rp, pen);
1196         Move(rp, x0, y0);
1197         Draw(rp, x1, y1);
1198         return;
1199     }
1200     if (usegradients)
1201     {
1202         color = CalcShade(basecolor, fact);
1203         SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, color, TAG_DONE);
1204         Move(rp, x0, y0);
1205         Draw(rp, x1, y1);
1206     }
1207     else if (ni->ok)
1208     {
1209         struct ShadeData shadeParams;
1210         struct Hook      shadeHook;
1211         struct Rectangle shadeRect;
1212
1213         shadeRect.MinX = x0;
1214         shadeRect.MaxX = x1;
1215         shadeRect.MinY = y0;
1216         shadeRect.MaxY = y1;
1217
1218         shadeParams.ni = ni;
1219         shadeParams.fact = fact;
1220         shadeParams.rl_num = 1;
1221         shadeParams.rl_next = (IPTR)NULL;
1222
1223         shadeHook.h_Entry = (HOOKFUNC)AROS_ASMSYMNAME(RectShadeFunc);
1224         shadeHook.h_Data = &shadeParams;
1225
1226         DoHookClipRects(&shadeHook, rp, &shadeRect);
1227     }
1228     else
1229     {
1230         Move(rp, x0, y0);
1231         Draw(rp, x1, y1);
1232     }
1233 }
1234
1235 void DrawScaledStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp,
1236         WORD scaledwidth, WORD scaledheight)
1237 {
1238
1239     UWORD subimagecol = 0;
1240     UWORD subimagerow = 0;
1241     
1242     if (ni->ok)
1243     {
1244         switch(state)
1245         {
1246             case IDS_NORMAL:
1247                 break;
1248             case IDS_SELECTED:
1249                 subimagecol = 1;
1250                 break;
1251             case IDS_INACTIVENORMAL:
1252                 subimagecol = 2;
1253                 break;
1254         }
1255
1256         BltScaleNewImageSubImageRastPortSimple(ni, subimagecol, subimagerow, rp, xp, yp, scaledwidth, scaledheight);
1257     }
1258 }
1259
1260 void DrawStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp)
1261 {
1262     DrawScaledStatefulGadgetImageToRP(rp, ni, state, xp, yp, -1, -1);
1263 }