/*************************************************************
 * Unit:    raster            release 0.18                   *
 * Purpose: General manipulation n dimensional matrices      *
 *          n = 1, 2 and 3.			             *
 * Modul:   raster.cc                                        *
 * Licency: GPL or LGPL                                      *
 * Copyright: (c) 1998-2019 Jaroslav Fojtik                  *
 *************************************************************/
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#include "common.h"

#include "raster.h"
#include "ras_prot.h"


#ifdef QWORD
 #ifndef _UI64_MAX
  #ifdef __BORLANDC__
   #define _UI64_MAX    18446744073709551615ui64
  #else 
   #define _UI64_MAX    0xFFFFFFFFFFFFFFFFll
  #endif
 #endif
#endif


/// Get nearly available amount of planes thatis supported by rasters.
int NearAvailPlanes(int n)
{
  if(n<1)
  {
    if(n==0) return 0;
    if(n>=-32) return -32;	// float
    return -64;			// double    
  }
  if(n<=1) return(1);		// bit
  if(n<=2) return(2);
  if(n<=4) return(4);
  if(n<=8) return(8);		// byte
  if(n<=16) return(16);		// word
  if(n<=24) return(24);
  if(n<=32) return(32);		// dword
  if(n<=64) return(64);		// qword
  return(n);
}


void Raster1DAbstract::Erase1DStub(void)
{
 if(Shadow)
 {
   Data1D = NULL;
   Size1D = 0;
   return;
 }

 if(Data1D!=NULL) 
   {free(Data1D);Data1D=NULL;}
 Size1D = 0;
}


void Raster1DAbstract::Allocate1D(unsigned NewSize1D)
{
 if(Data1D!=NULL) 
   {
   if(Size1D==NewSize1D) return;	// No reallocation needed.
   free(Data1D); Data1D=NULL;
   }
 Data1D = malloc((((unsigned long)abs(GetPlanes())*NewSize1D)+7)/8);
 if(Data1D==NULL)
     RaiseError(RasterId|No_Memory,this);
 Size1D = NewSize1D;
}


void Raster1DAbstract::Cleanup(void)
{
 if(Data1D==NULL) return;
 memset(Data1D,0,Size1D*GetPlanes()/8);
}


/** Push data to a given container. */
void Raster1DAbstract::Get(Raster1DAbstract &R1) const
{
int i,maxi;
int shift;
 maxi = Size1D>R1.Size1D?Size1D:R1.Size1D;

 if(R1.GetPlanes()==GetPlanes())
   {
   if(Data1D!=NULL && R1.Data1D!=NULL)
      memcpy(R1.Data1D, Data1D, ((long)maxi*labs(GetPlanes())+7)/8);
   return;
   }

 if(R1.GetPlanes()<0 || GetPlanes()<0)	// Floating point conversion
   {
   if(GetPlanes()<0)	// Both source and target are FP.
     {
     for(i=0; i<maxi; i++)
       R1.SetValue1Dd(i,GetValue1Dd(i));
     }
   else			// Source is integer type
     {
     double MaxVal = (unsigned long)1 << GetPlanes();
     for(i=0; i<maxi; i++)
       R1.SetValue1Dd(i,GetValue1D(i)*MaxVal);
     }
   return;
   }

 shift = R1.GetPlanes() - GetPlanes();
 if(shift>0)
   {
   for(i=0; i<maxi; i++)
     R1.SetValue1D(i,GetValue1D(i)<<shift);
   }
 if(shift<0)
   {
   shift = -shift;
   for(i=0; i<maxi; i++)
     R1.SetValue1D(i,GetValue1D(i)>>shift);
   } 
}



/** Copy data from a given container. */
void Raster1DAbstract::Set(const Raster1DAbstract &R1)
{
unsigned i,maxi;
signed char shift;

  if(Data1D==NULL || R1.Data1D==NULL) return;
  maxi = Size1D>R1.Size1D?Size1D:R1.Size1D;

  if(GetPlanes() == R1.GetPlanes())		// No bitplane change - copy data only
    {
    i = Size1D;
    if(R1.Size1D<i) i=R1.Size1D;
    memcpy(Data1D, R1.Data1D, ((long)i*labs(GetPlanes())+7)/8);
    return;
    }

  if(GetPlanes()<0 || R1.GetPlanes()<0)		// Floating point operation
    {
    for(i=0;i<maxi;i++)
      SetValue1Dd(i,R1.GetValue1Dd(i));
    return;
    }

  shift = GetPlanes() - R1.GetPlanes();
  if(shift>0)
    {
    for(i=0;i<maxi;i++)
      SetValue1D(i,R1.GetValue1D(i)<<shift);
    return;
    }
  else
    {
    shift = -shift;
    for(i=0;i<maxi;i++)
      SetValue1D(i,R1.GetValue1D(i)>>shift);
    return;
    }
}



#ifdef _REENTRANT

void Raster1DAbstract::PTR_Get(const void *RAW_Data1D, Raster1DAbstract &R1) const
{
int i,maxi;
int shift;
 maxi = Size1D>R1.Size1D?Size1D:R1.Size1D; 

 if(R1.GetPlanes()==GetPlanes())
   {
   if(Data1D!=NULL && R1.Data1D!=NULL)
      memcpy(R1.Data1D, RAW_Data1D, ((long)maxi*labs(GetPlanes())+7)/8);
   return;
   }

 if(R1.GetPlanes()<0 || GetPlanes()<0)	// Floating point conversion 
   {
   if(GetPlanes()<0)	// Both source and target are FP.
     {
     for(i=0; i<maxi; i++)
       R1.SetValue1Dd(i,PTR_GetValue1Dd(RAW_Data1D,i));
     }
   else			// Source is integer type
     {
     double MaxVal = (unsigned long)1 << GetPlanes();
     for(i=0; i<maxi; i++)
       R1.SetValue1Dd(i,PTR_GetValue1D(RAW_Data1D,i)*MaxVal);
     }
   return;     
   }

 shift = R1.GetPlanes() - GetPlanes();
 if(shift>0)
   {
   for(i=0;i<maxi;i++)
     R1.SetValue1D(i,PTR_GetValue1D(RAW_Data1D,i)<<shift);
   }
 if(shift<0)
   {
   shift = -shift;
   for(i=0;i<maxi;i++)
     R1.SetValue1D(i,PTR_GetValue1D(RAW_Data1D,i)>>shift);
   }
}


void Raster1DAbstract::PTR_Set(void *RAW_Data1D, const Raster1DAbstract &R1)
{
unsigned i,maxi;
signed char shift;

  if(Data1D==NULL || R1.Data1D==NULL) return;
  maxi = Size1D>R1.Size1D?Size1D:R1.Size1D;

  if(GetPlanes()==R1.GetPlanes())	// No bitplane change - copy data only
    {
    i = Size1D;		// Minimal equal range
    if(R1.Size1D<i) i=R1.Size1D;
    memcpy(RAW_Data1D, R1.Data1D, ((long)i*labs(GetPlanes())+7)/8);
    return;
    }

  if(GetPlanes()<0 || R1.GetPlanes()<0)		// Floating point operation
    {
    for(i=0;i<maxi;i++)
      PTR_SetValue1Dd(RAW_Data1D, i, R1.GetValue1Dd(i));
    return;
    }

  shift = GetPlanes() - R1.GetPlanes();  
  if(shift>0)
    {
    for(i=0;i<maxi;i++)
      PTR_SetValue1D(RAW_Data1D, i, R1.GetValue1D(i)<<shift);
    return;
    }
  else
    {
    shift = -shift;
    for(i=0;i<maxi;i++)
      PTR_SetValue1D(RAW_Data1D, i, R1.GetValue1D(i)>>shift);
    return;
    }
}

#endif


