/*********************************************************
* unit:    raster            release 0.33                *
* purpose: general manipulation n dimensional matrices   *
*          n = 1, 2 and 3.			         *
* licency:     GPL or LGPL                               *
* Copyright: (c) 1998-2025 Jaroslav Fojtik               *
**********************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include "typedfs.h"
#include "common.h"

#include "raster.h"
#include "xlat_swp.h"


/********* Convert one bit depth to another ***********/

/*--------------1 bit---------------- */

void Conv1_4(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    Mask = 0x80;
    do
      {
      if((*Src & Mask) == 0)
         *Dest = 0;
      else
        *Dest = 0xF0;
       
      if(--Size1D<=0) return;
      Mask >>= 1;

      if((*Src & Mask) != 0)
        *Dest |= 0x0F;

      Dest++;
      if(--Size1D<=0) return;
      Mask >>= 1;
      } while(Mask!=0);
    Src++;
    }
}


void Conv1_8(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if((*Src & Mask) == 0)
         *Dest++ = 0;
      else
        *Dest++ = 0xFF;
      if(--Size1D<=0) return;
      }
    Src++;
    }
}

void Conv1_16(uint16_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if((*Src & Mask) == 0)
         *Dest++ = 0;
      else
        *Dest++ = 0xFFFF;
      if(--Size1D<=0) return;
      }
    Src++;
    }
}

void Conv1_24(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;
uint8_t Value;

  while(Size1D>0)
    {
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if((*Src & Mask) == 0)
         Value = 0;
      else
         Value = 0xFF;
      *Dest++ = Value;
      *Dest++ = Value;
      *Dest++ = Value;
      if(--Size1D<=0) return;
      }
    Src++;
    }
}

void Conv1_32(uint32_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if((*Src & Mask) == 0)
         *Dest++ = 0;
      else
        *Dest++ = 0xFFFFFFFF;
      if(--Size1D<=0) return;
      }
    Src++;
    }
}


#if defined(uint64_t) || defined(uint64_t_defined)
void Conv1_64(uint64_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if((*Src & Mask) == 0)
         *Dest++ = 0;
      else
        *Dest++ = 0xFFFFFFFFFFFFFFFF;
      if(--Size1D<=0) return;
      }
    Src++;
    }
}
#endif


/*--------------4 bit---------------- */


void Conv4_1(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    *Dest = 0;
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if(*Src>=0x80) *Dest |= Mask;
      if(--Size1D<=0) return;
      Mask >>= 1;
      if((0xF & *Src++)>=0x08) *Dest |= Mask;
      if(--Size1D<=0) return;
      }
    Dest++;
    }
}


void Conv4_8(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = (*Src>>4) | (*Src&0xF0);  /* Duplicate nibble. */
    Dest++;
    if(Size1D-- <= 1) break;
    *Dest = (uint16_t)(*Src & 0xF) | (*Src<<4);
    Dest++;
    Src++;
    Size1D--;
    }
}


void Conv4_16(uint16_t *Dest, const uint8_t *Src, unsigned Size1D)
{
static const uint16_t Conv4_16TAB[16] = { 
       0x0000, 0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777,
       0x8888, 0x9999, 0xAAAA, 0xBBBB, 0xCCCC, 0xDDDD, 0xEEEE, 0xFFFF};
  while(Size1D>0)
    {
    *Dest = Conv4_16TAB[*Src>>4];
    Dest++;
    if(Size1D-- <= 1) break;
    *Dest = Conv4_16TAB[*Src & 0xF];
    Dest++;
    Src++;
    Size1D--;
    }
}


void Conv4_32(uint32_t *Dest, const uint8_t *Src, unsigned Size1D)
{
static const uint32_t Conv4_32TAB[16] = { 
       0x00000000, 0x11111111, 0x22222222, 0x33333333, 0x44444444, 0x55555555, 0x66666666, 0x77777777,
       0x88888888, 0x99999999, 0xAAAAAAAA, 0xBBBBBBBB, 0xCCCCCCCC, 0xDDDDDDDD, 0xEEEEEEEE, 0xFFFFFFFF};
  while(Size1D>0)
    {
    *Dest = Conv4_32TAB[*Src>>4];
    Dest++;
    if(Size1D-- <= 1) break;
    *Dest = Conv4_32TAB[*Src & 0xF];
    Dest++;
    Src++;
    Size1D--;
    }
}


/*---------- 8bit = 1byte ------------ */

void Conv8_1(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    *Dest = 0;
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if(*Src++>=0x80) *Dest |= Mask;
      if(--Size1D<=0) return;
      }
    Dest++;
    }
}


