/* ChunkyToBM.c © Paweî Marciniak <pmarciniak@lodz.home.pl>*/
#include <exec/execbase.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/rastport.h>
#include <graphics/gfxbase.h>
#include <graphics/view.h>
#include <intuition/screens.h>
#include <utility/tagitem.h>
#include <proto/exec.h>
#include <proto/graphics.h>
#include <proto/utility.h>

#include "/include/libraries/image.h"
#include "chunkytobm.h"

#define DEBUG
VOID __stdargs CleanUp( struct NewBitMap *, struct Screen * );
struct NewBitMap *MyAllocBitMap( UWORD, UWORD, BYTE );

/* ChunkyToBitMapA() (c) 1997 Paweî Marciniak
  Modify date  |  Version  |  Comment
---------------+-----------+------------------------------
30-05-97 18:00 |  1.0      |
1-06-97  8:42  |  1.1      |
1-06-97 15:48  |  1.2      |
1-06-97 16:56  |  1.21     | 
2-06-97 15:44  |  1.22     |
8-06-97 12:23  |  1.23     |
12-08-97 18:47 |  1.3      |
14-08-97 12:12 |  1.4      |
12-09-97 18:03 |  1.5      |  Zamiana WritePixel() na WritePixelLine8()
13-09-97 18:25 |  1.6      |  Usuniëcie pëtli ponownego remapowania
11-10-97 19:33 |  1.7      |  Dodane tagi
13-01-98 19:51 |  1.71     |  Dodanie sprawdzenia czy AllocVec() zwraca NULL
13-01-98 20:04 |  1.72     |
*/
struct BitMap * __saveds __asm ChunkyToBitMapA( register __a0 struct Screen *Pal_Screen_reg, register __a1 struct ChunkyImg *CI_reg, register __a2 struct TagItem *Tags  )
{
  UBYTE R, G, B;
  register UBYTE *chunkyPtr, *PalettePtr, *arraymem, *arrayPtr;
  register ULONG i, n, m;
  ULONG Error;
  LONG chunkysize, precision = PRECISION_GUI;
  struct RastPort temprp, *ChunkyRPort;
  struct NewBitMap *NBM;

  struct Screen *Pal_Screen = Pal_Screen_reg;
  struct ChunkyImg *CI = CI_reg;
  struct TagItem *ti, *TagsTmp = Tags;
  chunkyPtr = CI->ci_ChunkyData;
  PalettePtr = CI->ci_Palette;
  chunkysize=CI->ci_Width*CI->ci_Height;

/* Tagi */
  while ( ti = NextTagItem( &TagsTmp ) )
  {
    switch ( ti->ti_Tag )
    {
      case CTBM_Precision:
        precision = ti->ti_Data;
      break;

      default:
      break;
    }
  }

/* sprawdzam iloôê kolorów jeôli > 256 wyjôcie */
  if(CI->ci_NumColors > 256)
  {
    Error=1000;
    return( 0 );
  }



  if(!(ChunkyRPort=AllocVec( sizeof(struct RastPort),MEMF_ANY|MEMF_CLEAR )))
  {
    Error=1002;
    return( 0 );
  }

  InitRastPort( ChunkyRPort );
  
  if(!( NBM = (struct NewBitMap*)MyAllocBitMap( CI->ci_Width,
                                                CI->ci_Height,
                                                Pal_Screen->RastPort.BitMap->Depth)))
  {
    FreeVec( ChunkyRPort );
    Error=1003;
    return( 0 );
  }
  NBM->Width = CI->ci_Width;
  NBM->Height = CI->ci_Height;
  NBM->NumColors = CI->ci_NumColors;
  ChunkyRPort->BitMap = (struct BitMap *)NBM;

/* wypeîniamy tabelë wartoôciami -1 */
  for( i=0; i<CI->ci_NumColors; i++ )
    NBM->ColorTab[i] = -1;

/* zamieniam wartoôci RGB na numer koloru i wpisujë do tablicy */
  for( i=0; i<(CI->ci_NumColors); i++ )
  {
    R=*PalettePtr;
    PalettePtr++;
    G=*PalettePtr;
    PalettePtr++;
    B=*PalettePtr;
    PalettePtr++;
    NBM->ColorTab[i]=ObtainBestPen( Pal_Screen->ViewPort.ColorMap,
                                  (ULONG)((R) << 24),
                                  (ULONG)((G) << 24),
                                  (ULONG)((B) << 24),
                                   OBP_Precision, precision, TAG_DONE );
    if(NBM->ColorTab[i] ==-1)
    {
      Error=1001;
      CleanUp( NBM, Pal_Screen );
      return( 0 );
    }
  }

/* Iniciacja temprp */
  InitRastPort( &temprp );
  if(!(temprp.BitMap = AllocBitMap( CI->ci_Width, 1,
                  Pal_Screen->RastPort.BitMap->Depth, BMF_CLEAR, 0 )))
  {
    FreeVec( ChunkyRPort );
    Error=1003;
    CleanUp( NBM, Pal_Screen );
    return( 0 );
  }