void Raster1DAbstract::Get24BitRGB(void *Buffer24Bit) const
{
BYTE *N_Buffer24Bit = (BYTE *)Buffer24Bit;

  if(Buffer24Bit==NULL) return;

  {
  Raster1D_8Bit Helper;
  Helper.Data1D = Buffer24Bit;
  Helper.Size1D = Size1D;
  Helper.Set(*this);	// convert to 8 bits.
  Helper.Data1D = NULL;
  }

	// In place conversion, must iterate from the end.
  for(int i=Size1D-1; i>=0; i--)
  {
    N_Buffer24Bit[3*i] =
        N_Buffer24Bit[3*i+1] =
        N_Buffer24Bit[3*i+2] = N_Buffer24Bit[i];
  }
}


/* Specialised Raster 1D modules */


void Raster1DAbstract::Peel1Bit(void *Buffer1Bit, char plane)
{
Raster1D_1Bit R1;
int i,maxi;

 R1.Data1D=Buffer1Bit;R1.Size1D=Size1D;
 maxi=Size1D>R1.Size1D?Size1D:R1.Size1D;
 for(i=0;i<maxi;i++)
	{
	R1.SetValue1D(i,(GetValue1D(i)>>plane)&1);
	}
 R1.Data1D=NULL;
}

void Raster1DAbstract::Join1Bit(void *Buffer1Bit, char plane)
{
 Raster1D_1Bit R1;
 int i,maxi;
 long mask;

 R1.Data1D=Buffer1Bit;R1.Size1D=Size1D;
 maxi=Size1D>R1.Size1D?Size1D:R1.Size1D;

 mask=~(1l<<plane);
 for(i=0;i<maxi;i++)
	{
	SetValue1D(i,(GetValue1D(i) & mask) | (R1.GetValue1D(i) << plane));
	}
 R1.Data1D=NULL;
}


/** Joins 8 bit channel into raster data on given bit wise position.
 * Use 0,8,16 for RGB 8bit channels. */
void Raster1DAbstract::Join8Bit(BYTE *Buffer8Bit, char plane8)
{
 Raster1D_8Bit R8;
 int i,maxi;
 long mask;

 R8.Data1D=Buffer8Bit;R8.Size1D=Size1D;
 maxi=Size1D>R8.Size1D?Size1D:R8.Size1D;
 mask=~(0xFFl<<plane8);

 //printf("%d %lX %d;",plane8,mask,maxi);

 for(i=0;i<maxi;i++)
   {
   SetValue1D(i,(GetValue1D(i) & mask) | (R8.GetValue1D(i) << plane8));
   }
 R8.Data1D=NULL;
}


/** Extracts 8 bit channel from raster data on given bit wise position.
 * Use 0,8,16 for RGB 8bit channels. */
void Raster1DAbstract::Peel8Bit(BYTE *Buffer8Bit, char plane8)
{
unsigned i;

 //printf("%d %lX %d;",plane8,mask,maxi);
 for(i=0;i<Size1D;i++)
   {
   *Buffer8Bit++ = (GetValue1D(i)>>plane8) & 0xFF;
   }
}


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

void Raster1D_1Bit::SetValue1D(unsigned x, DWORD NewValue)
{
BYTE *b;
 
 if(x>=Size1D || Data1D==NULL) return;
 b = (BYTE *)Data1D + (x >> 3);
 if(NewValue==0) *b = *b & ~(0x80 >>(x & 0x07));
	    else *b = *b |  (0x80 >>(x & 0x07));
}


DWORD Raster1D_1Bit::GetValue1D(unsigned x) const
{
const BYTE *b;

 if(x>=Size1D || Data1D==NULL) return(0);
 b = (const BYTE *)Data1D + (x >> 3);
 if((*b & (0x80 >>(x & 0x07))) != 0) return(1);
 return(0);
}


#ifdef _REENTRANT
void Raster1D_1Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
BYTE *b;
 
 if(x>=Size1D || RAW_Data1D==NULL) return;
 b = (BYTE *)RAW_Data1D + (x >> 3);
 if(NewValue==0) *b = *b & ~(0x80 >>(x & 0x07));
	    else *b = *b |  (0x80 >>(x & 0x07));
}


DWORD Raster1D_1Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const BYTE *b;

 if(x>=Size1D || RAW_Data1D==NULL) return(0);
 b = (const BYTE *)RAW_Data1D + (x >> 3);
 if((*b & (0x80 >>(x & 0x07))) != 0) return(1);
 return(0);
}
#endif


#ifdef OPTIMISE_SPEED

