Fixed out-by-one error in previous commit.
[AROS.git] / workbench / c / Decoration / newimagefuncs.c
blob0bf0f6dd1ecd52aed46b8412f460408cefdeb0e6
1 /*
2 Copyright © 2011, The AROS Development Team.
3 $Id$
4 */
6 #include <datatypes/pictureclass.h>
7 #include <libraries/cybergraphics.h>
9 #include <proto/alib.h>
10 #include <proto/datatypes.h>
11 #include <proto/dos.h>
12 #include <proto/graphics.h>
13 #include <proto/exec.h>
14 #include <proto/intuition.h>
15 #include <proto/cybergraphics.h>
17 #include <string.h>
19 #include <aros/debug.h>
21 #include "newimage.h"
23 #if AROS_BIG_ENDIAN
24 #define GET_A(rgb) (((rgb) >> 24) & 0xff)
25 #else
26 #define GET_A(rgb) ((rgb) & 0xff)
27 #endif
29 /* Code taken from BM__Hidd_BitMap__BitMapScale */
30 /* srcdata point directly to (0,0) point of subbuffer to be read from */
31 ULONG * ScaleBuffer(ULONG * srcdata, LONG widthBuffer /* stride */, LONG widthSrc, LONG heightSrc, LONG widthDest, LONG heightDest)
33 ULONG * scaleddata = (ULONG *) AllocVec(sizeof(ULONG) * widthDest * heightDest, MEMF_ANY);
34 LONG srcline = -1;
35 UWORD * linepattern = (UWORD *) AllocVec(sizeof(UWORD) * widthDest, MEMF_ANY);
36 ULONG count = 0;
37 UWORD ys = 0;
38 ULONG xs = 0;
39 ULONG dyd = heightDest;
40 ULONG dxd = widthDest;
41 LONG accuys = dyd;
42 LONG accuxs = dxd;
43 ULONG dxs = widthSrc;
44 ULONG dys = heightSrc;
45 LONG accuyd = - (dys >> 1);
46 LONG accuxd = - (dxs >> 1);
47 ULONG x;
48 ULONG * lastscaledlineptr = scaleddata + ((heightDest - 1) * widthDest);
50 count = 0;
51 while (count < widthDest) {
52 accuxd += dxs;
53 while (accuxd > accuxs) {
54 xs++;
55 accuxs += dxd;
58 linepattern[count] = xs;
60 count++;
63 count = 0;
64 while (count < heightDest) {
65 accuyd += dys;
66 while (accuyd > accuys) {
67 ys++;
68 accuys += dyd;
71 if (srcline != ys) {
72 //HIDD_BM_GetImage(msg->src, (UBYTE *) srcbuf, bsa->bsa_SrcWidth * sizeof(ULONG), bsa->bsa_SrcX, bsa->bsa_SrcY + ys, bsa->bsa_SrcWidth, 1, vHidd_StdPixFmt_Native32);
73 ULONG * srcptr = srcdata + (ys * widthBuffer);
74 srcline = ys;
76 /* New: use last line as temp buffer */
77 for (x = 0; x < widthDest; x++)
78 lastscaledlineptr[x] = srcptr[linepattern[x]];
82 //HIDD_BM_PutImage(msg->dst, msg->gc, (UBYTE *) dstbuf, bsa->bsa_DestWidth * sizeof(ULONG), bsa->bsa_DestX, bsa->bsa_DestY + count, bsa->bsa_DestWidth, 1, vHidd_StdPixFmt_Native32);
83 CopyMem(lastscaledlineptr, scaleddata + (count * widthDest), widthDest * sizeof(ULONG));
85 count++;
88 FreeVec(linepattern);
90 return scaleddata;
93 void DisposeImageContainer(struct NewImage *ni)
95 if (ni)
97 FreeVec(ni->data);
99 if (ni->o)
101 DisposeDTObject(ni->o);
102 ni->o = NULL;
103 ni->bitmap = NULL;
104 ni->mask = NULL;
107 FreeVec(ni->filename);
109 FreeVec(ni->subimageinbm);
110 FreeBitMap(ni->bitmap2);
112 FreeVec(ni);
116 void DisposeLUT8ImageContainer(struct NewLUT8Image *ni)
118 if (ni)
120 FreeVec(ni->data);
121 FreeVec(ni);
125 struct NewLUT8Image *NewLUT8ImageContainer(UWORD w, UWORD h)
127 struct NewLUT8Image *ni;
129 ni = AllocVec(sizeof(struct NewLUT8Image), MEMF_ANY | MEMF_CLEAR);
130 if (ni)
132 ni->w = w;
133 ni->h = h;
134 ni->data = AllocVec(w * h, MEMF_ANY | MEMF_CLEAR);
135 if (ni->data == NULL)
137 FreeVec(ni);
138 ni = NULL;
141 return ni;
144 struct NewImage *NewImageContainer(UWORD w, UWORD h)
146 struct NewImage *ni;
148 ni = AllocVec(sizeof(struct NewImage), MEMF_ANY | MEMF_CLEAR);
149 if (ni)
151 ni->w = w;
152 ni->h = h;
153 ni->subimagescols = 1;
154 ni->subimagesrows = 1;
155 ni->data = AllocVec(w * h * sizeof (ULONG), MEMF_ANY | MEMF_CLEAR);
156 if (ni->data == NULL)
158 FreeVec(ni);
159 ni = NULL;
162 return ni;
165 struct NewImage *ScaleNewImage(struct NewImage * oni, UWORD neww, UWORD newh)
167 struct NewImage *ni;
169 ni = AllocVec(sizeof(struct NewImage), MEMF_ANY | MEMF_CLEAR);
170 if (ni)
172 ni->w = neww;
173 ni->h = newh;
174 ni->subimagescols = oni->subimagescols;
175 ni->subimagesrows = oni->subimagesrows;
176 ni->ok = TRUE;
177 ni->data = ScaleBuffer(oni->data, oni->w, oni->w, oni->h, ni->w, ni->h);
178 if (ni->data == NULL)
180 FreeVec(ni);
181 ni = NULL;
184 return ni;
187 struct NewImage *GetImageFromFile(STRPTR path, STRPTR name,
188 ULONG expectedsubimagescols, ULONG expectedsubimagesrows)
190 struct BitMapHeader *bmhd = NULL;
191 struct NewImage *ni = NULL;
192 struct BitMap *map = NULL;
193 struct RastPort *rp = NULL;
194 Object *pic;
195 struct pdtBlitPixelArray pa;
196 STRPTR buffer;
197 UWORD w, h, x, y;
198 UBYTE mask;
199 ULONG *dst;
200 LONG len;
202 len = strlen(path) + strlen(name) + 2;
203 buffer = AllocVec(len, MEMF_CLEAR | MEMF_ANY);
204 strncpy(buffer, path, len);
205 AddPart(buffer, name, len);
207 pic = NewDTObject(buffer, DTA_SourceType, DTST_FILE,
208 DTA_GroupID, GID_PICTURE,
209 PDTA_Remap, FALSE,
210 PDTA_DestMode, PMODE_V43,
211 TAG_DONE);
212 if (pic)
214 GetAttr(PDTA_BitMapHeader, pic, (APTR)&bmhd);
215 if(bmhd)
218 w = bmhd->bmh_Width;
219 h = bmhd->bmh_Height;
220 mask = bmhd->bmh_Masking;
221 ni = NewImageContainer(w, h);
222 if (ni)
224 ni->filename = AllocVec(len, MEMF_CLEAR | MEMF_ANY);
225 strncpy(ni->filename, buffer, len);
226 ni->subimagescols = expectedsubimagescols;
227 ni->subimagesrows = expectedsubimagesrows;
228 pa.MethodID = PDTM_READPIXELARRAY;
229 pa.pbpa_PixelData = (APTR) ni->data;
230 pa.pbpa_PixelFormat = PBPAFMT_ARGB;
231 pa.pbpa_PixelArrayMod = w*4;
232 pa.pbpa_Left = 0;
233 pa.pbpa_Top = 0;
234 pa.pbpa_Width = w;
235 pa.pbpa_Height = h;
236 DoMethodA(pic, (Msg) &pa);
237 ni->ok = TRUE;
238 if (bmhd->bmh_Depth <= 8)
240 GetAttr(PDTA_BitMap, pic, (APTR)&map);
241 if (map && (mask == mskHasTransparentColor))
243 rp = CreateRastPort();
244 if (rp) rp->BitMap = map;
248 if (rp)
250 dst = ni->data;
251 for (y = 0; y < h; y++)
253 for (x = 0; x < w; x++)
255 #if !AROS_BIG_ENDIAN
256 if (ReadPixel(rp, x, y) == 0) dst[x+y*w] &= 0xffffff00; else dst[x+y*w] |= 0x000000ff;
257 #else
258 if (ReadPixel(rp, x, y) == 0) dst[x+y*w] &= 0x00ffffff; else dst[x+y*w] |= 0xff000000;
259 #endif
262 FreeRastPort(rp);
266 DisposeDTObject(pic);
269 FreeVec(buffer);
271 return ni;
274 static Object * LoadPicture(CONST_STRPTR filename, struct Screen *scr)
276 Object *o;
278 o = NewDTObject((APTR)filename,
279 DTA_GroupID , GID_PICTURE,
280 OBP_Precision , PRECISION_EXACT,
281 PDTA_Screen , (IPTR)scr,
282 PDTA_FreeSourceBitMap, TRUE,
283 PDTA_DestMode , PMODE_V43,
284 PDTA_UseFriendBitMap , TRUE,
285 TAG_DONE);
287 if (o)
289 struct FrameInfo fri = {0};
291 D(bug("DTM_FRAMEBOX\n", o));
292 DoMethod(o,DTM_FRAMEBOX,NULL,(IPTR)&fri,(IPTR)&fri,sizeof(struct FrameInfo),0);
294 if (fri.fri_Dimensions.Depth > 0)
296 D(bug("DTM_PROCLAYOUT\n", o));
297 if (DoMethod(o,DTM_PROCLAYOUT,NULL,1))
299 return o;
302 DisposeDTObject(o);
305 return NULL;
308 /* This function must never return NULL, because logic in drawing code
309 checks img->ok instead of img != NULL to make decisions */
310 struct NewImage * CreateNewImageContainerMatchingScreen(struct NewImage *in, BOOL truecolor, struct Screen* scr)
312 struct NewImage * out = AllocVec(sizeof(struct NewImage), MEMF_ANY | MEMF_CLEAR);
313 out->ok = FALSE;
315 if (in != NULL)
317 out->w = in->w;
318 out->h = in->h;
319 out->subimagescols = in->subimagescols;
320 out->subimagesrows = in->subimagesrows;
321 out->filename = NULL;
322 out->bitmap = NULL;
323 out->bitmap2 = NULL;
324 out->mask = NULL;
325 out->o = NULL;
326 if (in->data != NULL)
328 out->data = AllocVec(out->w * out->h * sizeof(ULONG), MEMF_ANY | MEMF_CLEAR);
329 if (out->data != NULL) CopyMem(in->data, out->data, out->w * out->h * sizeof(ULONG));
331 out->ok = (out->data != NULL) ? TRUE : FALSE;
332 /* Allocate decision table, all values are set to FALSE (MEMF_CLEAR) */
333 out->subimageinbm = AllocVec(in->subimagescols * in->subimagesrows * sizeof(BOOL), MEMF_ANY | MEMF_CLEAR);
335 out->filename = AllocVec(strlen(in->filename) + 5, MEMF_ANY | MEMF_CLEAR); /* size + 5 -> covers all */
336 strcpy(out->filename, in->filename);
338 if (!truecolor)
340 /* If this is LUT screen, try to load LUT version of image */
341 out->ok = FALSE;
342 strcpy(out->filename, in->filename);
343 strcat(out->filename, "_LUT");
345 out->o = LoadPicture(out->filename, scr);
346 if (out->o == NULL)
348 /* Load the original image with conversion */
349 out->o = LoadPicture(in->filename, scr);
350 if (out->o != NULL)
351 strcpy(out->filename, in->filename);
354 if (out->o)
356 GetDTAttrs(out->o, PDTA_DestBitMap, (IPTR)&out->bitmap, TAG_DONE);
357 if (out->bitmap == NULL)
358 GetDTAttrs(out->o, PDTA_BitMap, (IPTR)&out->bitmap, TAG_DONE);
360 if (out->bitmap != NULL)
362 GetDTAttrs(out->o, PDTA_MaskPlane, (IPTR)&out->mask, TAG_DONE);
363 out->ok = TRUE;
365 else
367 DisposeDTObject(out->o);
368 out->o = NULL;
373 if (out->data != NULL)
375 ULONG subimagewidth = out->w / out->subimagescols;
376 ULONG subimageheight = out->h / out->subimagesrows;
377 ULONG col = 0, row = 0, x = 0, y = 0;
378 out->mask = NULL;
379 out->o = NULL;
380 BOOL atleastone = FALSE;
382 /* It is possible that some subimage do not have alpha channel.
383 If that is true, we could create a bitmap that can be later used
384 for blitting instead of alpha drawing */
386 /* Scan subimages and detect which don't have alpha channel */
387 for (row = 0; row < out->subimagesrows; row++)
389 for (col = 0; col < out->subimagescols; col++)
391 /* Assume image can be put to bitmap */
392 out->subimageinbm[col + (row * out->subimagescols)] = TRUE;
393 /* Place pointer at beginning of subimage */
394 ULONG * ptr = out->data + (row * out->w * subimageheight) + (col * subimagewidth);
395 for (y = 0; y < subimageheight; y++)
397 for (x = 0; x < subimagewidth; x++)
399 if (GET_A(*ptr) != 0xFF)
400 out->subimageinbm[col + (row * out->subimagescols)] = FALSE;
401 ptr++;
403 ptr += (subimagewidth * (out->subimagescols - 1)); /* Advance to next subimage line */
408 /* Check if there was at least one subimage without alpha channel */
409 D(bug("File: %s : ", out->filename));
410 for (row = 0; row < out->subimagesrows; row++)
412 for (col = 0; col < out->subimagescols; col++)
414 D(bug("sb(%d,%d):", col, row));
415 if (out->subimageinbm[col + (row * out->subimagescols)])
417 D(bug("YES, "));
418 atleastone = TRUE;
420 else
422 D(bug("NO, "));
426 D(bug("\n"));
428 /* If yes, generate a bitmap */
429 if (atleastone)
431 struct RastPort * rp = CreateRastPort();
432 out->bitmap2 = AllocBitMap(out->w, out->h, 1, 0, scr->RastPort.BitMap);
433 rp->BitMap = out->bitmap2;
434 WritePixelArray(out->data, 0, 0, out->w * 4, rp, 0, 0, out->w, out->h, RECTFMT_ARGB);
435 FreeRastPort(rp);
440 return out;
443 struct Region *RegionFromLUT8Image(int w, int h, struct NewLUT8Image *s)
445 struct Region *shape;
446 int x, y;
447 BOOL transp, transpstate;
448 BOOL failed = FALSE;
450 if (s == NULL) return NULL;
452 UBYTE *src = s->data;
454 shape = NewRegion();
456 if (shape) {
457 struct Rectangle rect = {0, s->h, w-1, h-1};
458 if (!OrRectRegion(shape, &rect)) failed = TRUE;
459 for(y = 0; y < s->h; y++)
461 struct Rectangle rect = {0, y, 0, y};
462 transpstate = TRUE;
463 for(x = 0; x < s->w; x++)
465 transp = src[y * s->w + x] == 0;
466 if (transpstate)
468 if (!transp)
470 rect.MaxX = rect.MinX = x;
471 transpstate = FALSE;
473 } else {
474 if (transp)
476 OrRectRegion(shape, &rect);
477 transpstate = TRUE;
479 else
481 rect.MaxX++;
485 if (!transpstate) if (!OrRectRegion(shape, &rect)) failed = TRUE;
487 if (failed)
489 DisposeRegion(shape);
490 shape = NULL;
493 return shape;