Logo Search packages:      
Sourcecode: blender version File versions

amiga.c

/**
 * amiga.c
 *
 * $Id: amiga.c,v 1.9 2003/12/04 18:18:05 sirdude Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

#include "imbuf.h"
#include "imbuf_patch.h"

#include "IMB_imbuf_types.h"
#include "IMB_imbuf.h"

#include "IMB_cmap.h"
#include "IMB_allocimbuf.h"
#include "IMB_bitplanes.h"
#include "IMB_amiga.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

/* actually hard coded endianness */
#define GET_BIG_LONG(x) (((uchar *) (x))[0] << 24 | ((uchar *) (x))[1] << 16 | ((uchar *) (x))[2] << 8 | ((uchar *) (x))[3])
#define GET_LITTLE_LONG(x) (((uchar *) (x))[3] << 24 | ((uchar *) (x))[2] << 16 | ((uchar *) (x))[1] << 8 | ((uchar *) (x))[0])
#define SWAP_L(x) (((x << 24) & 0xff000000) | ((x << 8) & 0xff0000) | ((x >> 8) & 0xff00) | ((x >> 24) & 0xff))
#define SWAP_S(x) (((x << 8) & 0xff00) | ((x >> 8) & 0xff))

/* more endianness... should move to a separate file... */
#if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__)
#define GET_ID GET_BIG_LONG
#define LITTLE_LONG SWAP_LONG
#else
#define GET_ID GET_LITTLE_LONG
#define LITTLE_LONG ENDIAN_NOP
#endif

static uchar *decodebodyscanl(uchar *body, short bytes, uchar **list, short d)
{
      for (;d>0;d--){
            uchar *point;
            short todo;
            uchar i,j;

            point = *(list++);
            todo=bytes;
            while (todo>0){
                  i = *body++;

                  if (i & 128){                 /* fill */
                        if (i==128) continue;   /* nop  */

                        i=257-i;
                        todo-=i;
                        j = *(body++);
                        do{
                              *(point++) = j;
                              i--;
                        }while (i);
                  } else{                       /* copy */
                        i++;
                        todo-=i;

                        do{
                              *(point++) = *(body++);
                              i--;
                        }while (i);
                  }
            }
            if (todo) return (0);
      }
      return(body);
}


static uchar *decodebodyh(struct ImBuf *ibuf, uchar *body)
{
      if (ibuf->y==1) {
            body=decodebodyscanl(body, WIDTHB(ibuf->x), (uchar **)ibuf->planes, ibuf->depth);
      }
      else {
            unsigned int **list;
            short skipx,i,bytes,y;

            list = imb_copyplanelist(ibuf);
            if (list == 0) return (0);

            y=ibuf->y;
            bytes = WIDTHB(ibuf->x);
            skipx = ibuf->skipx;

            for (;y>0;y--){
                  body=decodebodyscanl(body, bytes, (uchar **)list, ibuf->depth);
                  if (body == 0) return (0);

                  for (i=ibuf->depth-1;i>=0;i--){
                        list[i] += skipx;
                  }
            }
            free(list);
      }
      return(body);
}


static uchar *decodebodykolum(uchar *body, short bytes, uchar **list, short d, int next)
{
      for (;d>0;d--){
            uchar *point;
            short todo;
            uchar i,j;

            point = *(list++);
            todo=bytes;
            while (todo>0){
                  i = *body++;

                  if (i & 128){                 /* fill */
                        if (i==128) continue;   /* nop  */

                        i=257-i;
                        todo-=i;
                        j = *body++;
                        do{
                              *point = j;
                              point += next;
                              i--;
                        }while (i);
                  }
                  else{                   /* copy */
                        i++;
                        todo-=i;

                        do{
                              *point = *body++;
                              point += next;
                              i--;
                        }while (i);
                  }
            }
            if (todo) return (0);
      }
      return(body);
}


static uchar *decodebodyv(struct ImBuf *ibuf, uchar *body)
{
      uchar **list;
      int skipx, i, bytes, times;

      list = (uchar **)imb_copyplanelist(ibuf);
      if (list == 0) return (0);

      bytes = ibuf->y;
      times = WIDTHB(ibuf->x);
      skipx = ibuf->skipx << 2;

      for (;times>0;times--){
            body=decodebodykolum(body,bytes,list,ibuf->depth,skipx);
            if (body == 0) return (0);

            for (i=ibuf->depth-1;i>=0;i--){
                  list[i] += 1;
            }
      }
      free(list);
      return(body);
}