void Raster1D_1Bit::Set(const Raster1DAbstract &R1)
{
BYTE *N_Buffer8Bit = (BYTE *)Data1D;
unsigned i;
DWORD Half;
BYTE Mask;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Raster1DAbstract::Set(R1);
	    return;
    case 4: Conv4_1((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_1((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_1((BYTE *)Data1D,(const WORD *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_1((BYTE *)Data1D,(const DWORD *)R1.Data1D,Size1D);
	    return;
    }
  Half = 1 << (i-1);

  i = 0;
  while(i<Size1D)
    {    
    *N_Buffer8Bit = 0;
    for(Mask=0x80; Mask!=0; Mask>>=1)
      {
      if(R1.GetValue1D(i)>=Half) *N_Buffer8Bit |= Mask;
      if(++i>=Size1D) return;
      }
    N_Buffer8Bit++;
    }
}


void Raster1D_1Bit::Get(Raster1DAbstract &R1) const
{
const BYTE *N_Buffer8Bit = (BYTE *)Data1D;
unsigned i;
DWORD Max;
BYTE Mask;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Raster1DAbstract::Get(R1);
	    return;
    case 8: Conv1_8((BYTE *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 16:Conv1_16((WORD *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 24: Conv1_24((BYTE *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 32:Conv1_32((DWORD *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
#ifdef QWORD
    case 64:Conv1_64((QWORD*)R1.Data1D,(const BYTE *)Data1D,Size1D);
            return;
#endif
    }
  Max = 1 << (i-1);
  Max = Max + (Max-1);

  Mask = 0x80;
  for(i=0;i<Size1D;i++)
    {
    R1.SetValue1D(i, (*N_Buffer8Bit & Mask) ? Max : 0);

    Mask >>= 1;
    if(Mask==0)
      {
      Mask = 0x80;
      N_Buffer8Bit++;
      }
    }
}

#endif  // OPTIMISE_SPEED


/* --------------- 2 bit planes ------------- */

void Raster1D_2Bit::SetValue1D(unsigned x, DWORD NewValue)
{
BYTE *b=(BYTE *)Data1D;
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 Raster1D_2Bit::GetValue1D(unsigned x) const
{
const BYTE *b;

 if(Data1D==NULL || x>=Size1D) return 0;
 b = (const BYTE *)Data1D + (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;
}


#ifdef _REENTRANT
void Raster1D_2Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
BYTE *b = (BYTE *)RAW_Data1D;
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 Raster1D_2Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const BYTE *b;

 if(RAW_Data1D==NULL || x>=Size1D) return 0;
 b = (const BYTE *)RAW_Data1D + (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;
}
#endif


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

void Raster1D_4Bit::SetValue1D(unsigned x, DWORD NewValue)
{
BYTE *b=(BYTE *)Data1D;

 if(x>=Size1D) return;
 b+= x >> 1;
 if (x & 1) *b=(*b & 0xF0) | (NewValue & 0x0F);
       else *b=(*b & 0x0F) | ((NewValue << 4) & 0xF0);
}


DWORD Raster1D_4Bit::GetValue1D(unsigned x) const
{
const BYTE *b=(BYTE *)Data1D;

 if(x>=Size1D) return 0;
 b+= x >> 1;
 if(x & 1) return(*b & 0x0F);
      else return(*b >> 4);
}


#ifdef _REENTRANT
void Raster1D_4Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
BYTE *b = (BYTE *)RAW_Data1D;

 if(x>=Size1D || RAW_Data1D==NULL) return;
 b+= x >> 1;
 if (x & 1) *b=(*b & 0xF0) | (NewValue & 0x0F);
       else *b=(*b & 0x0F) | ((NewValue << 4) & 0xF0);
}


DWORD Raster1D_4Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const BYTE *b = (BYTE *)RAW_Data1D;

 if(x>=Size1D  || RAW_Data1D==NULL) return 0;
 b += x >> 1;
 if(x & 1) return(*b & 0x0F);
      else return(*b >> 4);
}
#endif


#ifdef OPTIMISE_SPEED

void Raster1D_4Bit::Get(Raster1DAbstract &R1) const
{
  switch(R1.GetPlanes())
    {
    case 1: Conv4_1((BYTE *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 4: Raster1DAbstract::Get(R1);
	    return;
    case 8: Conv4_8((BYTE *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 16:Conv4_16((WORD *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    case 32:Conv4_32((DWORD *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;
    }

  Raster1DAbstract::Get(R1);
}


void Raster1D_4Bit::Set(const Raster1DAbstract &R1)
{
  switch(R1.GetPlanes())
    {
    case 4: Raster1DAbstract::Set(R1);
	    return;
    case 8: Conv8_4((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_4((BYTE *)Data1D,(const WORD *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_4((BYTE *)Data1D,(const DWORD *)R1.Data1D,Size1D);
	    return;
    }

  Raster1DAbstract::Set(R1);
}

#endif // OPTIMISE_SPEED


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

#ifdef OPTIMISE_SPEED

void Raster1D_8Bit::Get(Raster1DAbstract &R1) const
{
unsigned i;
signed char shift;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv8_1((BYTE *)R1.Data1D,(const BYTE*)Data1D,Size1D);
    	    return;
    case 4: Conv8_4((BYTE *)R1.Data1D,(const BYTE*)Data1D,Size1D);
    	    return;
    case 8: Raster1DAbstract::Get(R1);
	    return;
    case 16:Conv8_16((WORD *)R1.Data1D,(const BYTE*)Data1D,Size1D);
	    return;
    case 24:Conv8_24((BYTE *)R1.Data1D,(const BYTE*)Data1D,Size1D);
	    return;
    case 32:Conv8_32((DWORD *)R1.Data1D,(const BYTE*)Data1D,Size1D);
	    return;
#ifdef QWORD
    case 64:Conv8_64((QWORD *)R1.Data1D,(const BYTE*)Data1D,Size1D);
	    return;
#endif

    }

  const BYTE *N_Buffer8Bit = (const BYTE *)Data1D;
  shift = i - 8;

  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(DWORD)(*N_Buffer8Bit++) << shift);
      }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,*N_Buffer8Bit++ >> shift);
      }
    }
}


void Raster1D_8Bit::Set(const Raster1DAbstract &R1)
{
signed char shift;
unsigned i;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv1_8((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_8((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
    	    return;
    case 8: Raster1DAbstract::Set(R1);
	    return;
    case 16:Conv16_8((BYTE *)Data1D,(const WORD *)R1.Data1D,Size1D);
	    return;
    case 24:Conv24_8((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
            return;
    case 32:Conv32_8((BYTE *)Data1D,(const DWORD *)R1.Data1D,Size1D);
	    return;
    }

  BYTE *N_Buffer8Bit = (BYTE *)Data1D;
  shift = 8-i;
  if(shift>0)
    {
      for(i=0;i<Size1D;i++)
	{
	*N_Buffer8Bit++ = R1.GetValue1D(i) << shift;
	}
    }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      *N_Buffer8Bit++ = R1.GetValue1D(i) >> shift;
      }
    }
}

#endif // OPTIMISE_SPEED


void Raster1D_8Bit::SetValue1D(unsigned x, DWORD NewValue)
{
  if(Size1D<x) return;
  if(NewValue>0xFF) NewValue = 0xFF;
  ((BYTE *)Data1D)[x] = (BYTE)NewValue;
}


DWORD Raster1D_8Bit::GetValue1D(unsigned x) const 
{
  if(x>=Size1D) return 0;
  return ((BYTE *)Data1D)[x];
}


#ifdef _REENTRANT
void Raster1D_8Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(Size1D<x || RAW_Data1D==NULL) return;
  if(NewValue>0xFF) NewValue = 0xFF;
  ((BYTE *)RAW_Data1D)[x] = (BYTE)NewValue;
}


DWORD Raster1D_8Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const 
{
  if(x>=Size1D || RAW_Data1D==NULL) return(0);
  return(((BYTE *)RAW_Data1D)[x]);
}


void Raster1D_8Bit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(Size1D<x || RAW_Data1D==NULL) return;
  if(NewValue>0xFF) NewValue = 0xFF;
  ((BYTE *)RAW_Data1D)[x] = (BYTE)NewValue;
}


double Raster1D_8Bit::PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const 
{
  if(x>=Size1D || RAW_Data1D==NULL) return(0);
  return(((BYTE *)RAW_Data1D)[x]);
}
#endif


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

#ifdef _REENTRANT
DWORD Raster1D_16Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return(0);
  return(((WORD *)RAW_Data1D)[x]);
}

void Raster1D_16Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((WORD *)RAW_Data1D)[x] = NewValue;
}

double Raster1D_16Bit::PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return(0);
  return(((WORD *)RAW_Data1D)[x]);
}

void Raster1D_16Bit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((WORD *)RAW_Data1D)[x] = NewValue;
}

#endif


#ifdef OPTIMISE_SPEED

void Raster1D_16Bit::Get(Raster1DAbstract &R1) const
{
unsigned i;
signed char shift;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv16_1((BYTE *)R1.Data1D,(const WORD *)Data1D,Size1D);
    	    return;
    case 4: Conv16_4((BYTE *)R1.Data1D,(const WORD *)Data1D,Size1D);
    	    return;
    case 8: Conv16_8((BYTE *)R1.Data1D,(const WORD *)Data1D,Size1D);
	    return;
    case 16:Raster1DAbstract::Get(R1);
	    return;
    case 32:Conv16_32((DWORD *)R1.Data1D,(const WORD *)Data1D,Size1D);
	    return;
    }
  shift = i - 16;
  const WORD *N_Buffer16Bit = (const WORD *)Data1D;
  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(DWORD)(*N_Buffer16Bit++) << shift);
      }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,*N_Buffer16Bit++ >> shift);
      }
    }
}


void Raster1D_16Bit::Set(const Raster1DAbstract &R1)
{
unsigned i;
signed char shift;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv1_16((WORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_16((WORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
            return;
    case 8: Conv8_16((WORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 16:Raster1DAbstract::Set(R1);
	    return;    
    case 32:Conv32_16((WORD *)Data1D,(const DWORD *)R1.Data1D,Size1D);
	    return;
    }
  shift = 16 - i;

  WORD *N_Buffer16Bit = (WORD *)Data1D;
  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      *N_Buffer16Bit++ = R1.GetValue1D(i) << shift;
      }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      *N_Buffer16Bit++ = R1.GetValue1D(i) >> shift;
      }
    }
}

#endif // OPTIMISE_SPEED

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

void Raster1D_24Bit::SetValue1D(unsigned x, DWORD NewValue)
{
BYTE *BuffPos;

 if(x>=Size1D) return;
 BuffPos=((BYTE *)Data1D)+(3*x);
 *BuffPos++=NewValue & 0xFF;
 NewValue >>= 8;
 *BuffPos++=NewValue & 0xFF;
 NewValue >>= 8;
 *BuffPos=NewValue & 0xFF;
}


DWORD Raster1D_24Bit::GetValue1D(unsigned x) const
{
const BYTE *b;

 if(x>=Size1D || Data1D==NULL) return(0);
 b = (BYTE *)Data1D + 3*x;
 return((DWORD)*b | (DWORD)b[1]<<8 | (DWORD)b[2]<<16);
}


#ifdef _REENTRANT
DWORD Raster1D_24Bit::PTR_GetValue1D(const void *RAW_Data1D,unsigned x) const
{
const BYTE *b;

 if(x>=Size1D || RAW_Data1D==NULL) return(0);
 b = (BYTE *)RAW_Data1D + 3*x;
 return((DWORD)*b | (DWORD)b[1]<<8 | (DWORD)b[2]<<16);
}


void Raster1D_24Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
BYTE *BuffPos;

 if(x>=Size1D || RAW_Data1D==NULL) return;
 BuffPos = ((BYTE *)RAW_Data1D)+(3*x);
 *BuffPos++=NewValue & 0xFF;
 NewValue >>= 8;
 *BuffPos++=NewValue & 0xFF;
 NewValue >>= 8;
 *BuffPos=NewValue & 0xFF;
}
#endif


#ifdef OPTIMISE_SPEED

void Raster1D_24Bit::Get(Raster1DAbstract &R1) const
{  
  switch(R1.GetPlanes())
    {
    case 8: Conv24_8((BYTE *)R1.Data1D,(const BYTE *)Data1D,Size1D);
	    return;  
    }
  Raster1DAbstract::Get(R1);
}


void Raster1D_24Bit::Set(const Raster1DAbstract &R1)
{  
  switch(R1.GetPlanes())
    {
    case 1: Conv1_24((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_24((BYTE *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    }
  Raster1DAbstract::Set(R1);
}

#endif // OPTIMISE_SPEED


void Raster1D_24Bit::Peel8Bit(BYTE *Buffer8Bit, char plane8)
{
unsigned i;
BYTE *b=(BYTE *)Data1D;

  if((plane8 & 0x3)!=0 || plane8>16)
    {Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8); return;}

  b += plane8 >> 3;
  for(i=0;i<Size1D;i++)
    {
    *(BYTE *)Buffer8Bit = *b;
#ifdef NO_LVAL_CAST
    Buffer8Bit=(BYTE *)Buffer8Bit + 1;
#else
    Buffer8Bit++;
#endif
    b+=3;
    }
}


void Raster1D_24Bit::Join8Bit(BYTE *Buffer8Bit, char plane8)
{
unsigned i;
BYTE *b=(BYTE *)Data1D;

  if((plane8 & 0x3)!=0 || plane8>16)
    {Raster1DAbstract::Join8Bit(Buffer8Bit,plane8); return;}

  b += plane8 >> 3;
  for(i=0;i<Size1D;i++)
    {
    *b = *(BYTE *)Buffer8Bit;
#ifdef NO_LVAL_CAST
    Buffer8Bit=(BYTE *)Buffer8Bit + 1;
#else
    Buffer8Bit++;
#endif
    b+=3;
    }
}


void Raster1D_24Bit::Get24BitRGB(void *Buffer24Bit) const
{
  memcpy(Buffer24Bit,Data1D,3*Size1D);
}


/* ------------ 32 bit planes -------------- */
void Raster1D_32Bit::SetValue1Dd(unsigned x, double NewValue)
{
  if(x>=Size1D) return;
  if(NewValue>(double)0xFFFFFFFF)           //overflow check
    ((DWORD *)Data1D)[x] = 0xFFFFFFFFl;
  else
    ((DWORD *)Data1D)[x] = NewValue;
}


#ifdef _REENTRANT
DWORD Raster1D_32Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return(0);
  return(((DWORD *)RAW_Data1D)[x]);
}

void Raster1D_32Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((DWORD *)RAW_Data1D)[x] = NewValue;
}

void Raster1D_32Bit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(RAW_Data1D==NULL || x>=Size1D) return;
  if(NewValue>(double)0xFFFFFFFF)           //overflow check
    ((DWORD *)RAW_Data1D)[x] = 0xFFFFFFFFl;
  else
    ((DWORD *)RAW_Data1D)[x] = NewValue;
}
#endif


/*
void Raster1DAbstract::Get32Bit(void *Buffer32Bit) const
{
DWORD *N_Buffer32Bit = (DWORD *)Buffer32Bit;
int i;
for(i=0;i<Size1D;i++)
	{
	*N_Buffer32Bit++ = GetValue1D(i);
	}
}
*/

#ifdef OPTIMISE_SPEED

void Raster1D_32Bit::Get(Raster1DAbstract &R1) const
{
unsigned i;
signed char shift;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv32_1((BYTE *)R1.Data1D,(const DWORD *)Data1D,Size1D);
    	    return;
    case 4: Conv32_4((BYTE *)R1.Data1D,(const DWORD *)Data1D,Size1D);
    	    return;
    case 8: Conv32_8((BYTE *)R1.Data1D,(const DWORD *)Data1D,Size1D);
	    return;
    case 16:Conv32_16((WORD *)R1.Data1D,(const DWORD *)Data1D,Size1D);
	    return;
    case 32:Raster1DAbstract::Get(R1);
	    return;
    }

  const DWORD *N_Buffer32Bit = (const DWORD *)Data1D;
  shift = i - 32;

  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(DWORD)(*N_Buffer32Bit++) << shift);
      }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,*N_Buffer32Bit++ >> shift);
      }
    }
}


void Raster1D_32Bit::Set(const Raster1DAbstract &R1)
{
unsigned i;
signed char shift;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Conv1_32((DWORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_32((DWORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_32((DWORD *)Data1D,(const BYTE *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_32((DWORD *)Data1D,(const WORD *)R1.Data1D,Size1D);
	    return;
    case 32:Raster1DAbstract::Set(R1);
	    return;
    }

  DWORD *N_Buffer32Bit = (DWORD *)Data1D;
  shift = 32 - i;

  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      *N_Buffer32Bit++ = R1.GetValue1D(i) << shift;
      }
  else
    {
    shift = -shift;
    for(i=0;i<Size1D;i++)
      {
      *N_Buffer32Bit++ = R1.GetValue1D(i) >> shift;
      }
    }
}

#endif // OPTIMISE_SPEED




/* ------------ 64 bit planes -------------- */
#ifdef QWORD


void Raster1D_64Bit::SetValue1Dd(unsigned x, double NewValue)
{
  if(x>=Size1D) return;
  if(NewValue>(double)_UI64_MAX)
    ((QWORD *)Data1D)[x] = (QWORD)_UI64_MAX;
  else
    ((QWORD *)Data1D)[x] = (QWORD)NewValue;
}

#ifdef _REENTRANT
DWORD Raster1D_64Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return(0);
  return(((QWORD *)RAW_Data1D)[x]);
}

double Raster1D_64Bit::PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return(0);
  return(((QWORD *)RAW_Data1D)[x]);
}

void Raster1D_64Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((QWORD *)RAW_Data1D)[x] = NewValue;
}

void Raster1D_64Bit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(RAW_Data1D==NULL || x>=Size1D) return;
  if(NewValue>(double)_UI64_MAX)
    ((QWORD *)RAW_Data1D)[x] = (QWORD)_UI64_MAX;
  else
    ((QWORD *)RAW_Data1D)[x] = (QWORD)NewValue;
}
#endif


#endif


/* ------------ 32 bit planes FLOAT -------------- */

DWORD Raster1D_32FltBit::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  return((((float *)Data1D)[x] - Min)*(Max-Min));
};

double Raster1D_32FltBit::GetValue1Dd(unsigned x) const
{
  if(x>=Size1D) return 0;
  return(((float *)Data1D)[x]);
};

void Raster1D_32FltBit::SetValue1D(unsigned x, DWORD NewValue)
{
  if(x>=Size1D) return;
  ((float *)Data1D)[x] = Min + (float)NewValue/(Max-Min);
  return;
}

void Raster1D_32FltBit::SetValue1Dd(unsigned x, double NewValue)
{
  if(x>=Size1D) return;
  ((float *)Data1D)[x] = NewValue;
  return;
}


#ifdef _REENTRANT
DWORD Raster1D_32FltBit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return((((float *)RAW_Data1D)[x] - Min)*(Max-Min));
};

double Raster1D_32FltBit::PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return(((float *)RAW_Data1D)[x]);
};

void Raster1D_32FltBit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(x>=Size1D) return;
  ((float *)RAW_Data1D)[x] = Min + (float)NewValue/(Max-Min);
  return;
}