void Conv8_4(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (uint8_t)(*Src);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (uint8_t)(*Src>>4);
    Src++;
    Dest++;    
    Size1D--;
    }
}


void Conv8_16(uint16_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x101;
  }
}


void Conv8_24(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
uint8_t b;
  while(Size1D-->0)
  {
    b = *Src++;
    *Dest++ = b;
    *Dest++ = b;
    *Dest++ = b;
  }
}


void Conv8_32(uint32_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x1010101;
  }
}


#if defined(uint64_t) || defined(uint64_t_defined)
void Conv8_64(uint64_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x101010101010101;
  }
}
#endif


/*---------- 16bit = 2byte ------------ */


void Conv16_1(uint8_t *Dest, const uint16_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    *Dest = 0;
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if(*Src++>=0x8000) *Dest |= Mask;
      if(--Size1D<=0) return;
      }
    Dest++;
    }
}


void Conv16_4(uint8_t *Dest, const uint16_t *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (uint8_t)(*Src >> 8);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (uint8_t)(*Src>>12);
    Src++;
    Dest++;    
    Size1D--;
    }
}


void Conv16_8(uint8_t *Dest, const uint16_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
    {
    *Dest++ = *Src++ >> 8;
    }
}


void Conv16_24(uint8_t *Dest, const uint16_t *Src, unsigned Size1D)
{
uint16_t w;
  while(Size1D-->0)
  {
    w = *Src++;
    *Dest++ = w >> 8;
    *Dest++ = w & 0xFF;
    *Dest++ = w >> 8;
  }
}

void Conv16_32(uint32_t *Dest, const uint16_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
    {
    *Dest++ = *Src++ * 0x10001;
    }
}


#if defined(uint64_t) || defined(uint64_t_defined)
void Conv16_64(uint64_t *Dest, const uint16_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x001000100010001;
  }
}
#endif



/*--------------------------------- */


void Conv24_8(uint8_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  Src += 2;		/* point to 3rd byte.*/
  while(Size1D-->0)
  {    
    *Dest++ = *Src;
    Src += 3;    
  }
}


void Conv24_16(uint16_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  Src += 1;		/* point to 3rd byte.*/
  while(Size1D-->0)
  {    
    *Dest++ = LD_UINT16_LO(Src);
    Src += 3;
  }
}


void Conv24_32(uint32_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {    
    *Dest++ = Src[0]*0x0100 | Src[1]*0x00010000 | Src[2]*0x01000001;
    Src += 3;
  }
}


#if defined(uint64_t) || defined(uint64_t_defined)
void Conv24_64(uint64_t *Dest, const uint8_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {    
    *Dest++ = Src[0]*0x0000010000000100 | Src[1]*0x0001000001000000 | Src[2]*0x0100000100000001;
    Src += 3;
  }
}
#endif


/*--------------------------------- */


void Conv32_1(uint8_t *Dest, const uint32_t *Src, unsigned Size1D)
{
uint8_t Mask;

  while(Size1D>0)
    {
    *Dest = 0;
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if(*Src++>=0x80000000) *Dest |= Mask;
      if(--Size1D<=0) return;
      }
    Dest++;
    }
}


void Conv32_4(uint8_t *Dest, const uint32_t *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (uint8_t)(*Src >> 24);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (uint8_t)(*Src>>28);
    Src++;
    Dest++;    
    Size1D--;
    }
}


void Conv32_8(uint8_t *Dest, const uint32_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
    {
    *Dest++ = *Src++ >> 24;
    }
}

void Conv32_16(uint16_t *Dest, const uint32_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ >> 16;
  }
}


void Conv32_24(uint8_t *Dest, const uint32_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    const uint32_t x = *Src;
    *Dest++ = 0xFF & (x >> 8);
    *Dest++ = 0xFF & (x >> 16);
    *Dest++ = 0xFF & (x >> 24);
    Src++;
  }
}


#if defined(uint64_t) || defined(uint64_t_defined)
void Conv32_64(uint64_t *Dest, const uint32_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * (uint64_t)0x000000100000001;
  }
}


void Conv64_32(uint32_t *Dest, const uint64_t *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ >> 32;
  }
}

#endif


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

#if 0
void SetValue1(uint8_t *b, unsigned x, uint32_t NewValue)
{
 b+= x >> 3;
 if(NewValue==0) *b = *b & ~(0x80 >>(x & 0x07));
	    else *b = *b |  (0x80 >>(x & 0x07));
}


uint32_t GetValue1(const uint8_t *b, unsigned x)
{
 if(b==NULL) return(0);
 b+= x >> 3;
 if((*b & (0x80 >>(x & 0x07))) != 0) return(1);
 return(0);
}