static uchar *makebody(uchar **planes, short bytes, short depth, uchar *buf)
{
      uchar *bitplstart,*temp;

      register uchar last,this,*bitpl;
      register short todo;
      register int copy;

      bytes--;
      for (;depth>0;depth--){
            bitpl = *(planes++);
            bitplstart = bitpl;
            todo = bytes;
            last = *bitpl++;
            this = *bitpl++;
            copy = last^this;
            while (todo>0){

                  if (copy){
                        do{
                              last = this;
                              this = *bitpl++;
                              if (last == this){
                                    if (this == bitpl[-3]){       /* three identical ones? */
                                          todo -= 1;        /* set todo */
                                          break;
                                    }
                              }
                        }while (--todo != 0);

                        copy=bitpl-bitplstart;
                        copy -= 1;
                        if (todo) copy -= 2;

                        temp = bitpl;
                        bitpl = bitplstart;

                        while (copy){
                              last = copy;
                              if (copy>MAXDAT) last = MAXDAT;
                              copy -= last;
                              *buf++ = last-1;
                              do{
                                    *buf++ = *bitpl++;
                              }while(--last != 0);
                        }
                        bitplstart = bitpl;
                        bitpl = temp;
                        last = this;

                        copy = FALSE;
                  }
                  else{
                        while (*bitpl++ == this){     /* search for first different bye */
                              if (--todo == 0) break; /* or end of line */
                        }
                        bitpl -= 1;
                        copy = bitpl-bitplstart;
                        bitplstart = bitpl;
                        todo -= 1;
                        this = *bitpl++;

                        while (copy){
                              if (copy>MAXRUN){
                                    *buf++ = -(MAXRUN-1);
                                    *buf++ = last;
                                    copy -= MAXRUN;
                              }
                              else{
                                    *buf++ = -(copy-1);
                                    *buf++ = last;
                                    break;
                              }
                        }
                        copy=TRUE;
                  }
            }
      }
      return (buf);
}


short imb_encodebodyh(struct ImBuf *ibuf, int file)
{
      uchar *buf, *endbuf, *max;
      int size, line, ok = TRUE;
      unsigned int **list;
      short skipx,i,y;

      line = WIDTHB(ibuf->x) * ibuf->depth;
      line += (line >> 6) + 10;
      size = 16 * line;
      if (size < 16384) size = 16384;
      
      buf = (uchar *) malloc(size);
      if (buf == 0) return (0);

      max = buf + size - line;
      
      list = imb_copyplanelist(ibuf);
      if (list == 0){
            free(buf);
            return (0);
      }

      y=ibuf->y;
      skipx = ibuf->skipx;
      endbuf = buf;
      
      for (y=ibuf->y;y>0;y--){
            endbuf = makebody((uchar **)list, WIDTHB(ibuf->x), ibuf->depth, endbuf);
            if (endbuf==0){
                  ok = -20;
                  break;
            }
            if (endbuf >= max || y == 1){ 
                  size = endbuf-buf;
                  if (write(file,buf,size)!=size) ok = -19;
                  endbuf = buf;
            }
            for (i=ibuf->depth-1;i>=0;i--){
                  list[i] += skipx;
            }
            if (ok != TRUE) break;
      }
      free(list);

      free(buf);
      return(ok);
}


short imb_encodebodyv(struct ImBuf *ibuf, int file)
{
      struct ImBuf *ibufv;
      uchar *buf,*endbuf;
      short x,offset;

      buf = (uchar *) malloc((ibuf->y + (ibuf->y >> 6) + 10) * ibuf->depth);
      if (buf == 0) return (0);

      ibufv=IMB_allocImBuf((ibuf->y)<<3,1, ibuf->depth, 0, 1);
      if (ibufv == 0){
            free(buf);
            return (0);
      }

      offset=0;

      for(x = WIDTHB(ibuf->x);x>0;x--){
            register short i;

            for(i = ibuf->depth-1 ;i>=0;i--){
                  register uchar *p1,*p2;
                  register int skipx;
                  register short y;

                  skipx = (ibuf->skipx)*sizeof(int *);
                  p1=(uchar *)ibuf->planes[i];
                  p2=(uchar *)ibufv->planes[i];
                  p1 += offset;

                  for (y=ibuf->y;y>0;y--){
                        *(p2++) = *p1;
                        p1 += skipx;
                  }
            }
            offset += 1;

            endbuf=makebody((uchar **)ibufv->planes, ibuf->y, ibuf->depth, buf);
            if (endbuf==0) return (-20);
            if (write(file,buf,endbuf-buf)!=endbuf-buf) return (-19);
      }
      free(buf);
      IMB_freeImBuf(ibufv);
      return (TRUE);
}

static uchar *readbody(struct ImBuf *ibuf, uchar *body)
{
      int skipbuf,skipbdy,depth,y,offset = 0;

      skipbuf = ibuf->skipx;
      skipbdy = WIDTHB(ibuf->x);

      for (y = ibuf->y; y> 0; y--){
            for( depth = 0; depth < ibuf->depth; depth ++){
                  memcpy(ibuf->planes[depth] + offset, body, skipbdy);
                  body += skipbdy;
            }
            offset += skipbuf;
      }
      return body;
}