void Raster1D_32FltBit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(x>=Size1D) return;
  ((float *)RAW_Data1D)[x] = NewValue;
  return;
}
#endif


#ifdef OPTIMISE_SPEED

void Raster1D_32FltBit::Get(Raster1DAbstract &R1) const
{
const float *N_BufferFlt = (float *)Data1D;
int i;
float MaxVal;

  i = R1.GetPlanes();
  
  if(i<0)		// Float or double.
    {
    if(i==-32)
      memcpy(R1.Data1D, Data1D, Size1D*sizeof(float));
    else
      {
      for(i=0; i<Size1D; i++)
        R1.SetValue1Dd(i, *N_BufferFlt++);
      }
    }
  else
    {
    MaxVal = (1<<i) - 1;

    for(i=0;i<Size1D;i++)
      {
      if(*N_BufferFlt>1)
        R1.SetValue1D(i,MaxVal);
      else if(*N_BufferFlt<0)
        R1.SetValue1D(i,0);
      else
        R1.SetValue1D(i,*N_BufferFlt*MaxVal);

      N_BufferFlt++;
      }
    }
}


void Raster1D_32FltBit::Set(const Raster1DAbstract &R1)
{
float *N_BufferFlt = (float *)Data1D;
int i;
float MaxVal;

  i = R1.GetPlanes();
  
  if(i<0)		// Float or double.
    {
    if(i==-32)
      memcpy(Data1D, R1.Data1D, Size1D*sizeof(float));
    else
      {
      for(i=0; i<Size1D; i++)
        *N_BufferFlt++ = R1.GetValue1Dd(i);
      }
    }
  else
    {
    MaxVal = (1<<i) - 1;
    for(i=0; i<Size1D; i++)
      {
      *N_BufferFlt++ = R1.GetValue1D(i) * MaxVal;
      }
    }
}