void SetValue2(uint8_t *b, unsigned x, uint32_t NewValue)
{
uint8_t v;

 v = NewValue;
 if(NewValue>3) v=3;
 b+= x >> 2;
 switch(x & 3)
   {
   case 0: v=v << 6; *b=*b & 0x3F;	break;
   case 1: v=v << 4; *b=*b & 0xCF;	break;
   case	2: v=v << 2; *b=*b & 0xF3;	break;
   case	3: *b=*b & 0xFC;
   }
 *b=*b | v;
}


uint32_t GetValue2(const uint8_t *b, unsigned x)
{
 if(b==NULL) return 0;
 b+= x >> 2;
 switch(x & 3)
   {
   case 0:return( (*b >> 6)&3 );
   case 1:return( (*b >> 4)&3 );
   case	2:return( (*b >> 2)&3 );
   case	3:return( *b & 3 );
   }
return 0;
}


/* ------------- 4 bit planes ------------- */

void SetValue4(uint8_t *b, unsigned x, uint32_t NewValue)
{
 if(b==NULL) return;
 b+= x >> 1;
 if (x & 1) *b=(*b & 0xF0) | (NewValue & 0x0F);
       else *b=(*b & 0x0F) | ((NewValue << 4) & 0xF0);
}


uint32_t GetValue4(const uint8_t *b, unsigned x)
{
 if(b==NULL) return 0;
 b+= x >> 1;
 if(x & 1) return(*b & 0x0F);
      else return(*b >> 4);
}


/* -------------- 8 bit planes ---------------- */


void SetValue8(uint8_t *b, unsigned x, uint32_t NewValue)
{
 if(b==NULL) return;
 if(NewValue>0xFF) b[x] = 0xFF;
              else b[x] = NewValue;
}


uint32_t GetValue8(const uint8_t *b, unsigned x)
{
 if(b==NULL) return 0;
 return b[x];
}


/* ------------- 16 bit planes -------------- */

void SetValue16(uint8_t *b, unsigned x, uint32_t NewValue)
{
 if(b==NULL) return;
 ((uint16_t *)b)[x] = NewValue;
}


uint32_t GetValue16(const uint8_t *b, unsigned x)
{
 if(b==NULL) return 0;
 return ((uint16_t *)b)[x];
}

/* ------------- 24 bit planes -------------- */

uint32_t GetValue24(const uint8_t *b, unsigned x)
{
 b += (3*x);
 return (uint32_t)*b | (uint32_t)b[1]<<8 | (uint32_t)b[2]<<16;
}

void SetValue24(uint8_t *b, int x, uint32_t NewValue)
{
 b += 3*x; 
 *b++ = NewValue & 0xFF;
 NewValue >>= 8;
 *b++ = NewValue & 0xFF;
 NewValue >>= 8;
 *b = NewValue & 0xFF;
}
#endif


/********* Flips ***********/


void Flip1(uint8_t *b, unsigned len)
{
uint8_t B1, B2, shift;
uint16_t W;

  if(len<=1 || b==NULL) return;

  Flip8(b,(len+7)>>3);

  shift = (1 + ~len) & 7;
  B1 = swap_bits_xlat[*b];
  while(len > 8)
  {
    B2 = B1;
    B1 = swap_bits_xlat[b[1]];
    W = (B2<<8) | B1;
    W <<= shift;
    *b++ = W >> 8;
    len -= 8;  
  }
  *b = B1 << shift;
}


void Flip2(uint8_t *b, unsigned len)
{
uint8_t B1, B2, shift;
uint16_t W;

  if(len<=1 || b==NULL) return;

  Flip8(b,(len+3)>>2);

  shift = (1 + ~(2*len)) & 7;
  B1 = swap_bits2_xlat[*b];
  while(len > 4)
  {
    B2 = B1;
    B1 = swap_bits2_xlat[b[1]];
    W = (B2<<8) | B1;
    W <<= shift;
    *b++ = W >> 8;
    len -= 4;
  }
  *b = B1 << shift;
}


void Flip4(uint8_t *b, unsigned len)
{
uint8_t *b2;
register uint8_t tmp;

 if(b==NULL || len<=1) return;


 if(len & 1)
 {		/* Odd number. */
   b2 = b + len/2;
   while(b<b2)
   {
   tmp = *b;
   *b = (*b &0x0F) | (*b2&0xF0);
   *b2 =(*b2&0x0F) | (tmp&0xF0);
   b2--;
   if(b>=b2) break;
   *b = (*b &0xF0) | (*b2&0x0F);
   *b2 =(*b2&0xF0) | (tmp&0x0F);
   b++;
   }
 }
 else
 {		/* Even number. */
   b2 = b + len/2 - 1;
   while(b<b2)
   {
     tmp = *b;
     *b = (*b2&0xF0)>>4 | ((*b2&0x0F)<<4);
     *b2 =(tmp&0xF0)>>4 | ((tmp&0x0F)<<4);
     b2--;
     b++;
   }
   if(b==b2)
   {
     tmp = *b;
     *b =(tmp&0xF0)>>4 | ((tmp&0x0F)<<4);
   }   
 }
}


