- Allow menu highlight colour to be configured through an ARGB hex value in
[AROS.git] / workbench / c / Decoration / drawfuncs.c
blobfac7682d1c9b98877a7e33a9d7f59939d2ea85c6
1 /*
2 Copyright © 2011, The AROS Development Team.
3 $Id$
4 */
6 #include <intuition/imageclass.h>
7 #include <graphics/rpattr.h>
8 #include <libraries/cybergraphics.h>
9 #include <proto/arossupport.h>
10 #include <proto/graphics.h>
11 #include <proto/cybergraphics.h>
12 #include <proto/exec.h>
13 #include <aros/debug.h>
15 #include <math.h>
17 #include "drawfuncs.h"
19 #if AROS_BIG_ENDIAN
20 #define GET_A(rgb) ((rgb >> 24) & 0xff)
21 #define GET_R(rgb) ((rgb >> 16) & 0xff)
22 #define GET_G(rgb) ((rgb >> 8) & 0xff)
23 #define GET_B(rgb) (rgb & 0xff)
24 #define SET_ARGB(a, r, g, b) a << 24 | r << 16 | g << 8 | b
25 #else
26 #define GET_A(rgb) (rgb & 0xff)
27 #define GET_R(rgb) ((rgb >> 8) & 0xff)
28 #define GET_G(rgb) ((rgb >> 16) & 0xff)
29 #define GET_B(rgb) ((rgb >> 24) & 0xff)
30 #define SET_ARGB(a, r, g, b) b << 24 | g << 16 | r << 8 | a
31 #endif
33 /* This function provides a number of ways to blit a NewImage onto RastPort. Please take great care when modifying it.
35 * The number of combinations of arguments is quite high. Please take time to understand it.
37 * Arguments:
38 * ni - a NewImage that is to be blitted
39 * subimageCol, subimageRow - define the initial read offset in source image based on assumption that image contains
40 * a number of subimages drawn in rows or columns
41 * xSrc, ySrc - define additional read offset in the source image subimage
42 * destRP - destination RastPort to blit the image to
43 * xDest, yDest - coordinates on the destination RastPort to where the imatge will be blitted
44 * widthSrc, heightSrc - width/height of region to be read from, if -1 then use the width/height of subimage
45 * widthDest, heightDest - width/height of blit on destination RastPort, if -1 then use widthSrc/heightSrc
48 static void BltScaleNewImageSubImageRastPort(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
49 LONG xSrc, LONG ySrc, struct RastPort * destRP, LONG xDest, LONG yDest,
50 LONG widthSrc, LONG heightSrc, LONG widthDest, LONG heightDest)
52 ULONG subimagewidth = ni->w / ni->subimagescols;
53 ULONG subimageheight = ni->h / ni->subimagesrows;
55 if (subimageCol >= ni->subimagescols) return;
56 if (subimageRow >= ni->subimagesrows) return;
58 /* If source size not provided, use subimage size */
59 if (widthSrc < 0) widthSrc = (LONG)subimagewidth;
60 if (heightSrc < 0) heightSrc = (LONG)subimageheight;
62 /* If destination size not provided, use source */
63 if (widthDest < 0) widthDest = widthSrc;
64 if (heightDest < 0) heightDest = heightSrc;
66 /* If source and destination sizes do not match, scale */
67 if ((widthSrc != widthDest) || (heightSrc != heightDest))
69 /* FIXME: The scaled blitting needs similar optimized code paths as non-scaled */
70 ULONG * srcptr = (ni->data) + (((subimageheight * subimageRow) + ySrc) * ni->w) +
71 ((subimagewidth * subimageCol) + xSrc); /* Go to (0,0) of source rect */
73 ULONG * scaleddata = ScaleBuffer(srcptr, ni->w, widthSrc, heightSrc, widthDest, heightDest);
75 D(bug("[Decoration] SCALED %d,%d -> %d,%d!\n", widthSrc, heightSrc, widthDest, heightDest));
77 WritePixelArrayAlpha(scaleddata, 0, 0, widthDest * 4, destRP, xDest, yDest, widthDest, heightDest, 0xffffffff);
79 FreeVec(scaleddata);
81 else /* ((widthSrc != widthDest) || (heightSrc != heightDest)) */
83 /* Detect if image can be drawn using blitting instead of alpha draw */
84 if ((!ni->subimageinbm) || (!(ni->subimageinbm[subimageCol + (subimageRow * ni->subimagescols)])))
86 WritePixelArrayAlpha(ni->data, (subimagewidth * subimageCol) + xSrc ,
87 (subimageheight * subimageRow) + ySrc, ni->w * 4, destRP,
88 xDest, yDest, widthSrc, heightSrc, 0xffffffff);
90 else
92 /* LUT */
93 if (ni->bitmap != NULL)
95 if (ni->mask)
97 BltMaskBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
98 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
99 widthSrc, heightSrc, 0xe0, (PLANEPTR) ni->mask);
101 else
103 BltBitMapRastPort(ni->bitmap, (subimagewidth * subimageCol) + xSrc ,
104 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
105 widthSrc, heightSrc, 0xc0);
109 /* Truecolor */
110 if (ni->bitmap2 != NULL)
112 BltBitMapRastPort(ni->bitmap2, (subimagewidth * subimageCol) + xSrc ,
113 (subimageheight * subimageRow) + ySrc, destRP, xDest, yDest,
114 widthSrc, heightSrc, 0xc0);
120 /* HELPER WRAPPERS */
121 static inline void BltNewImageSubImageRastPort(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
122 LONG xSrc, LONG ySrc, struct RastPort * destRP, LONG xDest, LONG yDest, LONG widthSrc, LONG heightSrc)
124 BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, xSrc, ySrc, destRP,
125 xDest, yDest, widthSrc, heightSrc, -1, -1);
128 static inline void BltNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
129 struct RastPort * destRP, LONG xDest, LONG yDest)
131 BltNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
132 xDest, yDest, -1, -1);
135 static inline void BltScaleNewImageSubImageRastPortSimple(struct NewImage * ni, ULONG subimageCol, ULONG subimageRow,
136 struct RastPort * destRP, LONG xDest, LONG yDest, LONG widthDest, LONG heightDest)
138 BltScaleNewImageSubImageRastPort(ni, subimageCol, subimageRow, 0, 0, destRP,
139 xDest, yDest, -1, -1, widthDest, heightDest);
141 /* HELPER WRAPPERS */
143 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)
146 ULONG dy, dx;
147 LONG dh, height, dw, width;
149 if (src == NULL) return;
150 if (dest == NULL) return;
152 dh = _sh;
153 dy = _dy;
154 height = _dh;
156 while (height > 0)
158 if ((height-dh)<0) dh = height;
159 height -= dh;
160 dw = _sw;
161 width = _dw;
162 dx = _dx;
163 while (width > 0)
165 if ((width-dw)<0) dw = width;
166 width -= dw;
167 DrawPartToImage(src, dest, _sx, _sy, dw, dh, dx, dy);
168 dx += dw;
170 dy += dh;
174 static void TileImageToImageMenuBar(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
176 UWORD y, h;
178 if (dest == NULL) return;
179 if (src == NULL) return;
180 if (srcti == NULL) return;
181 y = 0;
183 h = src->h;
185 if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
186 if (srcti->TileRight > dest->w) return;
188 DrawTileToImage(src, dest, srcti->TileLeft, y, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop, 0, 0, dest->w - srcti->TileRight, srcti->TileTop);
189 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);
190 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);
193 DrawTileToImage(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dest->w - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
194 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);
195 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);
199 static void TileImageToImage(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest)
201 UWORD y, h;
203 if (dest == NULL) return;
204 if (src == NULL) return;
205 if (srcti == NULL) return;
206 y = 0;
208 h = src->h;
210 if ((srcti->TileTop + srcti->TileBottom) > dest->h) return;
211 if ((srcti->TileLeft + srcti->TileRight) > dest->w) return;
213 DrawTileToImage(src, dest, 0, y, srcti->TileLeft, srcti->TileTop, 0 , 0, srcti->TileLeft, srcti->TileTop);
214 DrawTileToImage(src, dest, 0, y + h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom, 0 , dest->h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom);
215 DrawTileToImage(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dest->w - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
216 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);
218 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);
219 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);
220 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);
221 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);
222 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);
225 static void MixImage(struct NewImage *dst, struct NewImage *src, struct TileInfo *srcti, UWORD ratio, UWORD w, UWORD h, UWORD dx, UWORD dy)
227 ULONG *s, *d;
228 ULONG rgba, rgb;
229 UWORD r, g, b;
230 UBYTE as, rs, gs, bs, rd, gd, bd;
231 BOOL tiled = FALSE;
232 int x, y;
234 if (src == NULL) return;
235 if (dst == NULL) return;
237 s = src->data;
238 d = dst->data;
240 if (srcti) tiled = TRUE;
242 for (y = 0; y < h; y++)
244 for (x = 0; x < w; x++)
246 rgba = s[x+y*src->w];
247 as = GET_A(rgba);
248 rs = GET_R(rgba);
249 gs = GET_G(rgba);
250 bs = GET_B(rgba);
251 rgb = d[x+dx + (y+dy) * dst->w];
253 rd = GET_R(rgb);
254 gd = GET_G(rgb);
255 bd = GET_B(rgb);
257 r = ((rs * ratio) >> 8) + ((rd * (255 - ratio)) >> 8);
258 g = ((gs * ratio) >> 8) + ((gd * (255 - ratio)) >> 8);
259 b = ((bs * ratio) >> 8) + ((bd * (255 - ratio)) >> 8);
261 if (tiled) {
262 r = ((r * as) >> 8) + ((rd * (255 - as)) >> 8);
263 g = ((g * as) >> 8) + ((gd * (255 - as)) >> 8);
264 b = ((b * as) >> 8) + ((bd * (255 - as)) >> 8);
267 r = r & 0xff;
268 g = g & 0xff;
269 b = b & 0xff;
271 d[x+dx + (y+dy) * dst->w] = SET_ARGB(as, r, g, b);
277 static void BlurSourceAndMixTexture(struct NewImage *pic, struct NewImage *texture, struct TileInfo * textureti, UWORD ratio)
279 int x, y, ytw, t1, t2, b1, b2, l1, l2, r1, r2;
280 UWORD red, green, blue, alpha= 0, rs, gs, bs, as;
281 ULONG rgb, argb;
282 int width, w, height, ah, aw, xpos, ypos;
283 BOOL tiled = FALSE;
284 ULONG *raw, tw, th;
286 if (pic == NULL) return;
287 if (pic->data == NULL) return;
289 tw = pic->w;
290 if (textureti) tiled = TRUE;
291 th = pic->h;
292 raw = pic->data;
293 height = th;
294 width = tw;
296 if (raw)
298 for (y = 0; y < th; y++)
300 t1 = tw;
301 t2 = tw+tw;
302 b1 = tw;
303 b2 = tw+tw;
304 if (y == 0) t1 = t2 = 0;
305 else if (y == 1) t2 = t1;
307 if (y == (th-1)) b1 = b2 = 0;
308 else if (y == (th-2)) b2 = b1;
310 ytw = y*tw;
312 for (x = 0; x < tw; x++)
314 r1 = 1;
315 r2 = 2;
316 l1 = 1;
317 l2 = 2;
319 if (x == 0) l1 = r1 = 0;
320 else if (x == 1) l2 = l1;
322 if (x == (tw-1)) r1 = r2 = 0;
323 else if (x == (tw-2)) r2 = r1;
325 rgb = raw[x+ytw];
326 red = GET_R(rgb);
327 green = GET_G(rgb);
328 blue = GET_B(rgb);
330 rgb = raw[x+ytw-t2];
331 red += GET_R(rgb);
332 green += GET_G(rgb);
333 blue += GET_B(rgb);
335 rgb = raw[x+ytw-l1-t1];
336 red += GET_R(rgb);
337 green += GET_G(rgb);
338 blue += GET_B(rgb);
340 rgb = raw[x+ytw-t1];
341 red += GET_R(rgb);
342 green += GET_G(rgb);
343 blue += GET_B(rgb);
345 rgb = raw[x+ytw-t1];
346 red += GET_R(rgb);
347 green += GET_G(rgb);
348 blue += GET_B(rgb);
350 rgb = raw[x+ytw-t1+r1];
351 red += GET_R(rgb);
352 green += GET_G(rgb);
353 blue += GET_B(rgb);
355 rgb = raw[x+ytw-l2];
356 red += GET_R(rgb);
357 green += GET_G(rgb);
358 blue += GET_B(rgb);
360 rgb = raw[x+ytw-l1];
361 red += GET_R(rgb);
362 green += GET_G(rgb);
363 blue += GET_B(rgb);
365 rgb = raw[x+ytw+r1];
366 red += GET_R(rgb);
367 green += GET_G(rgb);
368 blue += GET_B(rgb);
370 rgb = raw[x+ytw+r2];
371 red += GET_R(rgb);
372 green += GET_G(rgb);
373 blue += GET_B(rgb);
375 rgb = raw[x+ytw+b1-l1];
376 red += GET_R(rgb);
377 green += GET_G(rgb);
378 blue += GET_B(rgb);
380 rgb = raw[x+ytw+b1];
381 red += GET_R(rgb);
382 green += GET_G(rgb);
383 blue += GET_B(rgb);
385 rgb = raw[x+ytw+b1+r1];
386 red += GET_R(rgb);
387 green += GET_G(rgb);
388 blue += GET_B(rgb);
390 rgb = raw[x+ytw+b2];
391 red += GET_R(rgb);
392 green += GET_G(rgb);
393 blue += GET_B(rgb);
395 red = red/14;
396 green = green/14;
397 blue = blue/14;
398 alpha = 255;
400 if (tiled)
402 argb = raw[x+ytw];
403 as = 255 - GET_A(texture->data[x + y * texture->w]);
404 rs = GET_R(argb);
405 gs = GET_G(argb);
406 bs = GET_B(argb);
408 red = ((rs * as) >> 8) + ((red * (255 - as)) >> 8);
409 green = ((gs * as) >> 8) + ((green * (255 - as)) >> 8);
410 blue = ((bs * as) >> 8) + ((blue * (255 - as)) >> 8);
412 raw[x+ytw] = SET_ARGB(as, red, green, blue);
415 else
417 raw[x+ytw] = SET_ARGB(alpha, red, green, blue);
422 if (ratio < 100)
424 if (texture)
426 ypos = 0;
427 while (height>0)
429 ah = texture->h;
430 if (ah > height) ah = height;
431 xpos = 0;
432 w = width;
433 while (w>0)
435 aw = texture->w;
436 if (aw > w) aw = w;
437 MixImage(pic, texture, textureti, 255 - (2.55 * ratio), aw, ah, xpos, ypos);
438 w -= aw;
439 xpos += aw;
441 height -= ah;
442 ypos += ah;
448 static void RenderBackgroundTiled(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti,
449 UWORD ratio, VOID (*TileImageToImageFunc)(struct NewImage *src, struct TileInfo * srcti, struct NewImage *dest))
451 struct NewImage *ni;
453 if (texture)
455 ni = NewImageContainer(pic->w, pic->h);
456 if (ni)
458 if (textureti)
460 TileImageToImageFunc(texture, textureti, ni);
461 BlurSourceAndMixTexture(pic, ni, textureti, ratio);
463 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
465 DisposeImageContainer(ni);
467 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
469 else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
472 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)
475 ULONG dy, dx;
476 LONG dh, height, dw, width;
478 if (src == NULL) return;
479 if (rp == NULL) return;
481 dh = _sh;
482 dy = _dy;
483 height = _dh;
485 if (!src->ok) return;
487 while (height > 0)
489 if ((height-dh)<0) dh = height;
490 height -= dh;
491 dw = _sw;
492 width = _dw;
493 dx = _dx;
494 while (width > 0)
496 if ((width-dw)<0) dw = width;
497 width -= dw;
499 if (src->mask)
501 BltMaskBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xe0, (PLANEPTR) src->mask);
503 else BltBitMapRastPort(src->bitmap, _sx, _sy, rp, dx, dy, dw, dh, 0xc0);
505 dx += dw;
507 dy += dh;
511 /******************************************************************************/
512 /******************************************************************************/
513 /******************************************************************************/
514 /******************************************************************************/
515 /******************************************************************************/
517 void DrawPartImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y, UWORD sx, UWORD sy, UWORD sw, UWORD sh)
519 if (ni->ok)
521 if (ni->bitmap == NULL)
523 WritePixelArray(ni->data, sx, sy, ni->w*4, rp, x, y, sw, sh, RECTFMT_ARGB);
525 else
527 BltBitMapRastPort(ni->bitmap, sx, sy, rp, x, y, sw, sh, 0xc0);
532 void DrawPartToImage(struct NewImage *src, struct NewImage *dest, UWORD sx, UWORD sy, UWORD sw, UWORD sh, UWORD dx, UWORD dy)
534 UWORD x, y;
536 for (y = 0; y < sh; y++)
538 for (x = 0; x < sw; x++)
540 dest->data[dx + x + (dy + y) * dest->w] = src->data[sx + x + (sy + y) * src->w];
545 void RenderMenuBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
547 if (texture)
549 if (textureti) RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImage);
550 else BlurSourceAndMixTexture(pic, texture, textureti, ratio);
552 else BlurSourceAndMixTexture(pic, NULL, NULL, ratio);
555 void RenderMenuBarBackground(struct NewImage *pic, struct NewImage *texture, struct TileInfo *textureti, UWORD ratio)
557 if (texture && textureti)
560 /* Fill the image with the center tile */
561 DrawTileToImage(texture, pic,
562 textureti->TileLeft, textureti->TileTop,
563 texture->w - textureti->TileLeft - textureti->TileRight, texture->h - textureti->TileBottom - textureti->TileTop,
564 0, 0, pic->w, pic->h);
566 RenderBackgroundTiled(pic, texture, textureti, ratio, TileImageToImageMenuBar);
570 void WriteAlphaPixelArray(struct NewImage *src, struct NewLUT8Image *dst, LONG sx, LONG sy, LONG dx, LONG dy, LONG w, LONG h)
572 ULONG *s = src->data;
573 ULONG argb;
574 UBYTE *d = dst->data;
575 int x, y;
577 for (y = 0; y < h; y++)
579 for (x = 0; x < w; x++)
581 argb = s[sx + x + (sy + y) * src->w];
582 d[dx + x + (dy + y) * dst->w] = GET_A(argb);
587 void SetImageTint(struct NewImage *dst, UWORD ratio, ULONG argb)
590 ULONG *d;
591 ULONG rgb;
592 UWORD r, g, b, w, h;
593 UBYTE rs, gs, bs, rd, gd, bd;
594 int x, y;
596 if (dst == NULL) return;
598 d = dst->data;
600 w = dst->w;
601 h = dst->h;
603 rs = (argb >> 16) & 0xff;
604 gs = (argb >> 8) & 0xff;
605 bs = argb & 0xff;
607 for (y = 0; y < h; y++)
609 for (x = 0; x < w; x++)
611 rgb = d[x + y * w];
612 rd = GET_R(rgb);
613 gd = GET_G(rgb);
614 bd = GET_B(rgb);
615 r = ((rs * ratio) >> 8) + ((rd * (255 - ratio)) >> 8);
616 g = ((gs * ratio) >> 8) + ((gd * (255 - ratio)) >> 8);
617 b = ((bs * ratio) >> 8) + ((bd * (255 - ratio)) >> 8);
619 r = r & 0xff;
620 g = g & 0xff;
621 b = b & 0xff;
623 d[x + y * w] = SET_ARGB(255, r, g, b);
629 * offx - offset between start of ni and place where image should be sample from
630 * offy - offset between start of ni and place where image should be sample from
631 * x, y, w, h - coords in rastport rp
633 void HorizVertRepeatNewImage(struct NewImage *ni, ULONG color, UWORD offx, UWORD offy, struct RastPort *rp, UWORD x, UWORD y, WORD w, WORD h)
635 ULONG ow, oh, sy, sx, dy, dx;
636 LONG dh, height, dw, width;
638 if ((w <= 0) || (h <= 0)) return;
640 if (!ni->ok)
642 FillPixelArray(rp, x, y, w, h, color);
643 return;
646 ow = ni->w;
647 oh = ni->h;
649 sy = offy % oh;
650 dh = oh - sy;
651 height = h;
652 dy = y;
653 while (height > 0)
655 if ((height-dh)<0) dh = height;
656 height -= dh;
658 sx = offx % ow;
659 dw = ow - sx;
660 width = w;
661 dx = x;
662 while (width > 0)
664 if ((width-dw)<0) dw = width;
665 width -= dw;
667 BltNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, dx, dy, dw, dh);
669 dx += dw;
670 sx = 0;
671 dw = ow;
673 dy += dh;
674 sy = 0;
675 dh = oh;
679 /* NOTE: fill parameter is ignored, previously it was forcing a no-alpha blit, but
680 this is already handled in BltNewImageSubImageRastPort */
681 /* dh - destination height to which subimage will be scaled to */
682 LONG WriteTiledImageTitle(BOOL fill, struct Window *win,
683 struct RastPort *rp, struct NewImage *ni, LONG sx, LONG sy, LONG sw,
684 LONG sh, LONG xp, LONG yp, LONG dw, LONG dh)
686 int w = dw;
687 int x = xp;
688 int ddw;
690 if (!ni->ok) return x;
692 if ((sw == 0) || (dw == 0)) return xp;
694 if (win)
696 if (x > win->Width) return xp;
697 if ((x + w) > win->Width) w = win->Width - x;
700 while (w > 0)
702 ddw = sw;
703 if (w < ddw) ddw = w;
705 BltScaleNewImageSubImageRastPort(ni, 0, 0, sx, sy, rp, x, yp, ddw, -1, -1, dh);
707 w -= ddw;
708 x += ddw;
710 return x;
714 * dh - destination height to scale to, -1 to use subimage height
716 LONG WriteVerticalScaledTiledImageHorizontal(struct RastPort *rp, struct NewImage *ni, ULONG subimage,
717 LONG sx, LONG sw, LONG xp, LONG yp, LONG sh, LONG dw, LONG dh)
719 LONG w = dw;
720 LONG x = xp;
721 LONG ddw;
723 if (!ni->ok) return xp;
725 if ((sw == 0) || (dw == 0)) return xp;
727 while (w > 0)
729 ddw = sw;
730 if (w < ddw) ddw = w;
732 BltScaleNewImageSubImageRastPort(ni, 0, subimage, sx, 0, rp, x, yp, ddw, sh, -1, dh);
734 w -= ddw;
735 x += ddw;
738 return x;
741 LONG WriteTiledImageHorizontal(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sx, LONG sw, LONG xp, LONG yp, LONG dw)
743 return WriteVerticalScaledTiledImageHorizontal(rp, ni, subimage, sx, sw, xp, yp, -1, dw, -1);
746 LONG WriteTiledImageVertical(struct RastPort *rp, struct NewImage *ni, ULONG subimage, LONG sy, LONG sh, LONG xp, LONG yp, LONG dh)
748 int h = dh;
749 int y = yp;
750 int ddh;
752 if (!ni->ok) return y;
754 if ((sh == 0) || (dh == 0)) return yp;
756 while (h > 0)
758 ddh = sh;
759 if (h < ddh) ddh = h;
761 BltNewImageSubImageRastPort(ni, subimage, 0, 0, sy, rp, xp, y, -1, ddh);
763 h -= ddh;
764 y += ddh;
766 return y;
769 struct myrgb
771 int red,green,blue;
774 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)
776 /* The basic idea of this algorithm is to calc the intersection between the
777 * diagonal of the rectangle (xs,ys) with dimension (xw,yw) a with the line starting
778 * at (x,y) (every pixel inside the rectangle) and angle angle with direction vector (vx,vy).
780 * Having the intersection point we then know the color of the pixel.
782 * TODO: Turn the algorithm into a incremental one
783 * Remove the use of floating point variables
785 double rad = angle*M_PI/180;
786 double cosarc = cos(rad);
787 double sinarc = sin(rad);
789 struct myrgb startRGB,endRGB;
791 int diffR, diffG, diffB;
793 int r,t; /* some helper variables to short the code */
794 int l,y,c,x;
795 int y1; /* The intersection point */
796 int incr_y1; /* increment of y1 */
797 int xs,ys,xw,yw;
798 int xadd,ystart,yadd;
799 // double vx = -cosarc;
800 // double vy = sinarc;
801 int vx = (int)(-cosarc*0xff);
802 int vy = (int)(sinarc*0xff);
804 int width = xb - xt + 1;
805 int height = yb - yt + 1;
807 if (buf == NULL) return;
809 startRGB.red = (start_rgb >> 16) & 0xff;
810 startRGB.green = (start_rgb >> 8) & 0xff;
811 startRGB.blue = start_rgb & 0xff;
813 endRGB.red = (end_rgb >> 16) & 0xff;
814 endRGB.green = (end_rgb >> 8) & 0xff;
815 endRGB.blue = end_rgb & 0xff;
817 diffR = endRGB.red - startRGB.red;
818 diffG = endRGB.green - startRGB.green;
819 diffB = endRGB.blue - startRGB.blue;
821 /* Normalize the angle */
822 if (angle < 0) angle = 360 - ((-angle)%360);
823 if (angle >= 0) angle = angle % 360;
825 if (angle <= 90 || (angle > 180 && angle <= 270))
827 /* The to be intersected diagonal goes from the top left edge to the bottom right edge */
828 xs = 0;
829 ys = 0;
830 xw = width;
831 yw = height;
832 } else
834 /* The to be intersected diagonal goes from the bottom left edge to the top right edge */
835 xs = 0;
836 ys = height;
837 xw = width;
838 yw = -height;
841 if (angle > 90 && angle <= 270)
843 /* for these angle we have y1 = height - y1. Instead of
845 * y1 = height - (-vy*(yw* xs -xw* ys) + yw*(vy* x -vx* y)) /(-yw*vx + xw*vy);
847 * we can write
849 * y1 = (-vy*(yw*(-xs)-xw*(-ys+height)) + yw*(vy*(-x)-vx*(-y+height)))/(-yw*vx + xw*vy);
851 * so height - y1 can be expressed with the normal formular adapting some parameters.
853 * Note that if one would exchanging startRGB/endRGB the values would only work
854 * for linear color gradients
856 xadd = -1;
857 yadd = -1;
858 ystart = height;
860 xs = -xs;
861 ys = -ys + height;
863 else
865 xadd = 1;
866 yadd = 1;
867 ystart = 0;
870 r = -vy*(yw*xs-xw*ys);
871 t = -yw*vx + xw*vy;
873 /* The formular as shown above is
875 * y1 = ((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));
877 * We see that only yw*(vy*x-vx*y) changes during the loop.
879 * We write
881 * Current Pixel: y1(x,y) = (r + yw*(vy*x-vx*y))/t = r/t + yw*(vy*x-vx*y)/t
882 * Next Pixel: y1(x+xadd,y) = (r + vw*(vy*(x+xadd)-vx*y))/t
884 * t*(y1(x+xadd,y) - y1(x,y)) = yw*(vy*(x+xadd)-vx*y) - yw*(vy*x-vx*y) = yw*vy*xadd;
888 incr_y1 = yw*vy*xadd;
889 UBYTE *bufptr = buf;
890 for (l = 0, y = ystart + ((yp - yt)* yadd); l < h; l++, y+=yadd)
893 /* Calculate initial y1 accu, can be brought out of the loop as well (x=0). It's probably a
894 * a good idea to add here also a value of (t-1)/2 to ensure the correct rounding
895 * This (and for r) is also a place were actually a overflow can happen |yw|=16 |y|=16. So for
896 * vx nothing is left, currently 9 bits are used for vx or vy */
897 int y1_mul_t_accu = r - yw*vx*y;
901 for (c = 0, x = ((xp - xt) * xadd); c < w; c++, x+=xadd)
903 int red,green,blue;
905 /* Calculate the intersection of two lines, this is not the fastet way to do but
906 * it is intuitive. Note: very slow! Will be optimzed later (remove FFP usage
907 * and making it incremental)...update: it's now incremental and no FFP is used
908 * but it probably can be optimized more by removing some more of the divisions and
909 * further specialize the stuff here (use of three accus). */
910 /* y1 = (int)((-vy*(yw*xs-xw*ys) + yw*(vy*x-vx*y)) /(-yw*vx + xw*vy));*/
911 y1 = y1_mul_t_accu / t;
913 red = startRGB.red + (int)(diffR*y1/height);
914 green = startRGB.green + (int)(diffG*y1/height);
915 blue = startRGB.blue + (int)(diffB*y1/height);
916 /* By using full 32 bits this can be made faster as well */
917 *bufptr++ = red;
918 *bufptr++ = green;
919 *bufptr++ = blue;
921 y1_mul_t_accu += incr_y1;
927 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)
929 UBYTE * buf = NULL;
931 if ((w <= 0) || (h <= 0)) return;
933 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
934 to WritePixelArray() can be made also faster */
935 buf = AllocVec(1 * yb * 3, 0);
937 FillMemoryBufferRGBGradient(buf, pen, xt, yt, xb, yb, xp, yp, 1, yb, start_rgb, end_rgb, angle);
939 HorizRepeatBuffer(buf, dy, pen, tc, rp, xp, yp, w, h);
941 FreeVec(buf);
944 void HorizRepeatBuffer(UBYTE * buf, LONG offy, LONG pen, BOOL tc, struct RastPort *rp, LONG x, LONG y, LONG w, LONG h)
946 UBYTE * bufblit = NULL;
947 ULONG xi, yi;
948 ULONG idxd;
949 ULONG idxs;
951 if ((w <= 0) || (h <= 0)) return;
952 if (!tc)
954 if (pen != -1) SetAPen(rp, pen); else SetAPen(rp, 2);
955 RectFill(rp, x, y, x + w - 1, y + h - 1);
956 return;
959 /* By bringing building the gradient array in the same format as the RastPort BitMap a call
960 to WritePixelArray() can be made also faster */
961 bufblit = AllocVec(w * h * 3, MEMF_ANY);
963 /* Copy one column buffer into blit buffer */
964 for (yi = 0; yi < h; yi++)
966 idxs = (offy + yi) * 3; /* source index */
967 idxd = yi * 3 * w; /* dest index */
968 for (xi = 0; xi < w; xi++)
970 /* Copy RGB pixel */
971 bufblit[idxd++] = buf[idxs + 0];
972 bufblit[idxd++] = buf[idxs + 1];
973 bufblit[idxd++] = buf[idxs + 2];
977 WritePixelArray(bufblit, 0, 0, w * 3, rp, x, y, w, h, RECTFMT_RGB);
979 FreeVec(bufblit);
982 void TileMapToBitmap(struct NewImage *src, struct TileInfo *srcti, struct BitMap *map, UWORD dw, UWORD dh)
984 UWORD y, h;
986 if (map == NULL) return;
987 if (src == NULL) return;
988 if (srcti == NULL) return;
989 y = 0;
991 h = src->h;
993 if ((srcti->TileTop + srcti->TileBottom) > dh) return;
994 if ((srcti->TileLeft + srcti->TileRight) > dw) return;
996 struct RastPort *dest = CreateRastPort();
998 if (dest != NULL)
1000 dest->BitMap = map;
1002 DrawMapTileToRP(src, dest, 0, y, srcti->TileLeft, srcti->TileTop, 0 , 0, srcti->TileLeft, srcti->TileTop);
1003 DrawMapTileToRP(src, dest, 0, y + h - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom, 0 , dh - srcti->TileBottom, srcti->TileLeft, srcti->TileBottom);
1004 DrawMapTileToRP(src, dest, src->w - srcti->TileRight, y, srcti->TileRight, srcti->TileTop, dw - srcti->TileRight, 0, srcti->TileRight, srcti->TileTop);
1005 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);
1007 DrawMapTileToRP(src, dest, srcti->TileLeft, y, src->w - srcti->TileLeft - srcti->TileRight, srcti->TileTop, srcti->TileLeft, 0, dw - srcti->TileLeft - srcti->TileRight, srcti->TileTop);
1008 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);
1009 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);
1010 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);
1011 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);
1012 FreeRastPort(dest);
1016 struct NewImage *GetImageFromRP(struct RastPort *rp, UWORD x, UWORD y, UWORD w, UWORD h)
1018 struct NewImage *ni;
1020 ni = NewImageContainer(w, h);
1021 if (ni)
1023 ReadPixelArray(ni->data, 0, 0, w*4, rp, x, y, w, h, RECTFMT_ARGB);
1025 return ni;
1028 void PutImageToRP(struct RastPort *rp, struct NewImage *ni, UWORD x, UWORD y) {
1030 if (ni)
1032 if (ni->data) WritePixelArray(ni->data, 0, 0, ni->w*4, rp, x, y, ni->w, ni->h, RECTFMT_ARGB);
1033 DisposeImageContainer(ni);
1037 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)
1039 int px, py, x, y;
1040 ULONG c;
1041 int c0, c1, c2, c3;
1042 UWORD offy = 0;
1044 if ((x1 < x0) || (y1 < y0)) return;
1045 if (!tc)
1047 SetAPen(rp, pen);
1048 Move(rp, x0, y0);
1049 Draw(rp, x1, y1);
1050 return;
1052 if (usegradients)
1054 c = basecolor;
1055 c3 = (c >> 24) & 0xff;
1056 c2 = (c >> 16) & 0xff;
1057 c1 = (c >> 8) & 0xff;
1058 c0 = c & 0xff;
1059 c0 *= fact;
1060 c1 *= fact;
1061 c2 *= fact;
1062 c3 *= fact;
1063 c0 = c0 >> 8;
1064 c1 = c1 >> 8;
1065 c2 = c2 >> 8;
1066 c3 = c3 >> 8;
1067 if (c0 > 255) c0 = 255;
1068 if (c1 > 255) c1 = 255;
1069 if (c2 > 255) c2 = 255;
1070 if (c3 > 255) c3 = 255;
1071 c = (c3 << 24) | (c2 << 16) | (c1 << 8) | c0;
1072 SetRPAttrs(rp, RPTAG_PenMode, FALSE, RPTAG_FgColor, c, TAG_DONE);
1073 Move(rp, x0, y0);
1074 Draw(rp, x1, y1);
1076 else if (ni->ok)
1078 if (x0 == x1)
1080 x = x0 % ni->w;
1081 for (py = y0; py < y1; py++)
1083 y = (py - offy) % ni->h;
1084 c = ni->data[x + y * ni->w];
1085 c0 = (c >> 24) & 0xff;
1086 c1 = (c >> 16) & 0xff;
1087 c2 = (c >> 8) & 0xff;
1088 c3 = c & 0xff;
1089 c0 *= fact;
1090 c1 *= fact;
1091 c2 *= fact;
1092 c3 *= fact;
1093 c0 = c0 >> 8;
1094 c1 = c1 >> 8;
1095 c2 = c2 >> 8;
1096 c3 = c3 >> 8;
1097 if (c0 > 255) c0 = 255;
1098 if (c1 > 255) c1 = 255;
1099 if (c2 > 255) c2 = 255;
1100 if (c3 > 255) c3 = 255;
1101 c = (c3 << 24) | (c2 << 16) | (c1 << 8) | c0;
1102 WriteRGBPixel(rp, x0, py, c);
1104 } else {
1105 y = (y0 - offy) % ni->h;
1106 for (px = x0; px < x1; px++) {
1107 x = px % ni->h;
1108 c = ni->data[x + y * ni->w];
1109 c0 = (c >> 24) & 0xff;
1110 c1 = (c >> 16) & 0xff;
1111 c2 = (c >> 8) & 0xff;
1112 c3 = c & 0xff;
1113 c0 *= fact;
1114 c1 *= fact;
1115 c2 *= fact;
1116 c3 *= fact;
1117 c0 = c0 >> 8;
1118 c1 = c1 >> 8;
1119 c2 = c2 >> 8;
1120 c3 = c3 >> 8;
1121 if (c0 > 255) c0 = 255;
1122 if (c1 > 255) c1 = 255;
1123 if (c2 > 255) c2 = 255;
1124 if (c3 > 255) c3 = 255;
1125 c = (c3 << 24) | (c2 << 16) | (c1 << 8) | c0;
1126 WriteRGBPixel(rp, px, y0, c);
1130 else
1132 Move(rp, x0, y0);
1133 Draw(rp, x1, y1);
1137 void DrawScaledStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp,
1138 WORD scaledwidth, WORD scaledheight)
1141 UWORD subimagecol = 0;
1142 UWORD subimagerow = 0;
1144 if (ni->ok)
1146 switch(state)
1148 case IDS_NORMAL:
1149 break;
1150 case IDS_SELECTED:
1151 subimagecol = 1;
1152 break;
1153 case IDS_INACTIVENORMAL:
1154 subimagecol = 2;
1155 break;
1158 BltScaleNewImageSubImageRastPortSimple(ni, subimagecol, subimagerow, rp, xp, yp, scaledwidth, scaledheight);
1162 void DrawStatefulGadgetImageToRP(struct RastPort *rp, struct NewImage *ni, ULONG state, UWORD xp, UWORD yp)
1164 DrawScaledStatefulGadgetImageToRP(rp, ni, state, xp, yp, -1, -1);