#endif


/* ------------ 64 bit planes DOUBLE -------------- */

DWORD Raster1D_64FltBit::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  return((((double *)Data1D)[x] - Min)*(Max-Min));
}

double Raster1D_64FltBit::GetValue1Dd(unsigned x) const
{
  if(x>=Size1D) return 0;
  return(((double *)Data1D)[x]);
}

void Raster1D_64FltBit::SetValue1D(unsigned x, DWORD NewValue)
{
  if(x>=Size1D) return;
  ((double *)Data1D)[x] = Min + (double)NewValue/(Max-Min);
  return;
}

void Raster1D_64FltBit::SetValue1Dd(unsigned x, double NewValue)
{
  if(x>=Size1D) return;
  ((double *)Data1D)[x] = NewValue;
  return;
}

#ifdef _REENTRANT
DWORD Raster1D_64FltBit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return((((double *)RAW_Data1D)[x] - Min)*(Max-Min));
}

double Raster1D_64FltBit::PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return(((double *)RAW_Data1D)[x]);
}

void Raster1D_64FltBit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(x>=Size1D) return;
  ((double *)RAW_Data1D)[x] = Min + (double)NewValue/(Max-Min);
  return;
}

void Raster1D_64FltBit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(x>=Size1D) return;
  ((double *)RAW_Data1D)[x] = NewValue;
  return;
}
#endif


#ifdef OPTIMISE_SPEED

void Raster1D_64FltBit::Get(Raster1DAbstract &R1) const
{
const double *N_BufferFlt = (const double *)Data1D;
int i;
float MaxVal;

  i = R1.GetPlanes();
  
  if(i<0)		// Float or double.
    {
    if(i==-64)
      memcpy(R1.Data1D, Data1D, Size1D*sizeof(float));
    else
      {
      for(i=0; i<Size1D; i++)
        R1.SetValue1Dd(i, *N_BufferFlt++);
      }
    }
  else
    {
    MaxVal = (1<<i) - 1;

    for(i=0;i<Size1D;i++)
      {
      if(*N_BufferFlt>1)
        R1.SetValue1D(i,MaxVal);
      else if(*N_BufferFlt<0)
        R1.SetValue1D(i,0);
      else
        R1.SetValue1D(i,*N_BufferFlt*MaxVal);

      N_BufferFlt++;
      }
    }
}


void Raster1D_64FltBit::Set(const Raster1DAbstract &R1)
{
double *N_BufferFlt = (double *)Data1D;
int i;
double MaxVal;

  i = R1.GetPlanes();
  
  if(i<0)		// Float or double.
    {
    if(i==-64)
      memcpy(Data1D, R1.Data1D, Size1D*sizeof(float));
    else
      {
      for(i=0; i<Size1D; i++)
        *N_BufferFlt++ = R1.GetValue1Dd(i);
      }
    }
  else
    {
    MaxVal = (1<<i) - 1;
    for(i=0;i<Size1D;i++)
      {
      *N_BufferFlt++ = R1.GetValue1D(i) * MaxVal;
      }
    }
}


#endif


//----------------------------------------------------------


Raster1DAbstract *CreateRaster1D(unsigned Size1D, int Planes)
{
Raster1DAbstract *Raster=NULL;

switch(Planes)
   {
   case -64:Raster=new Raster1D_64FltBit;  break;
   case -32:Raster=new Raster1D_32FltBit;  break;
   case  0: return(NULL);
   case  1: Raster=new Raster1D_1Bit;   break;
   case  2: Raster=new Raster1D_2Bit;   break;
   case  4: Raster=new Raster1D_4Bit;   break;
   case  8: Raster=new Raster1D_8Bit;   break;
   case 16: Raster=new Raster1D_16Bit;  break;
   case 24: Raster=new Raster1D_24Bit;  break;
   case 32: Raster=new Raster1D_32Bit;  break;
#ifdef QWORD
   case 64: Raster=new Raster1D_64Bit;  break;
#endif
   default:return(NULL);
   }
if(Raster)
   {
   if(Size1D!=0)
     {
     Raster->Allocate1D(Size1D);
     if(Raster->Data1D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
   }

return(Raster);
}


/* ------ */

/** Copy data from a given container. */
void Raster1DAbstractRGB::Set(const Raster1DAbstract &R1)
{
int i,maxi;
signed char shift;

DWORD val;

  if(Data1D==NULL || R1.Data1D==NULL) return;

  maxi = Size1D>R1.Size1D?Size1D:R1.Size1D;

  i = R1.Channels();
  shift = GetPlanes()/3 - R1.GetPlanes()/i;

  if(shift==0)		// No bitplane change - copy data only
    {
    switch(i)
      {
      case 1: for(i=0;i<maxi;i++)	// convert from gray to RGB
		{
		val = R1.GetValue1D(i);
		R(i,val);
		G(i,val);
		B(i,val);
		}
	      return;

      case 3: memcpy(Data1D, R1.Data1D, ((long)maxi*GetPlanes()+7)/8);   // convert from RGB to RGB - just copy
              return;

      case 4: for(i=0;i<maxi;i++)	// convert from RGBA to RGB
		{
		val = R1.GetValue1D(i);
		R(i,val & 0xFF);
		G(i,(val>>8)& 0xFF);
		B(i,(val>>16)& 0xFF);
		}
	      return;
      }
    }

  if(shift>0)
    {
    for(i=0;i<maxi;i++)
       {
       val = R1.GetValue1D(i);
       R(i,val<<shift);
       G(i,val<<shift);
       B(i,val<<shift);
       }
    return;
    }
  else
    {
    shift = -shift;
    for(i=0;i<maxi;i++)
     {
     val = R1.GetValue1D(i);
     R(i,val>>shift);
     G(i,val>>shift);
     B(i,val>>shift);
     }
    return;
    }
}


/** Copy data from a given container. */
void Raster1DAbstractRGBA::Set(const Raster1DAbstract &R1)
{
unsigned i, maxi;
signed char shift;

  if(Data1D==NULL || R1.Data1D==NULL) return;

  maxi=Size1D>R1.Size1D?Size1D:R1.Size1D;
  shift = GetPlanes() - R1.GetPlanes();

  if(shift==0)		// No bitplane change - copy data only
    {
    i = Size1D;
    if(R1.Size1D<i) i=R1.Size1D;
    memcpy(Data1D, R1.Data1D, ((long)i*GetPlanes()+7)/8);
    return;
    }

  if(shift>0)
    {
    for(i=0;i<maxi;i++)
       {
       R(i,R1.GetValue1D(i)<<shift);
       G(i,R1.GetValue1D(i)<<shift);
       B(i,R1.GetValue1D(i)<<shift);
       A(i,0);
       }
    return;
    }
  else
    {
    shift = -shift;
    for(i=0;i<maxi;i++)
     {
     R(i,R1.GetValue1D(i)>>shift);
     G(i,R1.GetValue1D(i)>>shift);
     B(i,R1.GetValue1D(i)>>shift);
     A(i,0);
     }
    return;
    }
}


/* 8 bit planes for 3 channels R,G,B */

DWORD Raster1D_8BitRGB::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 3;
  return((DWORD)(((BYTE *)Data1D)[x]) |
	   ((DWORD)(((BYTE *)Data1D)[x+1])<<8) |
	   ((DWORD)(((BYTE *)Data1D)[x+2])<<16));
}

void Raster1D_8BitRGB::SetValue1D(unsigned x, DWORD NewValue)
{
  if(Size1D<=x) return;
  x *= 3;
  ((BYTE *)Data1D)[x] = NewValue & 0xFF;
  ((BYTE *)Data1D)[x+1] = (NewValue>>8) & 0xFF;
  ((BYTE *)Data1D)[x+2] = (NewValue>>16) & 0xFF;
}


void Raster1D_8BitRGB::Get24BitRGB(void *Buffer24Bit) const
{
  memcpy(Buffer24Bit,Data1D,3*Size1D);
}


#ifdef _REENTRANT

DWORD Raster1D_8BitRGB::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 3;
  return((DWORD)(((BYTE *)RAW_Data1D)[x]) |
	   ((DWORD)(((BYTE *)RAW_Data1D)[x+1])<<8) |
	   ((DWORD)(((BYTE *)RAW_Data1D)[x+2])<<16));
}