/** Inplace flip for 8 bits. */
void Flip8(uint8_t *b, unsigned len)
{
uint8_t *b2;
register uint8_t tmp;

 if(b==NULL || len<=1) return;

 b2 = b + len - 1;
 while(b<b2)
   {
   tmp = *b;
   *b = *b2;
   *b2 = tmp;
   b++; b2--;
   }
}

void Flip16(uint16_t *w, unsigned len)
{
uint16_t *w2;
register uint16_t tmp;

 if(w==NULL || len<=1) return;

 w2 = w + len - 1;
 while(w<w2)
   {
   tmp = *w;
   *w = *w2;
   *w2 = tmp;
   w++; w2--;
   }
}


void Flip24(uint8_t *b, unsigned len)
{
uint8_t *b2;
register uint8_t tmp;

 if(b==NULL || len<=1) return;

 b2 = b + 3*(len-1);
 while(b<b2)
   {
   tmp=b[0];	b[0]=b2[0];	b2[0]=tmp;
   tmp=b[1];	b[1]=b2[1];	b2[1]=tmp;
   tmp=b[2];	b[2]=b2[2];	b2[2]=tmp;
   b2-=3;
   b+=3;
   }
}


void Flip32(uint32_t *d, unsigned len)
{
uint32_t *d2;
register uint32_t tmp;

 if(d==NULL || len<=1) return;

 d2 = d + len - 1;
 while(d<d2)
   {
   tmp = *d;
   *d = *d2;
   *d2 = tmp;
   d++; d2--;
   }
}


void Flip64(uint64_t_fix *q, unsigned len)
{
uint64_t_fix *q2;
register uint64_t_fix tmp;

 if(q==NULL || len<=1) return;

 //printf("Flip1D64 %d ",p);
 q2 = q + len - 1;
 while(q<q2)
   {
   tmp = *q;
   *q = *q2;
   *q2 = tmp;
   q++; q2--;
   }
}


void Peel1BitNStep(uint8_t *Buffer1Bit, const uint8_t *BufferSrc, unsigned count, uint16_t PlaneStep)
{
uint8_t Buff = 0;
uint8_t Mask = 0x80;
const uint8_t plane = PlaneStep & 0xFF;

 PlaneStep >>= 8;

 if(Buffer1Bit==NULL || BufferSrc==NULL) return;
 if(plane>=8)
 {
   memset(Buffer1Bit,0,(count+7)/8);
   return;
 }

 while(count-- > 0)
 {    
   if((*BufferSrc>>plane)&1)
	Buff|=Mask;
   BufferSrc += PlaneStep;
   Mask >>= 1;
   if(Mask==0)
   {
     *Buffer1Bit++ = Buff;
     Mask = 0x80;
     Buff = 0;
   }
 }
 if(Mask!=0x80)
     *Buffer1Bit = Buff;
}


void Join1BitNStep(const uint8_t *Buffer1Bit, uint8_t *Buffer, unsigned count, uint16_t PlaneStep)
{
uint8_t Mask = 0x80;
const uint8_t plane = PlaneStep & 0xFF;
uint8_t MaskOr, MaskAnd;

 MaskOr = 1 << (PlaneStep & 0xFF);
 MaskAnd = ~MaskOr;
 PlaneStep >>= 8;

 if(count==0 || Buffer1Bit==NULL || Buffer==NULL) return;
 if(plane>=8) return;

 while(count-- > 0)
 {    
   if(*Buffer1Bit & Mask)
     *Buffer |= MaskOr;
   else	
     *Buffer &= MaskAnd;

   Buffer += PlaneStep;
   Mask >>= 1;
   if(Mask==0)
   {
     Buffer1Bit++;
     Mask = 0x80;
   }
 }
}


void Join8BitNStep(const uint8_t *Buffer8Bit, uint8_t *Buffer, unsigned count, uint8_t ByteStep)
{
 while(count-- > 0)
 {
   *Buffer = *Buffer8Bit++;
   Buffer += ByteStep;
 }
}


void Peel8BitNStep(uint8_t *Buffer8Bit, const uint8_t *BufferSrc, unsigned count, uint8_t ByteStep)
{
 while(count-- > 0)
 {
   *Buffer8Bit++ = *BufferSrc;
   BufferSrc += ByteStep;
 }
}