struct ImBuf *imb_loadamiga(int *iffmem,int flags)
{
      int chunk,totlen,len,*cmap=0,cmaplen,*mem,ftype=0;
      uchar *body=0;
      struct BitMapHeader bmhd;
      struct ImBuf *ibuf=0;

      mem = iffmem;
      bmhd.w = 0;

      if (GET_ID(mem) != FORM) return (0);
      if (GET_ID(mem+2) != ILBM) return (0);
      totlen= (GET_BIG_LONG(mem+1) + 1) & ~1;
      mem += 3;
      totlen -= 4;


      while(totlen > 0){
            chunk = GET_ID(mem);
            len= (GET_BIG_LONG(mem+1) + 1) & ~1;
            mem += 2;

            totlen -= len+8;

            switch (chunk){
            case BMHD:
                  memcpy(&bmhd, mem, sizeof(struct BitMapHeader));

                  bmhd.w = BIG_SHORT(bmhd.w);
                  bmhd.h = BIG_SHORT(bmhd.h);
                  bmhd.x = BIG_SHORT(bmhd.x);
                  bmhd.y = BIG_SHORT(bmhd.y);
                  bmhd.transparentColor = BIG_SHORT(bmhd.transparentColor);
                  bmhd.pageWidth = BIG_SHORT(bmhd.pageWidth);
                  bmhd.pageHeight = BIG_SHORT(bmhd.pageHeight);
                  
                  break;
            case BODY:
                  body = (uchar *)mem;
                  break;
            case CMAP:
                  cmap = mem;
                  cmaplen = len/3;
                  break;
            case CAMG:
                  ftype = GET_BIG_LONG(mem);
                  break;
            }
            mem = (int *)((uchar *)mem +len);
            if (body) break;
      }
      if (bmhd.w == 0) return (0);
      if (body == 0) return (0);
      
      if (flags & IB_test) ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes, 0, 0);
      else ibuf = IMB_allocImBuf(bmhd.w, bmhd.h, bmhd.nPlanes + (bmhd.masking & 1),0,1);

      if (ibuf == 0) return (0);

      ibuf->ftype = (ftype | AMI);
      
      if (cmap){
            ibuf->mincol = 0;
            ibuf->maxcol = cmaplen;
            imb_addcmapImBuf(ibuf);
            imb_makecolarray(ibuf, (uchar *)cmap, 0);
      }

      if (flags & IB_test){
            if (flags & IB_freem) free(iffmem);
            return(ibuf);
      }
      
      switch (bmhd.compression){
      case 0:
            body= readbody(ibuf, body);
            break;
      case 1:
            body= decodebodyh(ibuf,body);
            break;
      case 2:
            body= decodebodyv(ibuf,body);
            ibuf->type |= IB_subdlta;
            break;
      }

      if (flags & IB_freem) free(iffmem);

      if (body == 0){
            free (ibuf);
            return(0);
      }
      
      /* forget stencil */
      ibuf->depth = bmhd.nPlanes;
      
      if (flags & IB_rect){
            imb_addrectImBuf(ibuf);
            imb_bptolong(ibuf);
            imb_freeplanesImBuf(ibuf);
            if (ibuf->cmap){
                  if ((flags & IB_cmap) == 0) IMB_applycmap(ibuf);
            } else if (ibuf->depth == 18){
                  int i,col;
                  unsigned int *rect;

                  rect = ibuf->rect;
                  for(i=ibuf->x * ibuf->y ; i>0 ; i--){
                        col = *rect;
                        col = ((col & 0x3f000) << 6) + ((col & 0xfc0) << 4) + ((col & 0x3f) << 2);
                        col += (col & 0xc0c0c0) >> 6;
                        *rect++ = col;
                  }
                  ibuf->depth = 24;
            } else if (ibuf->depth <= 8) { /* no colormap and no 24 bits: b&w */
                  uchar *rect;
                  int size, shift;

                  if (ibuf->depth < 8){
                        rect = (uchar *) ibuf->rect;
                        rect += 3;
                        shift = 8 - ibuf->depth;
                        for (size = ibuf->x * ibuf->y; size > 0; size --){
                              rect[0] <<= shift;
                              rect += 4;
                        }
                  }
                  rect = (uchar *) ibuf->rect;
                  for (size = ibuf->x * ibuf->y; size > 0; size --){
                        rect[1] = rect[2] = rect[3];
                        rect += 4;
                  }
                  ibuf->depth = 8;
            }
      }

      if ((flags & IB_ttob) == 0) IMB_flipy(ibuf);

      if (ibuf) {
            if (ibuf->rect) 
                  IMB_convert_rgba_to_abgr(ibuf->x*ibuf->y, ibuf->rect);
      }
      
      return (ibuf);
}

Generated by  Doxygen 1.6.0   Back to index