void Raster1D_8BitRGB::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(Size1D<=x) return;
  x *= 3;
  ((BYTE *)RAW_Data1D)[x] = NewValue & 0xFF;
  ((BYTE *)RAW_Data1D)[x+1] = (NewValue>>8) & 0xFF;
  ((BYTE *)RAW_Data1D)[x+2] = (NewValue>>16) & 0xFF;
}

#endif


/** 16 bit planes for 3 channels R,G,B */

DWORD Raster1D_16BitRGB::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 6;
  return((DWORD)((BYTE *)Data1D)[x+1] |
        ((DWORD)((BYTE *)Data1D)[x+3])<<8 |
        ((DWORD)((BYTE *)Data1D)[x+5])<<16);
}


void Raster1D_16BitRGB::SetValue1D(unsigned x, DWORD NewValue)
{
  if(Size1D<=x) return;
  x *= 3;
  ((WORD *)Data1D)[x] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((WORD *)Data1D)[x+1] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((WORD *)Data1D)[x+2] = (NewValue & 0xFF) * 0x101;
}


#ifdef _REENTRANT

DWORD Raster1D_16BitRGB::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 6;
  return((DWORD)((BYTE *)RAW_Data1D)[x+1] |
        ((DWORD)((BYTE *)RAW_Data1D)[x+3])<<8 |
        ((DWORD)((BYTE *)RAW_Data1D)[x+5])<<16);
}

void Raster1D_16BitRGB::PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const
{
  if(Size1D<=x) return;
  x *= 3;
  ((WORD *)RAW_Data1D)[x] = (NewValue << 8)& 0xFF00;
  ((WORD *)RAW_Data1D)[x+1] = NewValue & 0xFF00;
  ((WORD *)RAW_Data1D)[x+2] = (NewValue>>8) & 0xFF00;
}

#endif




/** 8 bit planes for 4 channels R,G,B, A */

DWORD Raster1D_8BitRGBA::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  return ((DWORD *)Data1D)[x];
}


void Raster1D_8BitRGBA::SetValue1D(unsigned x, DWORD NewValue)
{
  if(Size1D<=x) return;
  ((DWORD *)Data1D)[x] = NewValue;
}


/** 16 bit planes for 4 channels R,G,B, A */


DWORD Raster1D_16BitRGBA::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 8;
  return((DWORD)((BYTE *)Data1D)[x+1] |
	((DWORD)((BYTE *)Data1D)[x+3])<<8 |
	((DWORD)((BYTE *)Data1D)[x+5])<<16 |
	((DWORD)((BYTE *)Data1D)[x+7])<<24);
}


void Raster1D_16BitRGBA::SetValue1D(unsigned x, DWORD NewValue)
{
  if(Size1D<=x) return;
  x *= 4;
  ((WORD *)Data1D)[x] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((WORD *)Data1D)[x+1] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((WORD *)Data1D)[x+2] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((WORD *)Data1D)[x+3] = (NewValue & 0xFF) * 0x101;
}


/*
void Raster1D_24Bit::Get(Raster1DAbstract &R1) const
{
BYTE *N_Buffer24Bit = (BYTE *)R1->Data1D;
DWORD val;
int i;
int shift;

  if(Buffer24Bit==NULL) return;
  shift = 24-GetPlanes();

  for(i=0;i<Size1D;i++)
    {
    val = GetValue1D(i);
    if(shift>0) val <<= shift;
	   else val >>= -shift;
    *N_Buffer24Bit++ = val&0xFF;
    *N_Buffer24Bit++ = (val>>8)&0xFF;
    *N_Buffer24Bit++ = (val>>16)&0xFF;
    }
}
*/