  if(!(arraymem=(UBYTE *)AllocVec((CI->ci_Width + 16), MEMF_ANY | MEMF_CLEAR )))
  {
    FreeVec( ChunkyRPort );
    FreeBitMap( temprp.BitMap );
    Error=1003;
    CleanUp( NBM, Pal_Screen );
    return( 0 );
  }

/* konwersja chunky na bitmapë i remaping */
  for( n = 0; n < CI->ci_Height; n++ )
  {
    arrayPtr=arraymem;
    CopyMem( chunkyPtr, arrayPtr, CI->ci_Width );
    for( m = 0; m < CI->ci_Width; m++ )
    {
      *arrayPtr=NBM->ColorTab[*arrayPtr]; /* remaping */
      arrayPtr++;
    }
    chunkyPtr+=CI->ci_Width;
    WritePixelLine8( ChunkyRPort, 0, n, CI->ci_Width, arraymem, &temprp );
  }
  FreeBitMap( temprp.BitMap );
  FreeVec( arraymem );
  FreeVec( ChunkyRPort );
  return( (struct BitMap *)NBM );
}

/**FreeChunky***********************************************************/


/* FreeChunky() (c) 1997 Paweî Marciniak
  Modify date  |  Version  |  Comment
---------------+-----------+------------------------------
30-05-97 18:00 |  1.0      |
8-06-97 12:23  |  1.1      |
12-08-97 18:53 |  2.0      |
14-08-97 12:15 |  3.0      |
*/
VOID __saveds __asm FreeChunky( register __a0 struct Screen *Pal_Screen, register __a1 struct BitMap *BM )
{
  CleanUp( (struct NewBitMap *)BM, Pal_Screen );
}


/**CleanUp**************************************************************/


/* CleanUp() (c) 1997 Paweî Marciniak
  Modify date  |  Version  |  Comment
---------------+-----------+------------------------------
12-08-97 12:10 |  1.0      |
*/
VOID CleanUp( struct NewBitMap *NewBM, struct Screen *Pal_Screen )
{
  ULONG i;

  if( NewBM )
  {
  /* Zwalniam pîaty bitowe */
    FreeVec( NewBM->Planes[0] );

  /* Zwalniam wszystkie kolory */
      for( i=0; i<NewBM->NumColors; i++ )
    {
      if( NewBM->ColorTab[i] > -1)
      {
         ReleasePen( Pal_Screen->ViewPort.ColorMap,NewBM->ColorTab[i] );
        NewBM->ColorTab[i] = -1;
      }
    }
    FreeVec( NewBM);
    NewBM = NULL;
  }
}

/**MyAllocBitMap********************************************************/


/* MyAllocBitMap() (c) 1997 Paweî Marciniak
  Modify date  |  Version  |  Comment
---------------+-----------+------------------------------
14-08-97 12:10 |  1.0      |
13-01-98 20:03 |  1.01     |
26-09-98 17:44 |  1.02     | Change in first AllocVec MEMF_CHIP on MEMF_ANY
*/
struct NewBitMap *MyAllocBitMap( UWORD Width, UWORD Height, BYTE Depth )
{
  int i;
  struct NewBitMap *NBM;
  PLANEPTR Data;

  if(!(NBM = AllocVec( sizeof(struct NewBitMap), MEMF_ANY)))
    return( 0 );
  InitBitMap((struct BitMap *)NBM,Depth, Width, Height );

  if(!(Data = (PLANEPTR)AllocVec( RASSIZE( Width, Height)*Depth, MEMF_CHIP )))
  {
    FreeVec( NBM );
    return( 0 );
  }
  for(i = 0 ; i < Depth ; i++, Data += RASSIZE( Width, Height) )
    NBM->Planes[i] = Data;
  return( NBM);
}

/***********************************************************************/
