Initial revision
[blender.git] / source / blender / imbuf / intern / amiga.c
1 /**
2  * amiga.c
3  *
4  * $Id$
5  *
6  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License
10  * as published by the Free Software Foundation; either version 2
11  * of the License, or (at your option) any later version. The Blender
12  * Foundation also sells licenses for use in proprietary software under
13  * the Blender License.  See http://www.blender.org/BL/ for information
14  * about this.
15  *
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software Foundation,
23  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
24  *
25  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
26  * All rights reserved.
27  *
28  * The Original Code is: all of this file.
29  *
30  * Contributor(s): none yet.
31  *
32  * ***** END GPL/BL DUAL LICENSE BLOCK *****
33  */
34
35 #include "imbuf.h"
36 #include "imbuf_patch.h"
37
38 #include "IMB_imbuf_types.h"
39 #include "IMB_imbuf.h"
40
41 #include "IMB_cmap.h"
42 #include "IMB_allocimbuf.h"
43 #include "IMB_bitplanes.h"
44 #include "IMB_amiga.h"
45
46 /* actually hard coded endianness */
47 #define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
48 #define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
49 #define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
50 #define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))
51
52 /* more endianness... should move to a separate file... */
53 #if defined(__sgi) || defined (__sparc) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
54 #define GET_ID GET_BIG_LONG
55 #define LITTLE_LONG SWAP_LONG
56 #else
57 #define GET_ID GET_LITTLE_LONG
58 #define LITTLE_LONG ENDIAN_NOP
59 #endif
60
61 static uchar *decodebodyscanl(uchar *body, short bytes, uchar **list, short d)
62 {
63         for (;d>0;d--){
64                 uchar *point;
65                 short todo;
66                 uchar i,j;
67
68                 point = *(list++);
69                 todo=bytes;
70                 while (todo>0){
71                         i = *body++;
72
73                         if (i & 128){                   /* fill */
74                                 if (i==128) continue;   /* nop  */
75
76                                 i=257-i;
77                                 todo-=i;
78                                 j = *(body++);
79                                 do{
80                                         *(point++) = j;
81                                         i--;
82                                 }while (i);
83                         } else{                         /* copy */
84                                 i++;
85                                 todo-=i;
86
87                                 do{
88                                         *(point++) = *(body++);
89                                         i--;
90                                 }while (i);
91                         }
92                 }
93                 if (todo) return (0);
94         }
95         return(body);
96 }
97
98
99 static uchar *decodebodyh(struct ImBuf *ibuf, uchar *body)
100 {
101         if (ibuf->y==1) {
102                 body=decodebodyscanl(body, WIDTHB(ibuf->x), (uchar **)ibuf->planes, ibuf->depth);
103         }
104         else {
105                 unsigned int **list;
106                 short skipx,i,bytes,y;
107
108                 list = imb_copyplanelist(ibuf);
109                 if (list == 0) return (0);
110
111                 y=ibuf->y;
112                 bytes = WIDTHB(ibuf->x);
113                 skipx = ibuf->skipx;
114
115                 for (;y>0;y--){
116                         body=decodebodyscanl(body, bytes, (uchar **)list, ibuf->depth);
117                         if (body == 0) return (0);
118
119                         for (i=ibuf->depth-1;i>=0;i--){
120                                 list[i] += skipx;
121                         }
122                 }
123                 free(list);
124         }
125         return(body);
126 }
127
128
129 static uchar *decodebodykolum(uchar *body, short bytes, uchar **list, short d, int next)
130 {
131         for (;d>0;d--){
132                 uchar *point;
133                 short todo;
134                 uchar i,j;
135
136                 point = *(list++);
137                 todo=bytes;
138                 while (todo>0){
139                         i = *body++;
140
141                         if (i & 128){                   /* fill */
142                                 if (i==128) continue;   /* nop  */
143
144                                 i=257-i;
145                                 todo-=i;
146                                 j = *body++;
147                                 do{
148                                         *point = j;
149                                         point += next;
150                                         i--;
151                                 }while (i);
152                         }
153                         else{                           /* copy */
154                                 i++;
155                                 todo-=i;
156
157                                 do{
158                                         *point = *body++;
159                                         point += next;
160                                         i--;
161                                 }while (i);
162                         }
163                 }
164                 if (todo) return (0);
165         }
166         return(body);
167 }
168
169
170 static uchar *decodebodyv(struct ImBuf *ibuf, uchar *body)
171 {
172         uchar **list;
173         short skipx,i,bytes,times;
174
175         list = (uchar **)imb_copyplanelist(ibuf);
176         if (list == 0) return (0);
177
178         bytes = ibuf->y;
179         times = WIDTHB(ibuf->x);
180         skipx = ibuf->skipx << 2;
181
182         for (;times>0;times--){
183                 body=decodebodykolum(body,bytes,list,ibuf->depth,skipx);
184                 if (body == 0) return (0);
185
186                 for (i=ibuf->depth-1;i>=0;i--){
187                         list[i] += 1;
188                 }
189         }
190         free(list);
191         return(body);
192 }
193
194 static uchar *makebody(uchar **planes, short bytes, short depth, uchar *buf)
195 {
196         uchar *bitplstart,*temp;
197
198         register uchar last,this,*bitpl;
199         register short todo;
200         register int copy;
201
202         bytes--;
203         for (;depth>0;depth--){
204                 bitpl = *(planes++);
205                 bitplstart = bitpl;
206                 todo = bytes;
207                 last = *bitpl++;
208                 this = *bitpl++;
209                 copy = last^this;
210                 while (todo>0){
211
212                         if (copy){
213                                 do{
214                                         last = this;
215                                         this = *bitpl++;
216                                         if (last == this){
217                                                 if (this == bitpl[-3]){         /* drie dezelfde? */
218                                                         todo -= 1;                                      /* todo goed zetten */
219                                                         break;
220                                                 }
221                                         }
222                                 }while (--todo != 0);
223
224                                 copy=bitpl-bitplstart;
225                                 copy -= 1;
226                                 if (todo) copy -= 2;
227
228                                 temp = bitpl;
229                                 bitpl = bitplstart;
230
231                                 while (copy){
232                                         last = copy;
233                                         if (copy>MAXDAT) last = MAXDAT;
234                                         copy -= last;
235                                         *buf++ = last-1;
236                                         do{
237                                                 *buf++ = *bitpl++;
238                                         }while(--last != 0);
239                                 }
240                                 bitplstart = bitpl;
241                                 bitpl = temp;
242                                 last = this;
243
244                                 copy = FALSE;
245                         }
246                         else{
247                                 while (*bitpl++ == this){               /* zoek naar eerste afwijkende byte */
248                                         if (--todo == 0) break; /* of einde regel */
249                                 }
250                                 bitpl -= 1;
251                                 copy = bitpl-bitplstart;
252                                 bitplstart = bitpl;
253                                 todo -= 1;
254                                 this = *bitpl++;
255
256                                 while (copy){
257                                         if (copy>MAXRUN){
258                                                 *buf++ = -(MAXRUN-1);
259                                                 *buf++ = last;
260                                                 copy -= MAXRUN;
261                                         }
262                                         else{
263                                                 *buf++ = -(copy-1);
264                                                 *buf++ = last;
265                                                 break;
266                                         }
267                                 }
268                                 copy=TRUE;
269                         }
270                 }
271         }
272         return (buf);
273 }
274
275
276 short imb_encodebodyh(struct ImBuf *ibuf, int file)
277 {
278         uchar *buf, *endbuf, *max;
279         int size, line, ok = TRUE;
280         unsigned int **list;
281         short skipx,i,y;
282
283         line = WIDTHB(ibuf->x) * ibuf->depth;
284         line += (line >> 6) + 10;
285         size = 16 * line;
286         if (size < 16384) size = 16384;
287         
288         buf = (uchar *) malloc(size);
289         if (buf == 0) return (0);
290
291         max = buf + size - line;
292         
293         list = imb_copyplanelist(ibuf);
294         if (list == 0){
295                 free(buf);
296                 return (0);
297         }
298
299         y=ibuf->y;
300         skipx = ibuf->skipx;
301         endbuf = buf;
302         
303         for (y=ibuf->y;y>0;y--){
304                 endbuf = makebody((uchar **)list, WIDTHB(ibuf->x), ibuf->depth, endbuf);
305                 if (endbuf==0){
306                         ok = -20;
307                         break;
308                 }
309                 if (endbuf >= max || y == 1){ 
310                         size = endbuf-buf;
311                         if (write(file,buf,size)!=size) ok = -19;
312                         endbuf = buf;
313                 }
314                 for (i=ibuf->depth-1;i>=0;i--){
315                         list[i] += skipx;
316                 }
317                 if (ok != TRUE) break;
318         }
319         free(list);
320
321         free(buf);
322         return(ok);
323 }
324
325
326 short imb_encodebodyv(struct ImBuf *ibuf, int file)
327 {
328         struct ImBuf *ibufv;
329         uchar *buf,*endbuf;
330         short x,offset;
331
332         buf = (uchar *) malloc((ibuf->y + (ibuf->y >> 6) + 10) * ibuf->depth);
333         if (buf == 0) return (0);
334
335         ibufv=IMB_allocImBuf((ibuf->y)<<3,1, ibuf->depth, 0, 1);
336         if (ibufv == 0){
337                 free(buf);
338                 return (0);
339         }
340
341         offset=0;
342
343         for(x = WIDTHB(ibuf->x);x>0;x--){
344                 register short i;
345
346                 for(i = ibuf->depth-1 ;i>=0;i--){
347                         register uchar *p1,*p2;
348                         register int skipx;
349                         register short y;
350
351                         skipx = (ibuf->skipx)*sizeof(int *);
352                         p1=(uchar *)ibuf->planes[i];
353                         p2=(uchar *)ibufv->planes[i];
354                         p1 += offset;
355
356                         for (y=ibuf->y;y>0;y--){
357                                 *(p2++) = *p1;
358                                 p1 += skipx;
359                         }
360                 }
361                 offset += 1;
362
363                 endbuf=makebody((uchar **)ibufv->planes, ibuf->y, ibuf->depth, buf);
364                 if (endbuf==0) return (-20);
365                 if (write(file,buf,endbuf-buf)!=endbuf-buf) return (-19);
366         }
367         free(buf);
368         IMB_freeImBuf(ibufv);
369         return (TRUE);
370 }
371
372 static uchar *readbody(struct ImBuf *ibuf, uchar *body)
373 {
374         int skipbuf,skipbdy,depth,y,offset = 0;
375
376         skipbuf = ibuf->skipx;
377         skipbdy = WIDTHB(ibuf->x);
378
379         for (y = ibuf->y; y> 0; y--){
380                 for( depth = 0; depth < ibuf->depth; depth ++){
381                         memcpy(ibuf->planes[depth] + offset, body, skipbdy);
382                         body += skipbdy;
383                 }
384                 offset += skipbuf;
385         }
386         return body;
387 }
388
389 struct ImBuf *imb_loadamiga(int *iffmem,int flags)
390 {
391         int chunk,totlen,len,*cmap=0,cmaplen,*mem,ftype=0;
392         uchar *body=0;
393         struct BitMapHeader bmhd;
394         struct ImBuf *ibuf=0;
395
396         mem = iffmem;
397         bmhd.w = 0;
398
399         if (GET_ID(mem) != FORM) return (0);
400         if (GET_ID(mem+2) != ILBM) return (0);
401         totlen= (GET_BIG_LONG(mem+1) + 1) & ~1;
402         mem += 3;
403         totlen -= 4;
404
405
406         while(totlen > 0){
407                 chunk = GET_ID(mem);
408                 len= (GET_BIG_LONG(mem+1) + 1) & ~1;
409                 mem += 2;
410
411                 totlen -= len+8;
412
413                 switch (chunk){
414                 case BMHD:
415                         memcpy(&bmhd, mem, sizeof(struct BitMapHeader));
416
417                         bmhd.w = BIG_SHORT(bmhd.w);
418                         bmhd.h = BIG_SHORT(bmhd.h);
419                         bmhd.x = BIG_SHORT(bmhd.x);
420                         bmhd.y = BIG_SHORT(bmhd.y);
421                         bmhd.transparentColor = BIG_SHORT(bmhd.transparentColor);
422                         bmhd.pageWidth = BIG_SHORT(bmhd.pageWidth);
423                         bmhd.pageHeight = BIG_SHORT(bmhd.pageHeight);
424                         
425                         break;
426                 case BODY:
427                         body = (uchar *)mem;
428                         break;
429                 case CMAP:
430                         cmap = mem;
431                         cmaplen = len/3;
432                         break;
433                 case CAMG:
434                         ftype = GET_BIG_LONG(mem);
435                         break;
436                 }
437                 mem = (int *)((uchar *)mem +len);
438                 if (body) break;
439         }
440         if (bmhd.w == 0) return (0);
441         if (body == 0) return (0);
442         
443         if (flags & IB_test) ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes, 0, 0);
444         else ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes + (bmhd.masking & 1),0,1);
445
446         if (ibuf == 0) return (0);
447
448         ibuf->ftype = (ftype | AMI);
449         
450         if (cmap){
451                 ibuf->mincol = 0;
452                 ibuf->maxcol = cmaplen;
453                 imb_addcmapImBuf(ibuf);
454                 /* this functions needs a 3rd arg: the number of
455          * columns.... why did this work before? */
456 /*              imb_makecolarray(ibuf, cmap); */
457                 imb_makecolarray(ibuf, cmap, 0);
458         }
459
460         if (flags & IB_test){
461                 if (flags & IB_freem) free(iffmem);
462                 return(ibuf);
463         }
464         
465         switch (bmhd.compression){
466         case 0:
467                 body= readbody(ibuf, body);
468                 break;
469         case 1:
470                 body= decodebodyh(ibuf,body);
471                 break;
472         case 2:
473                 body= decodebodyv(ibuf,body);
474                 ibuf->type |= IB_subdlta;
475                 break;
476         }
477
478         if (flags & IB_freem) free(iffmem);
479
480         if (body == 0){
481                 free (ibuf);
482                 return(0);
483         }
484         
485         /* vergeet stencil */
486         ibuf->depth = bmhd.nPlanes;
487         
488         if (flags & IB_rect){
489                 imb_addrectImBuf(ibuf);
490                 imb_bptolong(ibuf);
491                 imb_freeplanesImBuf(ibuf);
492                 if (ibuf->cmap){
493                         if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf);
494                 } else if (ibuf->depth == 18){
495                         int i,col;
496                         unsigned int *rect;
497
498                         rect = ibuf->rect;
499                         for(i=ibuf->x * ibuf->y ; i>0 ; i--){
500                                 col = *rect;
501                                 col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4) + ((col & 0x3f) << 2);
502                                 col += (col & 0xc0c0c0) >> 6;
503                                 *rect++ = col;
504                         }
505                         ibuf->depth = 24;
506                 } else if (ibuf->depth <= 8) { /* geen colormap en geen 24 bits: zwartwit */
507                         uchar *rect;
508                         int size, shift;
509
510                         if (ibuf->depth < 8){
511                                 rect = (uchar *) ibuf->rect;
512                                 rect += 3;
513                                 shift = 8 - ibuf->depth;
514                                 for (size = ibuf->x * ibuf->y; size > 0; size --){
515                                         rect[0] <<= shift;
516                                         rect += 4;
517                                 }
518                         }
519                         rect = (uchar *) ibuf->rect;
520                         for (size = ibuf->x * ibuf->y; size > 0; size --){
521                                 rect[1] = rect[2] = rect[3];
522                                 rect += 4;
523                         }
524                         ibuf->depth = 8;
525                 }
526         }
527
528         if ((flags & IB_ttob) == 0) IMB_flipy(ibuf);
529
530         if (ibuf) {
531                 if (ibuf->rect) 
532                         IMB_convert_rgba_to_abgr(ibuf->x*ibuf->y, ibuf->rect);
533         }
534         
535         return (ibuf);
536 }