use consistant co-ords when calculating the offsets
[AROS.git] / workbench / c / Decoration / drawfuncs.c
blobde1cce68d1a53c9df257e37c176c410b92af467c
1 /*
2 Copyright © 2011-2013, The AROS Development Team.
3 $Id$
4 */
6 #include <aros/debug.h>
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>
17 #include <hidd/graphics.h>
19 #include <math.h>
21 #include "drawfuncs.h"
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
37 /* This function provides a number of ways to blit a NewImage onto RastPort. Please take great care when modifying it.
39 * The number of combinations of arguments is quite high. Please take time to understand it.
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
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)
56 ULONG subimagewidth = ni->w / ni->subimagescols;
57 ULONG subimageheight = ni->h / ni->subimagesrows;
59 if (subimageCol >= ni->subimagescols) return;
60 if (subimageRow >= ni->subimagesrows) return;
62 /* If source size not provided, use subimage size */
63 if (widthSrc < 0) widthSrc = (LONG)subimagewidth;
64 if (heightSrc < 0) heightSrc = (LONG)subimageheight;
66 /* If destination size not provided, use source */
67 if (widthDest < 0) widthDest = widthSrc;
68 if (heightDest < 0) heightDest = heightSrc;
70 /* If source and destination sizes do not match, scale */
71 if ((widthSrc != widthDest) || (heightSrc != heightDest))
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 */
77 ULONG * scaleddata = ScaleBuffer(srcptr, ni->w, widthSrc, heightSrc, widthDest, heightDest);
79 D(bug("[Decoration] SCALED %d,%d -> %d,%d!\n", widthSrc, heightSrc, widthDest, heightDest));
81 WritePixelArrayAlpha(scaleddata, 0, 0, widthDest * 4, destRP, xDest, yDest, widthDest, heightDest, 0xffffffff);
83 FreeVec(scaleddata);
85 else /* ((widthSrc != widthDest) || (heightSrc != heightDest)) */
87 /* Detect if image can be drawn using blitting instead of alpha draw */
88 if ((!ni->subimageinbm) || (!(ni->subimageinbm[subimageCol + (subimageRow * ni->subimagescols)])))
90 WritePixelArrayAlpha(ni->data, (subimagewidth * subimageCol) + xSrc ,
91 (subimageheight * subimageRow) + ySrc, ni->w * 4, destRP,
92 xDest, yDest, widthSrc, heightSrc, 0xffffffff);
94 else
96 /* LUT */
97 if (ni->bitmap != NULL)
99 if (ni->mask)
101 BltMaskBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
102 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
103 widthSrc, heightSrc, 0xe0, (PLANEPTR) ni->mask);
105 else
107 BltBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
108 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
109 widthSrc, heightSrc, 0xc0);
113 /* Truecolor */
114 if (ni->bitmap2 != NULL)
116 BltBitMapRastPort(ni->bitmap2, (subimagewidth * subimageCol) + xSrc ,
117 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
118 widthSrc, heightSrc, 0xc0);
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)
128 BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, xSrc, ySrc, destRP,
129 xDest, yDest, widthSrc, heightSrc, -1, -1);
132 static inline void BltNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
133 struct RastPort * destRP, LONG xDest, LONG yDest)
135 BltNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
136 xDest, yDest, -1, -1);
139 static inline void BltScaleNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
140 struct RastPort * destRP, LONG xDest, LONG yDest, LONG widthDest, LONG heightDest)
142 BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
143 xDest, yDest, -1, -1, widthDest, heightDest);
145 /* HELPER WRAPPERS */
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)
150 ULONG dy, dx;
151 LONG dh, height, dw, width;
153 if (src == NULL) return;
154 if (dest == NULL) return;
156 dh = _sh;
157 dy = _dy;
158 height = _dh;
160 while (height > 0)
162 if ((height-dh)<0) dh = height;
163 height -= dh;
164 dw = _sw;
165 width = _dw;
166 dx = _dx;
167 while (width > 0)
169 if ((width-dw)<0) dw = width;
170 width -= dw;
171 DrawPartToImage(src, dest, _sx, _sy, dw, dh, dx, dy);
172 dx += dw;
174 dy += dh;
178 static void TileImageToImageMenuBar(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
180 UWORD y, h;
182 if (dest == NULL) return;
183 if (src == NULL) return;
184 if (srcti == NULL) return;
185 y = 0;
187 h = src->h;
189 if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
190 if (srcti->TileRight > dest->w) return;
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);
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);
203 static void TileImageToImage(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
205 UWORD y, h;
207 if (dest == NULL) return;
208 if (src == NULL) return;
209 if (srcti == NULL) return;
210 y = 0;
212 h = src->h;
214 if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
215 if ((srcti->TileLeft + srcti->TileRight) > dest->w) return;
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);
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);
229 static void MixImage(struct NewImage *dst, struct NewImage *src, struct TileInfo *srcti, UWORD ratio, UWORD w, UWORD h, UWORD dx, UWORD dy)
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;
238 if (src == NULL) return;
239 if (dst == NULL) return;
241 s = src->data;
242 d = dst->data;
244 if (srcti) tiled = TRUE;
246 for (y = 0; y < h; y++)
248 for (x = 0; x < w; x++)
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];
257 rd = GET_R(rgb);
258 gd = GET_G(rgb);
259 bd = GET_B(rgb);
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);
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);
271 r = r & 0xff;
272 g = g & 0xff;
273 b = b & 0xff;
275 d[x+dx + (y+dy) * dst->w] = SET_ARGB(as, r, g, b);
281 static void BlurSourceAndMixTexture(struct NewImage *pic, struct NewImage *texture, struct TileInfo * textureti, UWORD ratio)
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;
290 if (pic == NULL) return;
291 if (pic->data == NULL) return;
293 tw = pic->w;
294 if (textureti) tiled = TRUE;
295 th = pic->h;
296 raw = pic->data;
297 height = th;
298 width = tw;
300 if (raw)
302 for (y = 0; y < th; y++)
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;
311 if (y == (th-1)) b1 = b2 = 0;
312 else if (y == (th-2)) b2 = b1;
314 ytw = y*tw;
316 for (x = 0; x < tw; x++)
318 r1 = 1;
319 r2 = 2;
320 l1 = 1;
321 l2 = 2;
323 if (x == 0) l1 = r1 = 0;
324 else if (x == 1) l2 = l1;
326 if (x == (tw-1)) r1 = r2 = 0;
327 else if (x == (tw-2)) r2 = r1;
329 rgb = raw[x+ytw];
330 red = GET_R(rgb);
331 green = GET_G(rgb);
332 blue = GET_B(rgb);
334 rgb = raw[x+ytw-t2];
335 red += GET_R(rgb);
336 green += GET_G(rgb);
337 blue += GET_B(rgb);
339 rgb = raw[x+ytw-l1-t1];
340 red += GET_R(rgb);
341 green += GET_G(rgb);
342 blue += GET_B(rgb);
344 rgb = raw[x+ytw-t1];
345 red += GET_R(rgb);
346 green += GET_G(rgb);
347 blue += GET_B(rgb);
349 rgb = raw[x+ytw-t1];
350 red += GET_R(rgb);
351 green += GET_G(rgb);
352 blue += GET_B(rgb);
354 rgb = raw[x+ytw-t1+r1];
355 red += GET_R(rgb);
356 green += GET_G(rgb);
357 blue += GET_B(rgb);
359 rgb = raw[x+ytw-l2];
360 red += GET_R(rgb);
361 green += GET_G(rgb);
362 blue += GET_B(rgb);
364 rgb = raw[x+ytw-l1];
365 red += GET_R(rgb);
366 green += GET_G(rgb);
367 blue += GET_B(rgb);
369 rgb = raw[x+ytw+r1];
370 red += GET_R(rgb);
371 green += GET_G(rgb);
372 blue += GET_B(rgb);
374 rgb = raw[x+ytw+r2];
375 red += GET_R(rgb);
376 green += GET_G(rgb);
377 blue += GET_B(rgb);
379 rgb = raw[x+ytw+b1-l1];
380 red += GET_R(rgb);
381 green += GET_G(rgb);
382 blue += GET_B(rgb);
384 rgb = raw[x+ytw+b1];
385 red += GET_R(rgb);
386 green += GET_G(rgb);
387 blue += GET_B(rgb);
389 rgb = raw[x+ytw+b1+r1];
390 red += GET_R(rgb);
391 green += GET_G(rgb);
392 blue += GET_B(rgb);
394 rgb = raw[x+ytw+b2];
395 red += GET_R(rgb);
396 green += GET_G(rgb);
397 blue += GET_B(rgb);
399 red = red/14;
400 green = green/14;
401 blue = blue/14;
402 alpha = 255;
404 if (tiled)
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);
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);
416 raw[x+ytw] = SET_ARGB(as, red, green, blue);
419 else
421 raw[x+ytw] = SET_ARGB(alpha, red, green, blue);
426 if (ratio < 100)
428 if (texture)
430 ypos = 0;
431 while (height>0)
433 ah = texture->h;
434 if (ah > height) ah = height;
435 xpos = 0;
436 w = width;
437 while (w>0)
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;
445 height -= ah;
446 ypos += ah;
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))
455 struct NewImage *ni;
457 if (texture)
459 ni = NewImageContainer(pic->w, pic->h);
460 if (ni)
462 if (textureti)
464 TileImageToImageFunc(texture, textureti, ni);
465 BlurSourceAndMixTexture(pic, ni, textureti, ratio);
467 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
469 DisposeImageContainer(ni);
471 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
473 else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
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)
479 ULONG dy, dx;
480 LONG dh, height, dw, width;
482 if (src == NULL) return;
483 if (rp == NULL) return;
485 dh = _sh;
486 dy = _dy;
487 height = _dh;
489 if (!src->ok) return;
491 while (height > 0)
493 if ((height-dh)<0) dh = height;
494 height -= dh;
495 dw = _sw;
496 width = _dw;
497 dx = _dx;
498 while (width > 0)
500 if ((width-dw)<0) dw = width;
501 width -= dw;
503 if (src->mask)
505 BltMaskBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xe0, (PLANEPTR) src->mask);
507 else BltBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xc0);
509 dx += dw;
511 dy += dh;
515 /******************************************************************************/
516 /******************************************************************************/
517 /******************************************************************************/
518 /******************************************************************************/
519 /******************************************************************************/
521 void DrawPartImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y, UWORD sx, UWORD sy, UWORD sw, UWORD sh)
523 if (ni->ok)
525 if (ni->bitmap == NULL)
527 WritePixelArray(ni->data, sx, sy, ni->w*4, rp, x, y, sw, sh, RECTFMT_ARGB);
529 else
531 BltBitMapRastPort(ni->bitmap, sx, sy, rp, x, y, sw, sh, 0xc0);
536 void DrawPartToImage(struct NewImage *src, struct NewImage *dest, UWORD sx, UWORD sy, UWORD sw, UWORD sh, UWORD dx, UWORD dy)
538 UWORD x, y;
540 for (y = 0; y < sh; y++)
542 for (x = 0; x < sw; x++)
544 dest->data[dx + x + (dy + y) * dest->w] = src->data[sx + x + (sy + y) * src->w];
549 void RenderMenuBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
551 if (texture)
553 if (textureti) RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImage);
554 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
556 else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
559 void RenderMenuBarBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
561 if (texture && textureti)
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);
570 RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImageMenuBar);
574 void WriteAlphaPixelArray(struct NewImage *src, struct NewLUT8Image *dst, LONG sx, LONG sy, LONG dx, LONG dy, LONG w, LONG h)
576 ULONG *s = src->data;
577 ULONG argb;
578 UBYTE *d = dst->data;
579 int x, y;
581 for (y = 0; y < h; y++)
583 for (x = 0; x < w; x++)
585 argb = s[sx + x + (sy + y) * src->w];
586 d[dx + x + (dy + y) * dst->w] = GET_A(argb);
591 void SetImageTint(struct NewImage *dst, UWORD ratio, ULONG argb)
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;
600 if (dst == NULL) return;
602 d = dst->data;
604 w = dst->w;
605 h = dst->h;
607 rs = (argb >> 16) & 0xff;
608 gs = (argb >> 8) & 0xff;
609 bs = argb & 0xff;
611 for (y = 0; y < h; y++)
613 for (x = 0; x < w; x++)
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);
623 r = r & 0xff;
624 g = g & 0xff;
625 b = b & 0xff;
627 d[x + y * w] = SET_ARGB(255, r, g, b);
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
637 void HorizVertRepeatNewImage(struct NewImage *ni, ULONG color, UWORD offx, UWORD offy, struct RastPort *rp, UWORD x, UWORD y, WORD w, WORD h)
639 ULONG ow, oh, sy, sx, dy, dx;
640 LONG dh, height, dw, width;
642 if ((w <= 0) || (h <= 0)) return;
644 if (!ni->ok)
646 FillPixelArray(rp, x, y, w, h, color);
647 return;
650 ow = ni->w;
651 oh = ni->h;
653 sy = offy % oh;
654 dh = oh - sy;
655 height = h;
656 dy = y;
657 while (height > 0)
659 if ((height-dh)<0) dh = height;
660 height -= dh;
662 sx = offx % ow;
663 dw = ow - sx;
664 width = w;
665 dx = x;
666 while (width > 0)
668 if ((width-dw)<0) dw = width;
669 width -= dw;
671 BltNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, dx, dy, dw, dh);
673 dx += dw;
674 sx = 0;
675 dw = ow;
677 dy += dh;
678 sy = 0;
679 dh = oh;
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)
690 int w = dw;
691 int x = xp;
692 int ddw;
694 if (!ni->ok) return x;
696 if ((sw == 0) || (dw == 0)) return xp;
698 if (win)
700 if (x > win->Width) return xp;
701 if ((x + w) > win->Width) w = win->Width - x;
704 while (w > 0)
706 ddw = sw;
707 if (w < ddw) ddw = w;
709 BltScaleNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, x, yp, ddw, -1, -1, dh);
711 w -= ddw;
712 x += ddw;
714 return x;
718 * dh - destination height to scale to, -1 to use subimage height
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)
723 LONG w = dw;
724 LONG x = xp;
725 LONG ddw;
727 if (!ni->ok) return xp;
729 if ((sw == 0) || (dw == 0)) return xp;
731 while (w > 0)
733 ddw = sw;
734 if (w < ddw) ddw = w;
736 BltScaleNewImageSubImageRastPort(ni, 0, subimage, sx, 0, rp, x, yp, ddw, sh, -1, dh);
738 w -= ddw;
739 x += ddw;
742 return x;
745 LONG WriteTiledImageHorizontal(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sx, LONG sw, LONG xp, LONG yp, LONG dw)
747 return WriteVerticalScaledTiledImageHorizontal(rp, ni, subimage, sx, sw, xp, yp, -1, dw, -1);
750 LONG WriteTiledImageVertical(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sy, LONG sh, LONG xp, LONG yp, LONG dh)
752 int h = dh;
753 int y = yp;
754 int ddh;
756 if (!ni->ok) return y;
758 if ((sh == 0) || (dh == 0)) return yp;
760 while (h > 0)
762 ddh = sh;
763 if (h < ddh) ddh = h;
765 BltNewImageSubImageRastPort(ni, subimage, 0, 0, sy, rp, xp, y, -1, ddh);
767 h -= ddh;
768 y += ddh;
770 return y;
773 struct myrgb
775 int red,green,blue;
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)
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).
784 * Having the intersection point we then know the color of the pixel.
786 * TODO: Turn the algorithm into a incremental one
787 * Remove the use of floating point variables
789 double rad = angle*M_PI/180;
790 double cosarc = cos(rad);
791 double sinarc = sin(rad);
793 struct myrgb startRGB,endRGB;
795 int diffR, diffG, diffB;
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);
808 int width = xb - xt + 1;
809 int height = yb - yt + 1;
811 if (buf == NULL) return;
813 startRGB.red = (start_rgb >> 16) & 0xff;
814 startRGB.green = (start_rgb >> 8) & 0xff;
815 startRGB.blue = start_rgb & 0xff;
817 endRGB.red = (end_rgb >> 16) & 0xff;
818 endRGB.green = (end_rgb >> 8) & 0xff;
819 endRGB.blue = end_rgb & 0xff;
821 diffR = endRGB.red - startRGB.red;
822 diffG = endRGB.green - startRGB.green;
823 diffB = endRGB.blue - startRGB.blue;
825 /* Normalize the angle */
826 if (angle < 0) angle = 360 - ((-angle)%360);
827 if (angle >= 0) angle = angle % 360;
829 if (angle <= 90 || (angle > 180 && angle <= 270))
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
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;
845 if (angle > 90 && angle <= 270)
847 /* for these angle we have y1 = height - y1. Instead of
849 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
851 * we can write
853 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
855 * so height - y1 can be expressed with the normal formular adapting some parameters.
857 * Note that if one would exchanging startRGB/endRGB the values would only work
858 * for linear color gradients
860 xadd = -1;
861 yadd = -1;
862 ystart = height;
864 xs = -xs;
865 ys = -ys + height;
867 else
869 xadd = 1;
870 yadd = 1;
871 ystart = 0;
874 r = -vy*(yw*xs-xw*ys);
875 t = -yw*vx + xw*vy;
877 /* The formular as shown above is
879 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
881 * We see that only yw*(vy*x-vx*y) changes during the loop.
883 * We write
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
888 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
892 incr_y1 = yw*vy*xadd;
893 UBYTE *bufptr = buf;
894 for (l = 0, y = ystart + ((yp - yt)* yadd); l < h; l++, y+=yadd)
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;
905 for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x+=xadd)
907 int red,green,blue;
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;
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;
925 y1_mul_t_accu += incr_y1;
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)
933 UBYTE * buf = NULL;
935 if ((w <= 0) || (h <= 0)) return;
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);
941 FillMemoryBufferRGBGradient(buf, pen, xt, yt, xb, yb, xp, yp, 1, yb, start_rgb, end_rgb, angle);
943 HorizRepeatBuffer(buf, dy, pen, tc, rp, xp, yp, w, h);
945 FreeVec(buf);
948 void HorizRepeatBuffer(UBYTE * buf, LONG offy, LONG pen, BOOL tc, struct RastPort *rp, LONG x, LONG y, LONG w, LONG h)
950 UBYTE * bufblit = NULL;
951 ULONG xi, yi;
952 ULONG idxd;
953 ULONG idxs;
955 if ((w <= 0) || (h <= 0)) return;
956 if (!tc)
958 if (pen != -1) SetAPen(rp, pen); else SetAPen(rp, 2);
959 RectFill(rp, x, y, x + w - 1, y + h - 1);
960 return;
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);
967 /* Copy one column buffer into blit buffer */
968 for (yi = 0; yi < h; yi++)
970 idxs = (offy + yi) * 3; /* source index */
971 idxd = yi * 3 * w; /* dest index */
972 for (xi = 0; xi < w; xi++)
974 /* Copy RGB pixel */
975 bufblit[idxd++] = buf[idxs + 0];
976 bufblit[idxd++] = buf[idxs + 1];
977 bufblit[idxd++] = buf[idxs + 2];
981 WritePixelArray(bufblit, 0, 0, w * 3, rp, x, y, w, h, RECTFMT_RGB);
983 FreeVec(bufblit);
986 void TileMapToBitmap(struct NewImage *src, struct TileInfo *srcti, struct BitMap *map, UWORD dw, UWORD dh)
988 UWORD y, h;
990 if (map == NULL) return;
991 if (src == NULL) return;
992 if (srcti == NULL) return;
993 y = 0;
995 h = src->h;
997 if ((srcti->TileTop + srcti->TileBottom) > dh) return;
998 if ((srcti->TileLeft + srcti->TileRight) > dw) return;
1000 struct RastPort *dest = CreateRastPort();
1002 if (dest != NULL)
1004 dest->BitMap = map;
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);
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);
1020 struct NewImage *GetImageFromRP(struct RastPort *rp, UWORD x, UWORD y, UWORD w, UWORD h)
1022 struct NewImage *ni;
1024 ni = NewImageContainer(w, h);
1025 if (ni)
1027 ReadPixelArray(ni->data, 0, 0, w*4, rp, x, y, w, h, RECTFMT_ARGB);
1029 return ni;
1032 void PutImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y) {
1034 if (ni)
1036 if (ni->data) WritePixelArray(ni->data, 0, 0, ni->w*4, rp, x, y, ni->w, ni->h, RECTFMT_ARGB);
1037 DisposeImageContainer(ni);
1041 struct ShadeData
1043 struct NewImage *ni;
1044 UWORD fact;
1045 /* RectList for UnLockBitMap */
1046 ULONG rl_num;
1047 IPTR rl_next;
1048 struct Rectangle rl_rect;
1051 struct layerhookmsg
1053 struct Layer *l;
1054 /* struct Rectangle rect; (replaced by the next line!) */
1055 WORD MinX, MinY, MaxX, MaxY;
1056 LONG OffsetX, OffsetY;
1059 ULONG CalcShade(ULONG base, UWORD fact)
1061 int c0, c1, c2, c3;
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;
1076 if (c0 > 255) c0 = 255;
1077 if (c1 > 255) c1 = 255;
1078 if (c2 > 255) c2 = 255;
1079 if (c3 > 255) c3 = 255;
1081 return ((c3 << 24) | (c2 << 16) | (c1 << 8) | c0);
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))
1089 AROS_USERFUNC_INIT
1091 APTR bm_handle;
1092 ULONG bm_bytesperrow;
1093 IPTR bm_baseaddress;
1095 int px, py, x, y;
1096 UWORD offy = 0;
1098 ULONG color;
1099 HIDDT_Color col;
1101 struct ShadeData *data = h->h_Data;
1103 bm_handle = LockBitMapTags(rp->BitMap,
1104 LBMI_BYTESPERROW, &bm_bytesperrow,
1105 LBMI_BASEADDRESS, &bm_baseaddress,
1106 TAG_END);
1108 if (msg->MinX == msg->MaxX)
1110 x = msg->OffsetX % data->ni->w;
1111 for (py = msg->MinY; py < (msg->MaxY + 1); py++)
1113 y = (py + msg->OffsetY - msg->MinY - offy) % data->ni->h;
1114 color = CalcShade(data->ni->data[x + y * data->ni->w], data->fact);
1116 if (bm_handle)
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);
1123 HIDD_BM_MapColor(HIDD_BM_OBJ(rp->BitMap), &col);
1124 HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), msg->MinX, py, col.pixval);
1126 else
1128 WriteRGBPixel(rp, msg->OffsetX, py + msg->OffsetY - msg->MinY, color);
1132 else
1134 y = (msg->OffsetY - offy) % data->ni->h;
1135 for (px = msg->MinX; px < (msg->MaxX + 1); px++) {
1136 x = (px + msg->OffsetX - msg->MinX) % data->ni->h;
1137 color = CalcShade(data->ni->data[x + y * data->ni->w], data->fact);
1139 if (bm_handle)
1141 col.alpha = (HIDDT_ColComp)((color >> 16) & 0x0000FF00);
1142 col.red = (HIDDT_ColComp)((color >> 8) & 0x0000FF00);
1143 col.green = (HIDDT_ColComp)(color & 0x0000FF00);
1144 col.blue = (HIDDT_ColComp)((color << 8) & 0x0000FF00);
1146 HIDDT_Pixel pixel = HIDD_BM_MapColor(HIDD_BM_OBJ(rp->BitMap), &col);
1147 HIDD_BM_PutPixel(HIDD_BM_OBJ(rp->BitMap), px, msg->MinY, pixel);
1149 else
1151 WriteRGBPixel(rp, px + msg->OffsetX - msg->MinX, msg->OffsetY, color);
1156 if (bm_handle)
1158 struct TagItem bm_ultags[3] =
1160 {UBMI_REALLYUNLOCK, TRUE },
1161 {UBMI_UPDATERECTS, (IPTR)&data->rl_num },
1162 {TAG_DONE, 0 }
1165 data->rl_rect.MinX = msg->MinX;
1166 data->rl_rect.MinY = msg->MinY;
1167 data->rl_rect.MaxX = msg->MaxX;
1168 data->rl_rect.MaxY = msg->MaxY;
1170 UnLockBitMapTagList(bm_handle, bm_ultags);
1172 else
1173 UpdateBitMap(rp->BitMap, msg->MinX, msg->MinY, msg->MaxX - msg->MinX + 1, msg->MaxY - msg->MinY + 1);
1175 AROS_USERFUNC_EXIT
1178 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)
1180 ULONG color;
1182 if ((x1 < x0) || (y1 < y0)) return;
1183 if (!tc)
1185 SetAPen(rp, pen);
1186 Move(rp, x0, y0);
1187 Draw(rp, x1, y1);
1188 return;
1190 if (usegradients)
1192 color = CalcShade(basecolor, fact);
1193 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, color, TAG_DONE);
1194 Move(rp, x0, y0);
1195 Draw(rp, x1, y1);
1197 else if (ni->ok)
1199 struct ShadeData shadeParams;
1200 struct Hook shadeHook;
1201 struct Rectangle shadeRect;
1203 shadeRect.MinX = x0;
1204 shadeRect.MaxX = x1;
1205 shadeRect.MinY = y0;
1206 shadeRect.MaxY = y1;
1208 shadeParams.ni = ni;
1209 shadeParams.fact = fact;
1210 shadeParams.rl_num = 1;
1211 shadeParams.rl_next = (IPTR)NULL;
1213 shadeHook.h_Entry = (HOOKFUNC)AROS_ASMSYMNAME(RectShadeFunc);
1214 shadeHook.h_Data = &shadeParams;
1216 DoHookClipRects(&shadeHook, rp, &shadeRect);
1218 else
1220 Move(rp, x0, y0);
1221 Draw(rp, x1, y1);
1225 void DrawScaledStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp,
1226 WORD scaledwidth, WORD scaledheight)
1229 UWORD subimagecol = 0;
1230 UWORD subimagerow = 0;
1232 if (ni->ok)
1234 switch(state)
1236 case IDS_NORMAL:
1237 break;
1238 case IDS_SELECTED:
1239 subimagecol = 1;
1240 break;
1241 case IDS_INACTIVENORMAL:
1242 subimagecol = 2;
1243 break;
1246 BltScaleNewImageSubImageRastPortSimple(ni, subimagecol, subimagerow, rp, xp, yp, scaledwidth, scaledheight);
1250 void DrawStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp)
1252 DrawScaledStatefulGadgetImageToRP(rp, ni, state, xp, yp, -1, -1);