/* ------- */
Raster1DAbstractRGB *CreateRaster1DRGB(unsigned Size1D, int Planes)
{
Raster1DAbstractRGB *Raster=NULL;

 switch(Planes)
   {
   case  8: Raster=new Raster1D_8BitRGB;   break;
   case 16: Raster=new Raster1D_16BitRGB;  break;
   default:return(NULL);
   }
 if(Raster)
   {
   if(Size1D>0)
     {
     Raster->Allocate1D(Size1D);
     if(Raster->Data1D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
 }

return(Raster);
}


Raster1DAbstractRGBA *CreateRaster1DRGBA(unsigned Size1D, int Planes)
{
Raster1DAbstractRGBA *Raster=NULL;

 switch(Planes)
   {
   case  8: Raster=new Raster1D_8BitRGBA;   break;
   case 16: Raster=new Raster1D_16BitRGBA;  break;
   default:return(NULL);
   }
 if(Raster)
   {
   if(Size1D>0)
     {
     Raster->Allocate1D(Size1D);
     if(Raster->Data1D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
 }

return(Raster);
}


/* ==================================================== */
/* ================ Raster 2D abstract class ========== */
/* ==================================================== */

void Raster2DAbstract::Erase2DStub(void)
{
unsigned SaveSize1D;

 if(Shadow)
   {
   Data2D=NULL;
   Size2D=0;
   Erase1DStub();
   return;
   }

 if(Data2D)
   {
   SaveSize1D = Size1D;
   for(unsigned i=0; i<Size2D; i++)
	{
	Size1D=SaveSize1D;
	Data1D=Data2D[i];
	Raster1DAbstract::Erase1D();
	}
   free(Data2D);
   Data2D = NULL;
   }
 else
   Raster1DAbstract::Erase1D();
Size2D=0;
}


void Raster2DAbstract::Cleanup(void)
{
unsigned i;

 if(Data2D==NULL) return;
 for(i=0;i<Size2D;i++)
	{	
	Data1D=Data2D[i];
	Raster1DAbstract::Cleanup();
	}
}


void Raster2DAbstract::Allocate2D(unsigned NewSize1D, unsigned NewSize2D)
{
unsigned i;

 if(Data2D) Erase();
 if(NewSize1D==0 || NewSize2D==0) return;	// No allocation needed

 Data2D = (void **)malloc(sizeof(void *)*NewSize2D);
 if(!Data2D)
   {
   RaiseError(RasterId|No_Memory,this);
   return;		/*Not Enough memory*/
   }
 memset(Data2D,0,sizeof(void *)*NewSize2D);

 Size2D = NewSize2D;
 for(i=0; i<NewSize2D; i++)
   {
   Data1D = NULL;
   Allocate1D(NewSize1D);
   Data2D[i] = Data1D;
   if(Data1D==NULL)
     {
     Erase();
     return;
     }
   }
}


/** Make the current 2D object to act like Raster1DAbstract.
 * This method modifies internal variable Data2D and thus it IS NOT THREAD SAFE. */
Raster1DAbstract *Raster2DAbstract::GetRowRaster(unsigned Offset2D)
{
  if(Data2D==NULL || Offset2D>=Size2D) return(NULL);
  Data1D = Data2D[Offset2D];
  return(this);
}


void Raster2DAbstract::Get(unsigned Offset2D, Raster1DAbstract &R1) MP_CONST
{
  if(Data2D==NULL || Offset2D>=Size2D) return;  
#ifdef _REENTRANT
  Raster1DAbstract::PTR_Get(Data2D[Offset2D],R1);
#else
  Data1D = Data2D[Offset2D];
  Raster1DAbstract::Get(R1);
#endif
}


void Raster2DAbstract::Set(unsigned Offset2D, const Raster1DAbstract &R1)
{
  if(Data2D==NULL || Offset2D>=Size2D) return;  
#ifdef _REENTRANT
  Raster1DAbstract::PTR_Set(Data2D[Offset2D],R1);
#else
  Data1D = Data2D[Offset2D];
  Raster1DAbstract::Set(R1);
#endif
}


DWORD Raster2DAbstract::GetValue2D(unsigned Offset1D, unsigned Offset2D) MP_CONST
{
  if(Data2D==NULL || Offset2D>=Size2D) return(0); 
#ifdef _REENTRANT
  return PTR_GetValue1D(Data2D[Offset2D],Offset1D);
#else
  Data1D = Data2D[Offset2D];
  return GetValue1D(Offset1D);
#endif
}

double Raster2DAbstract::GetValue2Dd(unsigned Offset1D, unsigned Offset2D) MP_CONST
{
  if(Data2D==NULL || Offset2D>=Size2D) return(0);
#ifdef _REENTRANT
  return PTR_GetValue1Dd(Data2D[Offset2D],Offset1D);
#else
  Data1D = Data2D[Offset2D];
  return(GetValue1Dd(Offset1D));
#endif
}

void Raster2DAbstract::SetValue2D(unsigned Offset1D, unsigned Offset2D, long x)
{
  if(Data2D==NULL || Offset2D>=Size2D) return;
#ifdef _REENTRANT
  PTR_SetValue1D(Data2D[Offset2D],Offset1D,x);
#else
  Data1D = Data2D[Offset2D];
  SetValue1D(Offset1D,x);
#endif
}

void Raster2DAbstract::SetValue2Dd(unsigned Offset1D, unsigned Offset2D, double x)
{
  if(Data2D==NULL || Offset2D>=Size2D) return;
#ifdef _REENTRANT
  PTR_SetValue1Dd(Data2D[Offset2D],Offset1D,x);
#else
  Data1D = Data2D[Offset2D];
  SetValue1Dd(Offset1D,x);
#endif
}


#if defined(_REENTRANT) && defined(RASTER_3D)
DWORD Raster2DAbstract::PTR_GetValue2D(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return(0); 
  return PTR_GetValue1D(RAW_Data2D[Offset2D],Offset1D);
}

double Raster2DAbstract::PTR_GetValue2Dd(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return(0);
  return PTR_GetValue1Dd(RAW_Data2D[Offset2D],Offset1D);
}

void Raster2DAbstract::PTR_SetValue2D(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, DWORD x) const
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return;
  PTR_SetValue1D(RAW_Data2D[Offset2D],Offset1D,x);
}

void Raster2DAbstract::PTR_SetValue2Dd(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, double x) const
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return;
  PTR_SetValue1Dd(RAW_Data2D[Offset2D],Offset1D,x);
}

void Raster2DAbstract::PTR_Get(const void **RAW_Data2D, unsigned Offset2D, Raster1DAbstract &R1) const
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return;
  Raster1DAbstract::PTR_Get(RAW_Data2D[Offset2D], R1);
}

void Raster2DAbstract::PTR_Set(void **RAW_Data2D, unsigned Offset2D, const Raster1DAbstract &R1)
{
  if(RAW_Data2D==NULL || Offset2D>=Size2D) return;
  Raster1DAbstract::PTR_Set(RAW_Data2D[Offset2D], R1);
}

#endif


DWORD Raster2DAbstractRGB::GetValue2DRAW(unsigned Offset1D, unsigned Offset2D)
{
 if(Data2D==NULL || Offset2D>=Size2D) return(0);
#if defined(_REENTRANT)
 return(PTR_GetValue1DRAW(Data2D[Offset2D],Offset1D));
#else
 Data1D = Data2D[Offset2D];
 return(GetValue1DRAW(Offset1D));
#endif
}

void Raster2DAbstractRGB::SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x)
{
 if(Data2D==NULL || Offset2D>=Size2D) return;
#if defined(_REENTRANT)
 PTR_SetValue1DRAW(Data2D[Offset2D],Offset1D,x);
#else
 Data1D = Data2D[Offset2D];
 SetValue1DRAW(Offset1D,x);
#endif
}



DWORD Raster2DAbstractRGBA::GetValue2DRAW(unsigned Offset1D, unsigned Offset2D)
{
 if(Data2D==NULL || Offset2D>=Size2D) return(0);
#if defined(_REENTRANT)
 return PTR_GetValue1DRAW(Data2D[Offset2D],Offset1D);
#else
 Data1D = Data2D[Offset2D];
 return(GetValue1DRAW(Offset1D));
#endif
}


void Raster2DAbstractRGBA::SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x)
{
 if(Data2D==NULL || Offset2D>=Size2D) return;
 Data1D=Data2D[Offset2D];
 SetValue1DRAW(Offset1D,x);
}


/** Create raster with given amount of planes. Negative numbers
 * are used for floating point rasters. */
