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

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

#include "raster.h"


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

void Conv1_8(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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(WORD *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE Mask;
BYTE 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(DWORD *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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++;
    }
}


#ifdef QWORD
void Conv1_64(QWORD *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = (*Src>>4) | (*Src&0xF0);  /* Duplicate nibble. */
    Dest++;
    if(Size1D-- <= 1) break;
    *Dest = (WORD)(*Src & 0xF) | (*Src<<4);
    Dest++;
    Src++;
    Size1D--;
    }
}


void Conv4_16(WORD *Dest, const BYTE *Src, unsigned Size1D)
{
static const WORD 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(DWORD *Dest, const BYTE *Src, unsigned Size1D)
{
static const DWORD 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(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const BYTE *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (BYTE)(*Src);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (BYTE)(*Src>>4);
    Src++;
    Dest++;    
    Size1D--;
    }
}


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


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


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


#ifdef QWORD
void Conv8_64(QWORD *Dest, const BYTE *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x101010101010101;
  }
}
#endif


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


void Conv16_1(BYTE *Dest, const WORD *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const WORD *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (BYTE)(*Src >> 8);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (BYTE)(*Src>>12);
    Src++;
    Dest++;    
    Size1D--;
    }
}


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

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


#ifdef QWORD
void Conv16_64(QWORD *Dest, const WORD *Src, unsigned Size1D)
{
  while(Size1D-->0)
  {
    *Dest++ = *Src++ * 0x001000100010001;
  }
}
#endif



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


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


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


void Conv32_1(BYTE *Dest, const DWORD *Src, unsigned Size1D)
{
BYTE 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(BYTE *Dest, const DWORD *Src, unsigned Size1D)
{
  while(Size1D>0)
    {
    *Dest = 0xF0 & (BYTE)(*Src >> 24);
    Src++;
    if(Size1D-- <= 1) break;
    *Dest |= (BYTE)(*Src>>28);
    Src++;
    Dest++;    
    Size1D--;
    }
}


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

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


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

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


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


void SetValue2(BYTE *b, unsigned x, DWORD NewValue)
{
BYTE 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;
}


DWORD GetValue2(const BYTE *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(BYTE *b, unsigned x, DWORD NewValue)
{
 if(b==NULL) return;
 b+= x >> 1;
 if (x & 1) *b=(*b & 0xF0) | (NewValue & 0x0F);
       else *b=(*b & 0x0F) | ((NewValue << 4) & 0xF0);
}


DWORD GetValue4(const BYTE *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(BYTE *b, unsigned x, DWORD NewValue)
{
 if(b==NULL) return;
 if(NewValue>0xFF) b[x] = 0xFF;
              else b[x] = NewValue;
}


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


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

void SetValue16(BYTE *b, unsigned x, DWORD NewValue)
{
 if(b==NULL) return;
 ((WORD *)b)[x] = NewValue;
}


DWORD GetValue16(const BYTE *b, unsigned x)
{
 if(b==NULL) return 0;
 return ((WORD *)b)[x];
}

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

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

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


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


void Flip1(BYTE *b, unsigned len)
{
  BYTE Mask1, Mask2;
  BYTE *b2;
  if(len<=1) return;	// Prevent underflow 0-1
  len--;

  Mask1 = 0x80;
  b2 = b + (len>>3);
  Mask2 = 0x80 >>(len & 0x07);

  while(b<b2 || (b==b2 && Mask1>Mask2))
  {
    if(*b & Mask1)
    {
      if((*b2 & Mask2) == 0)
      {
        *b &= ~Mask1;
        *b2 |= Mask2;
      }
      //else{}		// Both values are 1, no op needed.
    }
    else
    {
      if(*b2 & Mask2)
      {
        *b |= Mask1;
        *b2 &= ~Mask2;      
      }
      //else		// Both values are 0, no op needed.
    }
   
    if(Mask1==1)
    {
      Mask1 = 0x80;
      b++;
    }
    else
      Mask1 >>= 1;

    if(Mask2==0x80)
    {
      Mask2 = 1;
      b2--;
    }
    else
      Mask2 <<= 1;   
  }  
}


void Flip4(BYTE *b, unsigned len)
{
BYTE *b2;
register BYTE 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(BYTE *b, unsigned len)
{
BYTE *b2;
register BYTE tmp;

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

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

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

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

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


void Flip24(BYTE *b, unsigned len)
{
BYTE *b2;
register BYTE 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(DWORD *d, unsigned len)
{
DWORD *d2;
register DWORD tmp;

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

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


#ifdef QWORD
void Flip64(QWORD *q, unsigned len)
{
QWORD *q2;
register QWORD tmp;

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

 q2 = q + len - 1;
 while(q<q2)
   {
   tmp = *q;
   *q = *q2;
   *q2 = tmp;
   q++; q2--;
   }
}
#endif /* QWORD */