Raster2DAbstract *CreateRaster2D(unsigned Size1D, unsigned Size2D, int Planes)
{
Raster2DAbstract *Raster=NULL;

switch(Planes)
   {
   case -64:Raster=new Raster2D_64FltBit;  break;
   case -32:Raster=new Raster2D_32FltBit;  break;
   case  0:return(NULL);
   case  1:Raster=new Raster2D_1Bit;   break;
   case  2:Raster=new Raster2D_2Bit;   break;
   case  4:Raster=new Raster2D_4Bit;   break;
   case  8:Raster=new Raster2D_8Bit;   break;
   case 16:Raster=new Raster2D_16Bit;  break;
   case 24:Raster=new Raster2D_24Bit;  break;
   case 32:Raster=new Raster2D_32Bit;  break;
#ifdef QWORD
   case 64:Raster=new Raster2D_64Bit;  break;
#endif
   default:return(NULL);
   }
if(Raster)
   {
   if(Size1D!=0 && Size2D!=0)
     {
     Raster->Allocate2D(Size1D,Size2D);
     if(Raster->Data2D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
   }

return(Raster);
}


/** Create RGB raster with given amount of planes per channel. */
Raster2DAbstractRGB *CreateRaster2DRGB(unsigned Size1D, unsigned Size2D, int Planes)
{
Raster2DAbstractRGB *Raster=NULL;

switch(Planes)
   {
   case  8:Raster=new Raster2D_8BitRGB;   break;
   case 16:Raster=new Raster2D_16BitRGB;  break;
   default:return(NULL);
   }
if(Raster)
   {
   if(Size1D!=0 && Size2D!=0)
     {
     Raster->Allocate2D(Size1D,Size2D);
     if(Raster->Data2D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
   }

return(Raster);
}


/** Create RGB raster with given amount of planes per channel. */
Raster2DAbstractRGBA *CreateRaster2DRGBA(unsigned Size1D, unsigned Size2D, int Planes)
{
Raster2DAbstractRGBA *Raster=NULL;

switch(Planes)
   {
   case  8:Raster=new Raster2D_8BitRGBA;   break;
   case 16:Raster=new Raster2D_16BitRGBA;  break;
   default:return(NULL);
   }
if(Raster)
   {
   if(Size1D!=0 && Size2D!=0)
     {
     Raster->Allocate2D(Size1D,Size2D);
     if(Raster->Data2D==NULL)
	{
	delete Raster;
	return(NULL);
	}
     }
   }

return(Raster);
}


#ifdef RASTER_3D
/* ==================================================== */
/* ================ Raster 3D abstract class ========== */
/* ==================================================== */

void Raster3DAbstract::Erase3DStub(void)
{
unsigned i,SaveSize2D;

 if(Shadow)
   {
   Data3D = NULL;
   Size3D = 0;
   Erase2DStub();
   return;
   }

 if(Data3D)
   {
   SaveSize2D=Size2D;
   for(i=0;i<Size3D;i++)
     {
     Size2D=SaveSize2D;
     Data2D=Data3D[i];
     Raster2DAbstract::Erase2D();
     }
   free(Data3D);
   Data3D=NULL;
   }
 else
   Raster2DAbstract::Erase2D();

 Size3D=0;
}


void Raster3DAbstract::Cleanup(void)
{
 if(Data3D==NULL) return;
 for(unsigned i=0;i<Size3D;i++)
 {	
   Data2D=Data3D[i];
   Raster2DAbstract::Cleanup();
 }
}


void Raster3DAbstract::Allocate3D(unsigned NewSize1D, unsigned NewSize2D, unsigned NewSize3D)
{
 if(NewSize1D==Size1D && NewSize2D==Size2D && NewSize3D==Size3D && Data3D!=NULL) return; // No change occurs

 if(Data3D) Erase();
 if(NewSize1D==0 || NewSize2D==0 || NewSize3D==0) return;	// No allocation needed

 Data3D = (void ***)malloc(sizeof(void **)*NewSize3D);
 if(Data3D==NULL)
   {
   RaiseError(RasterId|No_Memory,this);
   return;		// Not Enough memory
   }
 memset(Data3D,0,sizeof(void **)*NewSize3D);

 Size3D = NewSize3D;
 for(unsigned i=0; i<NewSize3D; i++)
   {
   Size2D=NewSize2D;
   Data2D=NULL;
   Allocate2D(NewSize1D,Size2D);
   if(Data3D==NULL) return;		// The structure has been erased from virtual call.
   Data3D[i] = Data2D;
   if(Data2D==NULL)
     {
     RaiseError(RasterId|No_Memory,this);
     Erase();
     return;
     }
   }
}


/** Make the current 3D object to act like Raster1DAbstract.
 * This method modifies internal variable Data2D and thus it IS NOT THREAD SAFE. */
Raster1DAbstract *Raster3DAbstract::GetRowRaster(unsigned Offset2D, unsigned Offset3D)
{
 if(Data3D==NULL || Offset3D>=Size3D) return(NULL);
 Data2D = Data3D[Offset3D];
 return Raster2DAbstract::GetRowRaster(Offset2D);
}


/** Make the current 3D object to act like Raster2DAbstract.
 * This method modifies internal variable Data2D and thus it IS NOT THREAD SAFE. */
Raster2DAbstract *Raster3DAbstract::GetRowRaster(unsigned Offset3D)
{
 if(Data3D==NULL || Offset3D>=Size3D) return(NULL);
 Data2D = Data3D[Offset3D];
 return(this);
}


DWORD Raster3DAbstract::GetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D) MP_CONST
{
 if(Data3D==NULL || Offset3D>=Size3D) return(0);
#ifdef _REENTRANT
 return PTR_GetValue2D((const void**)(Data3D[Offset3D]),Offset1D,Offset2D);
#else
 Data2D = Data3D[Offset3D];
 return GetValue2D(Offset1D,Offset2D);
#endif
}


double Raster3DAbstract::GetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D) MP_CONST
{
 if(Data3D==NULL || Offset3D>=Size3D) return(0);
#ifdef _REENTRANT
 return PTR_GetValue2Dd((const void**)(Data3D[Offset3D]),Offset1D,Offset2D);
#else
 Data2D = Data3D[Offset3D];
 return GetValue2Dd(Offset1D,Offset2D);
#endif
}


void Raster3DAbstract::SetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, DWORD x)
{
 if(Data3D==NULL || Offset3D>=Size3D) return;
#ifdef _REENTRANT
 PTR_SetValue2D(Data3D[Offset3D],Offset1D,Offset2D,x);
#else
 Data2D = Data3D[Offset3D];
 SetValue2D(Offset1D,Offset2D,x);
#endif
}


void Raster3DAbstract::SetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, double x)
{
 if(Data3D==NULL || Offset3D>=Size3D) return;
#ifdef _REENTRANT
 PTR_SetValue2Dd(Data3D[Offset3D],Offset1D,Offset2D,x);
#else
 Data2D = Data3D[Offset3D];
 SetValue2Dd(Offset1D,Offset2D,x);
#endif
}


void Raster3DAbstract::Get(unsigned Offset2D, unsigned Offset3D, Raster1DAbstract &R1) MP_CONST
{
  if(Data3D==NULL || Offset3D>=Size3D) return;
#ifdef _REENTRANT
  PTR_Get((const void **)Data3D[Offset3D], Offset2D, R1);
#else
  Data2D = Data3D[Offset3D];
  Raster2DAbstract::Get(Offset2D,R1);
#endif
}


void Raster3DAbstract::Set(unsigned Offset2D, unsigned Offset3D, const Raster1DAbstract &R1)
{
  if(Data3D==NULL || Offset3D>=Size3D) return;
#ifdef _REENTRANT
  PTR_Set((void **)Data3D[Offset3D], Offset2D, R1);
#else
  Data2D = Data3D[Offset3D];
  Raster2DAbstract::Set(Offset2D,R1);
#endif
}


/* Specialised Raster 3D modules */

Raster3DAbstract *CreateRaster3D(unsigned Size1D, unsigned Size2D, unsigned Size3D, int Planes)
{
Raster3DAbstract *Raster=NULL;

switch(Planes)
   {
   case -64:Raster=new Raster3D_64FltBit;  break;
   case -32:Raster=new Raster3D_32FltBit;  break;
   case  0:return(NULL);
   case  1:Raster=new Raster3D_1Bit;   break;
   case  2:Raster=new Raster3D_2Bit;   break;
   case  4:Raster=new Raster3D_4Bit;   break;
   case  8:Raster=new Raster3D_8Bit;   break;
   case 16:Raster=new Raster3D_16Bit;  break;
   case 24:Raster=new Raster3D_24Bit;  break;
   case 32:Raster=new Raster3D_32Bit;  break;
#ifdef QWORD
   case 64:Raster=new Raster3D_64Bit;  break;
#endif
   default:return(NULL);
   }
if(Raster)
   {
   if(Size1D!=0 && Size2D!=0 && Size3D!=0)
     {
     Raster->Allocate3D(Size1D,Size2D,Size3D);
     if(Raster->Data3D==NULL)
       {
       delete Raster;
       return(NULL);
       }
     }
   }

return(Raster);
}


Raster3DAbstract *Raster3DAbstract::CreateShadow(void)
{
  Raster3DAbstract *Ras = CreateRaster3D(0,0,0,GetPlanes());
  if(Ras!=NULL)
    {    
    Ras->Shadow = true;
    Ras->Data3D = Data3D;		Ras->Size3D = Size3D;
    Ras->Data2D = Data2D;		Ras->Size2D = Size2D;
    Ras->Data1D = Data1D;		Ras->Size1D = Size1D;
    }
  return Ras;
}


#endif

