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

#include "common.h"

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


#if defined(uint64_t_defined)
 #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);		// nibble
  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;
 }
 if(NewSize1D==0) return;
 const unsigned long SzBit = (unsigned long)labs(GetPlanes()) * NewSize1D;
 Data1D = malloc((SzBit+7)/8);
 if(Data1D!=NULL) 
 {
   if((SzBit & 7) != 0)			// Incomplete padding byte should be cleared to prevent walgrind errors to access uninitialised memory.
     *((uint8_t*)Data1D + SzBit/8) = 0; // This is not neccessary for normal functionality.
 }					// Storing one junk byte will not hurt.
 else
   RaiseError(RasterId|No_Memory,this);
 Size1D = NewSize1D;
}


void Raster1DAbstract::Cleanup(void)
{
 if(Data1D==NULL) return;
 memset(Data1D, 0, (Size1D+7)*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;
   }

 i = R1.GetPlanes(); 
 shift = GetPlanes();
#if defined(uint64_t_defined)
 if(i>32) i=32;
 if(shift>32) shift=32;
#endif

 shift = i - shift;

#if defined(uint64_t_defined)
 if(shift==0)		// Also used for cropped 64 bit values.
 {
   for(i=0; i<maxi; i++)
     R1.SetValue1D(i,GetValue1D(i));
   return;
 }
#endif

 if(shift>0)
 {
   for(i=0; i<maxi; i++)
     R1.SetValue1D(i,GetValue1D(i)<<shift);
   return;
 }
 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;
signed char BasePlanes, SetPlanes;

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

  BasePlanes = GetPlanes();
  SetPlanes = R1.GetPlanes();
  if(BasePlanes == SetPlanes)		// 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;
  }

	// RGB to gray conversion.
  if(Channels()==1 && Channels()!= R1.Channels())
  {
    RGBQuad RGB;
    shift = SetPlanes/R1.Channels() - BasePlanes;
    if(shift>=0)
    {
      int k = 3* ((1<<shift)-1);
      for(i=0; i<maxi; i++)
      {
        R1.Get(i,&RGB);
        SetValue1D(i, (RGB.R+RGB.G+RGB.B)/k);
      }
      return;
    }
  }

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

  if(SetPlanes > 32) SetPlanes=32;
  if(BasePlanes > 32) BasePlanes=32;
  shift = BasePlanes - SetPlanes;
  if(shift>0)
  {
    unsigned k = 0;
    while(shift >= 0)		// Needs to replicate lower bits.
    {
      k |= 1 << shift;
      shift -= R1.GetPlanes();
    }
    for(i=0; i<maxi; i++)
      SetValue1D(i,R1.GetValue1D(i)*k);
    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
{
uint8_t *N_Buffer24Bit = (uint8_t *)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 */

/// param[out]	Buffer1Bit	Buffer to get 1bpp image.
/// param[in]	plane		Plane No to be extracted.
void Raster1DAbstract::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
uint8_t Buff = 0;
uint8_t Mask = 0x80;

 if(Buffer1Bit==NULL) return;
 if(plane>=labs(GetPlanes()))
 {
   memset(Buffer1Bit,0,(Size1D+7)/8);
   return; 
 }

 for(unsigned i=0; i<Size1D; i++)
 {    
   if((GetValue1D(i)>>plane)&1)
	Buff|=Mask;
   Mask >>= 1;
   if(Mask==0)
   {
     *((uint8_t*)Buffer1Bit) = Buff;
     Buffer1Bit = ((uint8_t*)Buffer1Bit)+1;
     Mask = 0x80;
     Buff = 0;
   }
 }
 if(Mask!=0x80)
     *(uint8_t*)Buffer1Bit = Buff;
}


void Raster1DAbstract::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
 unsigned i;
 unsigned MaskPos, iMaskPos;
 uint8_t Mask = 0x80;
 uint8_t Buff;

 if(Buffer1Bit==NULL || Size1D==0 || plane>=labs(GetPlanes())) return;		// Nothing to do, bit layer is padding.
 iMaskPos = (1l<<plane);
 MaskPos = ~iMaskPos;

 Buff = *(const uint8_t*)Buffer1Bit;
 for(i=0; i<Size1D; i++)
 {
   if(Buff & Mask)
     SetValue1D(i,(GetValue1D(i) | iMaskPos));
   else
     SetValue1D(i,(GetValue1D(i) & MaskPos));

   Mask >>= 1;
   if(Mask==0)
   {
     Buffer1Bit = ((const uint8_t*)Buffer1Bit)+1;     
     Mask = 0x80;
     Buff = *(const uint8_t*)Buffer1Bit;
   }
 }
}


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

 if(plane8>=labs(GetPlanes()) || Buffer8Bit==NULL || Data1D==NULL) return;

 R8.Data1D=(void*)Buffer8Bit;R8.Size1D=Size1D; R8.Shadow=true;
 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(void *Buffer8Bit, uint8_t plane8) const
{
 if(plane8 >= labs(GetPlanes()))
 {
   memset(Buffer8Bit,0,Size1D);
   return;
 }

 for(unsigned i=0; i<Size1D; i++)
   {
#ifdef NO_LVAL_CAST
   *(uint8_t*)Buffer8Bit = (GetValue1D(i)>>plane8) & 0xFF;
   Buffer8Bit = 1 + (uint8_t*)Buffer8Bit;
#else
   *((uint8_t*)Buffer8Bit)++ = (GetValue1D(i)>>plane8) & 0xFF;
#endif
   }
}


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

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


uint32_t Raster1D_1Bit::GetValue1D(unsigned x) const
{
const uint8_t *b;

 if(x>=Size1D || Data1D==NULL) return(0);
 b = (const uint8_t *)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, uint32_t NewValue) const
{
uint8_t *b;
 
 if(x>=Size1D || RAW_Data1D==NULL) return;
 b = (uint8_t *)RAW_Data1D + (x >> 3);
 if(NewValue==0) *b = *b & ~(0x80 >>(x & 0x07));
	    else *b = *b |  (0x80 >>(x & 0x07));
}


uint32_t Raster1D_1Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const uint8_t *b;

 if(x>=Size1D || RAW_Data1D==NULL) return(0);
 b = (const uint8_t *)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)
{
int i;

  i = R1.GetPlanes();
  switch(i)
  {
    case -32:
    case -64:					// Do not process floats here
    case -1:
    case 1: Raster1DAbstract::Set(R1);
	    return;
    case -4:
    case 4: Conv4_1((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case -8:
    case 8: Conv8_1((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case -16:
    case 16:Conv16_1((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_1((uint8_t *)Data1D,(const uint32_t *)R1.Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
 #ifdef LO_ENDIAN
    case 64:if(R1.Data1D)
                Peel1BitNStep((uint8_t *)Data1D, 7+(const uint8_t*)R1.Data1D, Size1D, 0x807);
	    return;
 #endif
 #ifdef HI_ENDIAN
    case 64:Peel1BitNStep((uint8_t *)Data1D, (const uint8_t*)R1.Data1D, Size1D, 0x807);
	    return;
 #endif
#endif
    }

  if(i<0)	// -32 and -64 are floats.
  {	// Converting from float to int is not fully implemented
    return;
  }
  else
  {
    uint8_t *N_Buffer8Bit = (uint8_t *)Data1D;
    uint8_t Mask;
    uint32_t 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 uint8_t *N_Buffer8Bit = (uint8_t *)Data1D;
unsigned i;
uint32_t Max;
uint8_t Mask;

  i = R1.GetPlanes();
  switch(i)
    {
    case 1: Raster1DAbstract::Get(R1);
	    return;
    case 4: Conv1_4((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 8: Conv1_8((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 16:Conv1_16((uint16_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 24: Conv1_24((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 32:Conv1_32((uint32_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv1_64((uint64_t*)R1.Data1D,(const uint8_t *)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++;
      }
    }
}


void Raster1D_1Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(Data1D==NULL) return;
 if(plane==0)
 {
   memcpy(Buffer1Bit,Data1D,(Size1D+7)/8);
 }
 else
 {
   memset(Buffer1Bit,0,(Size1D+7)/8);
 }
}

void Raster1D_1Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
 if(plane==0)
     memcpy(Data1D,Buffer1Bit,(Size1D+7)/8);
}


#endif  // OPTIMISE_SPEED


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

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

 if(Data1D==NULL || x>=Size1D) return 0;
 b = (const uint8_t *)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, uint32_t NewValue) const
{
uint8_t *b = (uint8_t *)RAW_Data1D;
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 Raster1D_2Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const uint8_t *b;

 if(RAW_Data1D==NULL || x>=Size1D) return 0;
 b = (const uint8_t *)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, uint32_t NewValue)
{
uint8_t *b=(uint8_t *)Data1D;

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


uint32_t Raster1D_4Bit::GetValue1D(unsigned x) const
{
const uint8_t *b=(uint8_t *)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, uint32_t NewValue) const
{
uint8_t *b = (uint8_t *)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);
}


uint32_t Raster1D_4Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
const uint8_t *b = (uint8_t *)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((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
//  case 4: Raster1DAbstract::Get(R1);
//	    return;
    case 8: Conv4_8((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 16:Conv4_16((uint16_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 32:Conv4_32((uint32_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    }

  Raster1DAbstract::Get(R1);
}


void Raster1D_4Bit::Set(const Raster1DAbstract &R1)
{
  switch(R1.GetPlanes())
    {
    case 1: Conv1_4((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
//  case 4: Raster1DAbstract::Set(R1);
//	    return;
    case 8: Conv8_4((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_4((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_4((uint8_t *)Data1D,(const uint32_t *)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((uint8_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
    	    return;
    case 4: Conv8_4((uint8_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
    	    return;
    case 8: Raster1DAbstract::Get(R1);
	    return;
    case 16:Conv8_16((uint16_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
	    return;
    case 24:Conv8_24((uint8_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
	    return;
    case 32:Conv8_32((uint32_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv8_64((uint64_t *)R1.Data1D,(const uint8_t*)Data1D,Size1D);
	    return;
#endif

    }

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

  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(uint32_t)(*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((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_8((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
    	    return;
    case 8: Raster1DAbstract::Set(R1);
	    return;
    case 16:Conv16_8((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 24:Conv24_8((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
            return;
    case 32:Conv32_8((uint8_t *)Data1D,(const uint32_t *)R1.Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
 #ifdef LO_ENDIAN
    case 64:if(R1.Data1D)
                Peel8BitNStep((uint8_t *)Data1D, 7+(const uint8_t*)R1.Data1D, Size1D, 8);
	    return;
 #endif
 #ifdef HI_ENDIAN
    case 64:Peel8BitNStep((uint8_t *)Data1D, (const uint8_t*)R1.Data1D, Size1D, 8);
	    return;
 #endif
#endif

    }

  uint8_t *N_Buffer8Bit = (uint8_t *)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;
      }
    }
}


void Raster1D_8Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(plane>=8)
 {
   if(Buffer1Bit!=NULL)
       memset(Buffer1Bit,0,(Size1D+7)/8);
 }
 else
   Peel1BitNStep((uint8_t*)Buffer1Bit, (const uint8_t*)Data1D, Size1D, 0x100|plane);
}


void Raster1D_8Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
  if(plane<8)
    Join1BitNStep((const uint8_t*)Buffer1Bit,(uint8_t*)Data1D,Size1D,0x100|plane);
}


void Raster1D_8Bit::Peel8Bit(void *Buffer8Bit, uint8_t plane8) const
{
  if(plane8!=0)  
    Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8);
  else
  {
    if(Buffer8Bit!=NULL)
        memcpy(Buffer8Bit,Data1D,Size1D);
  }
}


void Raster1D_8Bit::Join8Bit(const void *Buffer8Bit, uint8_t plane8)
{
  if(plane8!=0)
      Raster1DAbstract::Join8Bit(Buffer8Bit,plane8);
  else
  {
    if(Buffer8Bit!=NULL)
        memcpy(Data1D,	Buffer8Bit,Size1D);
  }  
}


#endif // OPTIMISE_SPEED


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


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


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


uint32_t Raster1D_8Bit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const 
{
  if(x>=Size1D || RAW_Data1D==NULL) return(0);
  return(((uint8_t *)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;
  ((uint8_t *)RAW_Data1D)[x] = (uint8_t)NewValue;
}


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


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

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

void Raster1D_16Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, uint32_t NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((uint16_t *)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(((uint16_t *)RAW_Data1D)[x]);
}

void Raster1D_16Bit::PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((uint16_t *)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((uint8_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
    	    return;
    case 4: Conv16_4((uint8_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
    	    return;
    case 8: Conv16_8((uint8_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
	    return;
    case 16:Raster1DAbstract::Get(R1);
	    return;
    case 24:Conv16_24((uint8_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
	    return;
    case 32:Conv16_32((uint32_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv16_64((uint64_t *)R1.Data1D,(const uint16_t *)Data1D,Size1D);
	    return;
#endif
    }
  shift = i - 16;
  const uint16_t *N_Buffer16Bit = (const uint16_t *)Data1D;
  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(uint32_t)(*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((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_16((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
            return;
    case 8: Conv8_16((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 16:Raster1DAbstract::Set(R1);
	    return;
    case 24:Conv24_16((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
            return;    
    case 32:Conv32_16((uint16_t *)Data1D,(const uint32_t *)R1.Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv64_16((uint16_t *)Data1D,(const uint64_t *)R1.Data1D,Size1D);
	    return;
#endif
    }
  shift = 16 - i;

  uint16_t *N_Buffer16Bit = (uint16_t *)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;
      }
    }
}


void Raster1D_16Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(plane>=16)
 {
   if(Buffer1Bit!=NULL)
       memset(Buffer1Bit,0,(Size1D+7)/8);
 }
 else
 {
#ifdef HI_ENDIAN
   if(plane<8)   
     Peel1BitNStep((uint8_t*)Buffer1Bit, 1+(const uint8_t*)Data1D, Size1D, 0x200|plane);
   else
     Peel1BitNStep((uint8_t*)Buffer1Bit, (const uint8_t*)Data1D, Size1D, 0x200|(plane-8));
#else
 #ifdef LO_ENDIAN
   Peel1BitNStep((uint8_t*)Buffer1Bit, (plane>>3)+(const uint8_t*)Data1D, Size1D, 0x200|(plane%8));
 #else
    Raster1DAbstract::Peel1Bit(Buffer1Bit,plane);	// ?? Unspecified endian, use default.
 #endif
#endif
 }
}


void Raster1D_16Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
  if(plane<16)
  {
#ifdef HI_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(1-(plane>>3))+(uint8_t*)Data1D,Size1D,0x200|(plane%8));
#else
 #ifdef LO_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(plane>>3)+(uint8_t*)Data1D,Size1D,0x200|(plane%8));
 #else
    Raster1DAbstract::Join1Bit(Buffer1Bit,plane);	// ??
 #endif
#endif
  }
}


#endif // OPTIMISE_SPEED


/*
Raster1D_16BitIDX::Raster1D_16BitIDX(int InitSize1D, Raster1DAbstractRGB *newPalette): Raster1D_16Bit(InitSize1D)
{
  pPalette = newPalette;
  if(pPalette!=NULL)
      pPalette->UsageCount++;
}


Raster1D_16BitIDX::~Raster1D_16BitIDX()
{
  if(pPalette!=NULL)
  {
    if(InterlockedDecrement(&pPalette->UsageCount)<=0) delete(pPalette);
    pPalette = NULL;
  }
}


void Raster1D_16BitIDX::Set(const Raster1DAbstract &R1)
{
  if(pPalette!=NULL && R1.Channels()>=4 && Data1D!=NULL)
  {
    int maxi = Size1D>R1.Size1D?Size1D:R1.Size1D;
    uint32_t val;
    while(maxi-- > 0)
    {
      val = GetValue1D(maxi);	// Indexed Val;
      R1.SetValue1D(maxi,val);
    }
  }
  else
    Raster1D_16Bit::Set(R1);
}
*/

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

void Raster1D_24Bit::SetValue1D(unsigned x, uint32_t NewValue)
{
uint8_t *BuffPos;

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


uint32_t Raster1D_24Bit::GetValue1D(unsigned x) const
{
const uint8_t *b;

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


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

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


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

 if(x>=Size1D || RAW_Data1D==NULL) return;
 BuffPos = ((uint8_t *)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((uint8_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 16:Conv24_16((uint16_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
    case 32:Conv24_32((uint32_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv24_64((uint64_t *)R1.Data1D,(const uint8_t *)Data1D,Size1D);
	    return;
#endif
    }
  Raster1DAbstract::Get(R1);
}


void Raster1D_24Bit::Set(const Raster1DAbstract &R1)
{  
  switch(R1.GetPlanes())
    {
    case 1: Conv1_24((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_24((uint8_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_24((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_24((uint8_t *)Data1D,(const uint32_t *)R1.Data1D,Size1D);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv64_24((uint8_t *)Data1D,(const uint64_t *)R1.Data1D,Size1D);
	    return;
#endif
    }
  Raster1DAbstract::Set(R1);
}


void Raster1D_24Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(plane>=24)
 {
   if(Buffer1Bit!=NULL)
       memset(Buffer1Bit,0,(Size1D+7)/8);
 }
 else
 {
   Peel1BitNStep((uint8_t*)Buffer1Bit, (plane>>3)+(const uint8_t*)Data1D, Size1D, 0x300|(plane%8));
 }
}


void Raster1D_24Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
  if(plane<24)
  {
    Join1BitNStep((const uint8_t*)Buffer1Bit,(plane>>3)+(uint8_t*)Data1D,Size1D,0x300|(plane%8));
  }
}


#endif // OPTIMISE_SPEED


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

  Peel8BitNStep((uint8_t*)Buffer8Bit, (plane8>>3)+(const uint8_t*)Data1D, Size1D, 3);
}


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

  Join8BitNStep((const uint8_t*)Buffer8Bit, (plane8>>3)+(uint8_t*)Data1D, Size1D, 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
    ((uint32_t *)Data1D)[x] = 0xFFFFFFFFl;
  else
    ((uint32_t *)Data1D)[x] = NewValue;
}


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

void Raster1D_32Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, uint32_t NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((uint32_t *)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
    ((uint32_t *)RAW_Data1D)[x] = 0xFFFFFFFFl;
  else
    ((uint32_t *)RAW_Data1D)[x] = NewValue;
}
#endif


/*
void Raster1DAbstract::Get32Bit(void *Buffer32Bit) const
{
uint32_t *N_Buffer32Bit = (uint32_t *)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((uint8_t *)R1.Data1D,(const uint32_t *)Data1D,Size1D);
    	    return;
    case 4: Conv32_4((uint8_t *)R1.Data1D,(const uint32_t *)Data1D,Size1D);
    	    return;
    case 8: Conv32_8((uint8_t *)R1.Data1D,(const uint32_t *)Data1D,Size1D);
	    return;
    case 16:Conv32_16((uint16_t *)R1.Data1D,(const uint32_t *)Data1D,Size1D);
	    return;
    case 24:Conv32_24((uint8_t *)R1.Data1D,(const uint32_t *)Data1D,Size1D);
	    return;
    case 32:Raster1DAbstract::Get(R1);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv32_64((uint64_t *)R1.Data1D,(const uint32_t*)Data1D,Size1D);
	    return;
#endif

    }

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

  if(shift>0)
    for(i=0;i<Size1D;i++)
      {
      R1.SetValue1D(i,(uint32_t)(*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((uint32_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
    	    return;
    case 4: Conv4_32((uint32_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_32((uint32_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_32((uint32_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 24:Conv24_32((uint32_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 32:Raster1DAbstract::Set(R1);
	    return;
#if defined(uint64_t_defined)
    case 64:Conv64_32((uint32_t *)Data1D,(const uint64_t *)R1.Data1D,Size1D);
	    return;
#endif
    }

  uint32_t *N_Buffer32Bit = (uint32_t *)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;
      }
    }
}


void Raster1D_32Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(plane>=32)
 {
   if(Buffer1Bit!=NULL)
       memset(Buffer1Bit,0,(Size1D+7)/8);
 }
 else
 {
#ifdef HI_ENDIAN
   Peel1BitNStep((uint8_t*)Buffer1Bit, (3-(plane>>3))+(const uint8_t*)Data1D, Size1D, 0x400|(plane%8));
#else
 #ifdef LO_ENDIAN
   Peel1BitNStep((uint8_t*)Buffer1Bit, (plane>>3)+(const uint8_t*)Data1D, Size1D, 0x400|(plane%8));
 #else
   Raster1DAbstract::Peel1Bit(Buffer1Bit,plane);	// ?? Unspecified endian, use default.
 #endif
#endif
 }
}


void Raster1D_32Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
  if(plane<32)
  {
#ifdef HI_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(3-(plane>>3))+(uint8_t*)Data1D,Size1D,0x400|(plane%8));
#else
 #ifdef LO_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(plane>>3)+(uint8_t*)Data1D,Size1D,0x400|(plane%8));
 #else
    Raster1DAbstract::Join1Bit(Buffer1Bit,plane);	// ??
 #endif
#endif
  }
}


#endif // OPTIMISE_SPEED


void Raster1D_32Bit::Peel8Bit(void *Buffer8Bit, uint8_t plane8) const
{
  if((plane8 & 0x3)!=0 || plane8>24)
    {Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8); return;}

#ifdef HI_ENDIAN
  Peel8BitNStep((uint8_t*)Buffer8Bit, (3-(plane8>>3))+(const uint8_t*)Data1D, Size1D, 4);
#else
 #ifdef LO_ENDIAN
  Peel8BitNStep((uint8_t*)Buffer8Bit, (plane8>>3)+(const uint8_t*)Data1D, Size1D, 4);
 #else
  Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8);
 #endif
#endif
}


void Raster1D_32Bit::Join8Bit(const void *Buffer8Bit, uint8_t plane8)
{
  if((plane8 & 0x3)!=0 || plane8>24)
    {Raster1DAbstract::Join8Bit(Buffer8Bit,plane8); return;}

#ifdef HI_ENDIAN
  Join8BitNStep((const uint8_t*)Buffer8Bit, (3-(plane8>>3))+(uint8_t*)Data1D, Size1D, 4);
#else
 #ifdef LO_ENDIAN
  Join8BitNStep((const uint8_t*)Buffer8Bit, (plane8>>3)+(uint8_t*)Data1D, Size1D, 4);
 #else
  Raster1DAbstract::Join8Bit(Buffer8Bit,plane8);
 #endif
#endif
}


/* ------------ 64 bit planes -------------- */
#if defined(uint64_t_defined)

uint32_t Raster1D_64Bit::GetValue1D(unsigned x) const 
{
  if(x>=Size1D) return 0;
  const uint64_t q = ((uint64_t *)Data1D)[x];
  return((uint32_t)(q>>32));
};


void Raster1D_64Bit::SetValue1D(unsigned x, uint32_t NewValue)
{
  if(x<Size1D) 
    ((uint64_t *)Data1D)[x] = NewValue *
#ifdef __BORLANDC__
			(uint64_t)0x0000000100000001ui64;
#else
			(uint64_t)0x0000000100000001ll;
#endif                       
  return;
};


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


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

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

void Raster1D_64Bit::PTR_SetValue1D(void *RAW_Data1D, unsigned x, uint32_t NewValue) const
{
  if(RAW_Data1D==NULL || Size1D<=x) return; 
  ((uint64_t *)RAW_Data1D)[x] = NewValue *
#ifdef __BORLANDC__
			(uint64_t)0x0000000100000001ui64;
#else
			(uint64_t)0x0000000100000001ll;
#endif
}

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)
    ((uint64_t *)RAW_Data1D)[x] = (uint64_t)_UI64_MAX;
  else
    ((uint64_t *)RAW_Data1D)[x] = (uint64_t)NewValue;
}
#endif


void Raster1D_64Bit::Peel1Bit(void *Buffer1Bit, uint8_t plane) const
{
 if(plane>=64)
 {
   if(Buffer1Bit!=NULL)
       memset(Buffer1Bit,0,(Size1D+7)/8);
 }
 else
 {
#ifdef HI_ENDIAN
   Peel1BitNStep((uint8_t*)Buffer1Bit, (7-(plane>>3))+(const uint8_t*)Data1D, Size1D, 0x800|(plane%8));
#else
 #ifdef LO_ENDIAN
   Peel1BitNStep((uint8_t*)Buffer1Bit, (plane>>3)+(const uint8_t*)Data1D, Size1D, 0x800|(plane%8));
 #else
   Raster1DAbstract::Peel1Bit(Buffer1Bit,plane);	// ?? Unspecified endian, use default.
 #endif
#endif
 }
}


void Raster1D_64Bit::Join1Bit(const void *Buffer1Bit, uint8_t plane)
{
  if(plane<64)
  {
#ifdef HI_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(7-(plane>>3))+(uint8_t*)Data1D,Size1D,0x800|(plane%8));
#else
 #ifdef LO_ENDIAN
    Join1BitNStep((const uint8_t*)Buffer1Bit,(plane>>3)+(uint8_t*)Data1D,Size1D,0x800|(plane%8));
 #else
    Raster1DAbstract::Join1Bit(Buffer1Bit,plane);	// ??
 #endif
#endif
  }
}


void Raster1D_64Bit::Peel8Bit(void *Buffer8Bit, uint8_t plane8) const
{
  if((plane8 & 0x3)!=0 || plane8>56)
    {Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8); return;}

#ifdef HI_ENDIAN
  Peel8BitNStep((uint8_t*)Buffer8Bit, (7-(plane8>>3))+(const uint8_t*)Data1D, Size1D, 8);
#else
 #ifdef LO_ENDIAN
  Peel8BitNStep((uint8_t*)Buffer8Bit, (plane8>>3)+(const uint8_t*)Data1D, Size1D, 8);
 #else
  Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8);
 #endif
#endif
}


void Raster1D_64Bit::Join8Bit(const void *Buffer8Bit, uint8_t plane8)
{
  if((plane8 & 0x3)!=0 || plane8>56)
    {Raster1DAbstract::Join8Bit(Buffer8Bit,plane8); return;}

#ifdef HI_ENDIAN
  Join8BitNStep((const uint8_t*)Buffer8Bit, (7-(plane8>>3))+(uint8_t*)Data1D, Size1D, 8);
#else
 #ifdef LO_ENDIAN
  Join8BitNStep((const uint8_t*)Buffer8Bit, (plane8>>3)+(uint8_t*)Data1D, Size1D, 8);
 #else
  Raster1DAbstract::Join8Bit(Buffer8Bit,plane8);
 #endif
#endif
}


#ifdef OPTIMISE_SPEED


void Raster1D_64Bit::Get(Raster1DAbstract &R1) const
{
  switch(R1.GetPlanes())
    {
#ifdef LO_ENDIAN
    case 1: if(Data1D)
                Peel1BitNStep((uint8_t *)R1.Data1D, 7+(const uint8_t*)Data1D, Size1D, 0x807);
	    return;
    case 8: if(Data1D)
                Peel8BitNStep((uint8_t *)R1.Data1D, 7+(const uint8_t*)Data1D, Size1D, 8);
	    return;
#endif
#ifdef HI_ENDIAN
    case 1: Peel1BitNStep((uint8_t *)R1.Data1D, (const uint8_t*)Data1D, Size1D, 0x807);
	    return;
    case 8: Peel8BitNStep((uint8_t *)R1.Data1D, (const uint8_t*)Data1D, Size1D, 8);
	    return;
#endif
    //case 8: Conv64_8((uint8_t *)R1.Data1D,(const uint64_t *)Data1D,Size1D);
    //	    return;
    case 16:Conv64_16((uint16_t *)R1.Data1D,(const uint64_t *)Data1D,Size1D);
	    return;
    case 24:Conv64_24((uint8_t *)R1.Data1D,(const uint64_t *)Data1D,Size1D);
	    return;
    case 32:Conv64_32((uint32_t *)R1.Data1D,(const uint64_t *)Data1D,Size1D);
	    return;
    }
  Raster1DAbstract::Get(R1);
}


void Raster1D_64Bit::Set(const Raster1DAbstract &R1)
{
  switch(R1.GetPlanes())
    {
    case 1: Conv1_64((uint64_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 8: Conv8_64((uint64_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 16:Conv16_64((uint64_t *)Data1D,(const uint16_t *)R1.Data1D,Size1D);
	    return;
    case 24:Conv24_64((uint64_t *)Data1D,(const uint8_t *)R1.Data1D,Size1D);
	    return;
    case 32:Conv32_64((uint64_t *)Data1D,(const uint32_t *)R1.Data1D,Size1D);
	    return;
    }
  Raster1DAbstract::Set(R1);
}

#endif

#endif


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

uint32_t 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, uint32_t 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
uint32_t 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, uint32_t 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 -------------- */

/// Normalises value to the range 0 - 0xFFFFFFFF.
uint32_t Raster1D_64FltBit::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  return (0xFFFFFFFF*(((double *)Data1D)[x] - Min)/(Max-Min)) + 0.5; // provide proper rounding.
}

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


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


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

#ifdef _REENTRANT
uint32_t Raster1D_64FltBit::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return (0xFFFFFFFF*(((double *)RAW_Data1D)[x] - Min)/(Max-Min)) + 0.5; // provide proper rounding.  
}


/// Must be consistent with Raster1D_64FltBit::GetValue1Dd
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, uint32_t NewValue) const
{
  if(x>=Size1D) return;
  ((double *)RAW_Data1D)[x] = Min + ((double)NewValue*(Max-Min))/0xFFFFFFFF;
  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;
#if defined(uint64_t_defined)
   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;
uint32_t 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: while(maxi-- > 0)	// convert from gray to RGB
		{
		val = R1.GetValue1D(maxi);
		setR(maxi,val);
		setG(maxi,val);
		setB(maxi,val);
		}
	      return;

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

      case 4: while(maxi-- > 0)		// convert from RGBA to RGB
		{
		val = R1.GetValue1D(maxi);
		setR(maxi,val & 0xFF);
		setG(maxi,(val>>8)& 0xFF);
		setB(maxi,(val>>16)& 0xFF);
		}
	      return;
      }
    }

  if(shift>0)
    {
    while(maxi-- > 0)
       {
       val = R1.GetValue1D(maxi);
       val <<= shift;
       setR(maxi,val);
       setG(maxi,val);
       setB(maxi,val);
       }
    return;
    }
  else
    {
    shift = -shift;
    while(maxi-- > 0)
     {
     val = R1.GetValue1D(i);
     val >>= shift;
     setR(maxi,val);
     setG(maxi,val);
     setB(maxi,val);
     }
    return;
    }
}


void Raster1DAbstractRGB::Set(const Raster1DAbstract &R1, const Raster1DAbstract &Palette)
{
int maxi;
signed char shift = 0;
uint32_t val;

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

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

  if(shift>0)
    {
    while(maxi-- > 0)
      {
      val = R1.GetValue1D(maxi);
      val = Palette.GetValue1D(maxi);
      setR(maxi,val<<shift);
      setG(maxi,val<<shift);
      setB(maxi,val<<shift);
      }
    }
  else
    {
    shift = -shift;
    while(maxi-- > 0)
      {
      val = R1.GetValue1D(maxi);
      val = Palette.GetValue1D(maxi);
      setR(maxi,val>>shift);
      setG(maxi,val>>shift);
      setB(maxi,val>>shift);
      }

    }
}


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

  if(Data1D==NULL || R1.Data1D==NULL) return;
  memset(&RGB,0,sizeof(RGB));

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

  switch(R1.Channels())
  {
    case 1:
    case 2: if(shift==0)		// No bitplane change - copy data only
            {
	      for(i=0;i<maxi;i++)
              {
                RGB.R = RGB.G = RGB.B = R1.GetValue1D(i);
                Set(i,&RGB);
              }
              return;
            }

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

    case 3: if(shift==0)		// No bitplane change - copy data only
            {
	      for(i=0;i<maxi;i++)
              {
		R1.Get(i,&RGB);
                Set(i,&RGB);
              }
              return;
            }

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

    case 4: 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++)
              {
	        R1.Get(i,&RGB);
	        RGB.R <<= shift;
	        RGB.G <<= shift;
	        RGB.B <<= shift;
                RGB.O <<= shift;
                Set(i,&RGB);
              }
              return;
           }
           else
           {
             shift = -shift;
             for(i=0;i<maxi;i++)
             {
               R1.Get(i,&RGB);
	       RGB.R >>= shift;
	       RGB.G >>= shift;
	       RGB.B >>= shift;
               RGB.O >>= shift;
               Set(i,&RGB);
             }
             return;
          }
  }
}


void Raster1DAbstractRGB::Get(unsigned index, RGBQuad *RGB) const
{
 if(RGB==NULL) return;
 RGB->R = R(index);
 RGB->G = G(index);
 RGB->B = B(index);
}


void Raster1DAbstractRGBA::Get(unsigned index, RGBQuad *RGB) const
{
 if(RGB==NULL) return;
 RGB->R = R(index);
 RGB->G = G(index);
 RGB->B = B(index);
 RGB->O = A(index);
}


void Raster1DAbstractRGB::Set(unsigned index, const RGBQuad *RGB)
{
 if(RGB==NULL) return;
 setR(index, RGB->R);
 setG(index, RGB->G);
 setB(index, RGB->B);
}


void Raster1DAbstractRGBA::Set(unsigned index, const RGBQuad *RGB)
{
 if(RGB==NULL) return;
 setR(index, RGB->R);
 setG(index, RGB->G);
 setB(index, RGB->B);
 setA(index, RGB->O);
}


/* 16 bit planes for 3 channels R,G,B in geometry A1 R5 G5 B5 */


void Raster1D_16Bit565::Get(unsigned index, RGBQuad *RGB) const
{
  if(RGB==NULL) return;
  if(Data1D==NULL || Size1D<index) {memset(RGB,0,sizeof(RGBQuad));return;}
  uint32_t val = ((uint16_t *)Data1D)[index];
  RGB->B = (val&0x1F) << 3;
  RGB->G = (val>>3) & 0xFC;	// ((val>>5)&0x3F) << 2;
  RGB->R = (val>>8) & 0xF8;	//((val>>11)&0x1F) << 2;
  RGB->O = 0;
}


void Raster1D_16Bit565::Set(unsigned index, const RGBQuad *RGB)
{
  if(RGB==NULL || Data1D==NULL || Size1D<index) return;
  ((uint16_t *)Data1D)[index] = (RGB->B>>3) | ((RGB->G & 0xFC)<<3) | ((RGB->R & 0xF8)<<8);
}


#ifdef _REENTRANT
uint32_t Raster1D_16Bit565::PTR_GetValue1DRAW(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  uint32_t val = ((uint16_t *)RAW_Data1D)[x];
  //return ((255*(val&0x1F)/31)<<16) | ((255*((val>>5)&0x1F)/31)<<8) | (255*((val>>10)&0x1F)/31);
  return ((val&0x1F)<<19) | (((val>>5)&0x3F)<<10) | (((val>>11)&0x1F)<<3);
}


void Raster1D_16Bit565::PTR_SetValue1DRAW(void *RAW_Data1D, unsigned x, uint32_t NewValue)
{
  if(RAW_Data1D==NULL || Size1D<x) return;
  ((uint16_t *)RAW_Data1D)[x] = ((NewValue&0xFF)>>3) | ((NewValue&0xFC00)>>5) | ((NewValue&0xF80000)>>8);
}
#endif


uint32_t Raster1D_16Bit565::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  uint32_t val = ((uint16_t *)Data1D)[x];
  //return ((255*(val&0x1F)/31)<<16) | ((255*((val>>5)&0x1F)/31)<<8) | (255*((val>>10)&0x1F)/31);
  return ((val&0x1F)<<19) | ((val&0x7E0)<<5) | ((val&0xF800)>>8);
}


void Raster1D_16Bit565::SetValue1D(unsigned x, uint32_t NewValue)
{
  if(Size1D<=x) return;
  ((uint16_t *)Data1D)[x] = (uint16_t)(((NewValue&0xF8)<<8) | ((NewValue&0xFC00)>>5) | ((NewValue&0xF80000)>>19));
}


/*
void Raster1D_16BitA1R5G5B5:Get24BitRGB(void *Buffer24Bit) const
{
}
*/

uint32_t Raster1D_16Bit565::R(unsigned x) const
{
  return((((const uint16_t*)Data1D)[x]>>8)&0xF8);
}

uint32_t Raster1D_16Bit565::G(unsigned x) const 
{
  return((((const uint16_t*)Data1D)[x]>>3)&0xFC);
}

uint32_t Raster1D_16Bit565::B(unsigned x) const 
{
  return((((const uint16_t*)Data1D)[x]&0x1F)<<3);
}

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

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

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


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


void Raster1D_8BitRGB::Get(unsigned index, RGBQuad *RGB) const
{
uint8_t *ptrb;

 if(RGB==NULL || Data1D==NULL || Size1D<index) return;
 index *= 3; 
 ptrb = ((uint8_t *)Data1D)+index;
 RGB->R = *ptrb++;
 RGB->G = *ptrb++;
 RGB->B = *ptrb;
 RGB->O = 0;
}


void Raster1D_8BitRGB::Set(const Raster1DAbstract &R1)
{
 if(R1.Channels()==3)
 {
   switch(R1.GetPlanes())
    {
    case 3*8: memcpy(Data1D,R1.Data1D,3*Size1D);
	      return;
    case 3*16:Conv16_8((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,3*Size1D);
	      return;
    }
 }
 Raster1DAbstractRGB::Set(R1);
}

#ifdef OPTIMISE_SPEED
void  Raster1D_8BitRGB::Set(unsigned x, const RGBQuad *RGB)

{
  if(Size1D<=x || RGB==NULL) return;
  x *= 3;
  ((uint8_t *)Data1D)[x] = RGB->R & 0xFF;
  ((uint8_t *)Data1D)[x+1] = RGB->G & 0xFF;
  ((uint8_t *)Data1D)[x+2] = RGB->B & 0xFF;
}
#endif


#ifdef _REENTRANT

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

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

#endif


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

  Peel8BitNStep((uint8_t*)Buffer8Bit, (plane8>>3)+(const uint8_t*)Data1D, Size1D, 3);
}


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

  Join8BitNStep((const uint8_t*)Buffer8Bit, (plane8>>3)+(uint8_t*)Data1D, Size1D, 3);
}


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

uint32_t Raster1D_16BitRGB::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 6;
#ifdef HI_ENDIAN
  return((uint32_t)((const uint8_t *)Data1D)[x+0] |
        ((uint32_t)((const uint8_t *)Data1D)[x+2])<<8 |
        ((uint32_t)((const uint8_t *)Data1D)[x+4])<<16);
#else
   return((uint32_t)((const uint8_t *)Data1D)[x+1] |
        ((uint32_t)((const uint8_t *)Data1D)[x+3])<<8 |
        ((uint32_t)((const uint8_t *)Data1D)[x+5])<<16);
#endif
}


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


void Raster1D_16BitRGB::Get24BitRGB(void *Buffer24Bit) const
{
  Conv16_8((unsigned char*)Buffer24Bit, (uint16_t*)Data1D, 3*Size1D);
}

void Raster1D_16BitRGB::Get(unsigned index, RGBQuad *RGB) const
{
const uint16_t *ptrw;

 if(RGB==NULL || Data1D==NULL || Size1D<index) return;
 ptrw = (const uint16_t*)(((const uint8_t *)Data1D)+6*index);
 RGB->R = *ptrw++;
 RGB->G = *ptrw++;
 RGB->B = *ptrw++;
}


void Raster1D_16BitRGB::Set(const Raster1DAbstract &R1)
{
 if(R1.Channels()==3)
 {
   switch(R1.GetPlanes())
    {
    case 3*8: Conv8_16((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,3*Size1D);
	      return;
    case 3*16:memcpy(Data1D,R1.Data1D,3*Size1D);
	      return;
    }
 }
 Raster1DAbstractRGB::Set(R1);
}


#ifdef _REENTRANT

uint32_t Raster1D_16BitRGB::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 6;
#ifdef HI_ENDIAN
  return((uint32_t)((const uint8_t *)RAW_Data1D)[x+0] |
        ((uint32_t)((const uint8_t *)RAW_Data1D)[x+2])<<8 |
        ((uint32_t)((const uint8_t *)RAW_Data1D)[x+4])<<16);
#else
  return((uint32_t)((const uint8_t *)RAW_Data1D)[x+1] |
        ((uint32_t)((const uint8_t *)RAW_Data1D)[x+3])<<8 |
        ((uint32_t)((const uint8_t *)RAW_Data1D)[x+5])<<16);
#endif
}

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

#endif




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

uint32_t Raster1D_8BitRGBA::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
#ifdef HI_ENDIAN
  return  __builtin_bswap32(((uint32_t *)Data1D)[x]);
#else
  return ((uint32_t *)Data1D)[x];
#endif
}


void Raster1D_8BitRGBA::SetValue1D(unsigned x, uint32_t NewValue)
{
  if(Size1D<=x) return;
  ((uint32_t *)Data1D)[x] = 
#ifdef HI_ENDIAN
	 __builtin_bswap32(NewValue);
#else
	NewValue;
#endif
}


void Raster1D_8BitRGBA::Get(unsigned x, RGBQuad *RGB) const
{
const uint32_t d = ((uint32_t *)Data1D)[x];
#ifdef HI_ENDIAN
  RGB->O = d & 0xFF;
  RGB->B = (d>>8) & 0xFF;
  RGB->G = (d>>16) & 0xFF;
  RGB->R = (d>>24) & 0xFF;
#else
  RGB->R = d & 0xFF;
  RGB->G = (d>>8) & 0xFF;
  RGB->B = (d>>16) & 0xFF;
  RGB->O = (d>>24) & 0xFF;
#endif
}


void Raster1D_8BitRGBA::Get24BitRGB(void *Buffer24Bit) const
{
uint8_t *BBuffer24Bit = (uint8_t *)Buffer24Bit;

  if(Buffer24Bit==NULL) return;
  for(unsigned x=0; x<Size1D; x++)
  {
    const uint32_t d = ((const uint32_t *)Data1D)[x];
#ifdef HI_ENDIAN
    *BBuffer24Bit++ = (d>>24) & 0xFF;
    *BBuffer24Bit++ = (d>>16) & 0xFF;
    *BBuffer24Bit++ = (d>>8) & 0xFF;
#else
    *BBuffer24Bit++ = d & 0xFF;
    *BBuffer24Bit++ = (d>>8) & 0xFF;
    *BBuffer24Bit++ = (d>>16) & 0xFF;
#endif
  }
}


void Raster1D_8BitRGBA::Set(const Raster1DAbstract &R1)
{
 if(R1.Channels()==4)
 {
   switch(R1.GetPlanes())
    {
    case 4*8: memcpy(Data1D,R1.Data1D,4*Size1D);
	      return;
    case 4*16:Conv16_8((uint8_t *)Data1D,(const uint16_t *)R1.Data1D,4*Size1D);
	      return;
    }
 }
 Raster1DAbstractRGBA::Set(R1);
}


#ifdef _REENTRANT

uint32_t Raster1D_8BitRGBA::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return
#ifdef HI_ENDIAN
	__builtin_bswap32
#endif
		(((const uint32_t*)RAW_Data1D)[x]);
}

void Raster1D_8BitRGBA::PTR_SetValue1D(void *RAW_Data1D, unsigned x, uint32_t NewValue) const
{
  if(Size1D<=x) return;
  ((uint32_t *)RAW_Data1D)[x] =
#ifdef HI_ENDIAN
	 __builtin_bswap32(NewValue);
#else
	NewValue;
#endif
}
#endif


void Raster1D_8BitRGBA::Peel8Bit(void *Buffer8Bit, uint8_t plane8) const
{
  if((plane8 & 0x3)!=0 || plane8>24)
    {Raster1DAbstract::Peel8Bit(Buffer8Bit,plane8); return;}

  Peel8BitNStep((uint8_t*)Buffer8Bit, (plane8>>3)+(const uint8_t*)Data1D, Size1D, 4);
}


void Raster1D_8BitRGBA::Join8Bit(const void *Buffer8Bit, uint8_t plane8)
{
  if((plane8 & 0x3)!=0 || plane8>24)
    {Raster1DAbstract::Join8Bit(Buffer8Bit,plane8); return;}

  Join8BitNStep((const uint8_t*)Buffer8Bit, (plane8>>3)+(uint8_t*)Data1D, Size1D, 4);
}



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


uint32_t Raster1D_16BitRGBA::GetValue1D(unsigned x) const
{
  if(x>=Size1D) return 0;
  x *= 8;
#ifdef HI_ENDIAN
  return((uint32_t)((const uint8_t *)Data1D)[x+0] |
	((uint32_t)((const uint8_t *)Data1D)[x+2])<<8 |
	((uint32_t)((const uint8_t *)Data1D)[x+4])<<16 |
	((uint32_t)((const uint8_t *)Data1D)[x+6])<<24);
#else
  return((uint32_t)((const uint8_t *)Data1D)[x+1] |
	((uint32_t)((const uint8_t *)Data1D)[x+3])<<8 |
	((uint32_t)((const uint8_t *)Data1D)[x+5])<<16 |
	((uint32_t)((const uint8_t *)Data1D)[x+7])<<24);
#endif
}


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


#ifdef _REENTRANT
uint32_t Raster1D_16BitRGBA::PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const
{
  if(x>=Size1D) return 0;
  return((uint32_t)((const uint8_t *)RAW_Data1D)[x+1] |
	((uint32_t)((const uint8_t *)RAW_Data1D)[x+3])<<8 |
	((uint32_t)((const uint8_t *)RAW_Data1D)[x+5])<<16 |
	((uint32_t)((const uint8_t *)RAW_Data1D)[x+7])<<24);
}

void Raster1D_16BitRGBA::PTR_SetValue1D(void *RAW_Data1D, unsigned x, uint32_t NewValue) const
{
  if(Size1D<=x) return;
  x *= 4;
  ((uint16_t *)RAW_Data1D)[x] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((uint16_t *)RAW_Data1D)[x+1] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((uint16_t *)RAW_Data1D)[x+2] = (NewValue & 0xFF) * 0x101;
  NewValue >>= 8;
  ((uint16_t *)RAW_Data1D)[x+3] = (NewValue & 0xFF) * 0x101;
}
#endif


void Raster1D_16BitRGBA::Set(const Raster1DAbstract &R1)
{
 if(R1.Channels()==4)
 {
   switch(R1.GetPlanes())
   {
    case 8*4: Conv8_16((uint16_t *)Data1D,(const uint8_t *)R1.Data1D,4*Size1D);
	      return;
    case 16*4:memcpy(Data1D,R1.Data1D,4*Size1D);
	      return;
   }
 }
 Raster1DAbstractRGBA::Set(R1);
}


/*
void Raster1D_24Bit::Get(Raster1DAbstract &R1) const
{
uint8_t *N_Buffer24Bit = (uint8_t *)R1->Data1D;
uint32_t 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  5: Raster=new Raster1D_16Bit565; break;
   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)
{
 //printf("Erasing Ras2D |%p|",Data2D);
 if(Shadow)
 {
   Data2D = NULL;
   Size2D = 0;
   Erase1DStub();
   return;
 }

 if(Data2D)
 {
   const unsigned 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)
 {
   if(Size1D==NewSize1D && Size2D==NewSize2D) return; // No allocation needed
   Erase();
 }
 if(NewSize1D==0 || NewSize2D==0) return;	// Do not allocate empty object.

 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();
     RaiseError(RasterId|No_Memory,this);
     return;
     }
   }
 //printf("Allocate2D |%p|",Data2D);
}


/** 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*)this)->Get(R1);
#endif
}


void Raster2DAbstract::Get(unsigned Offset1D, unsigned Offset2D, RGBQuad *RGB)
{
  if(Data2D==NULL || Offset2D>=Size2D) return;
  Data1D = Data2D[Offset2D];
  ((const Raster1DAbstract*)this)->Get(Offset1D,RGB);		//Raster1DAbstract::Get() forces only one method not using VMT.
}


void Raster2DAbstract::Set(unsigned Offset1D, unsigned Offset2D, const RGBQuad *RGB)
{
  if(Data2D==NULL || Offset2D>=Size2D) return;
  Data1D = Data2D[Offset2D];
  ((Raster1DAbstract*)this)->Set(Offset1D,RGB);		//Raster1DAbstract::Set() forces only one method not using VMT.
}


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*)this)->Set(R1);
#endif
}


uint32_t 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)
uint32_t 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, uint32_t 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


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


uint32_t 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, uint32_t x)
{
 if(Data2D==NULL || Offset2D>=Size2D) return;
#if defined(_REENTRANT)
 PTR_SetValue1DRAW(Data2D[Offset2D],Offset1D,x);
#else
 Data1D = Data2D[Offset2D];
 SetValue1DRAW(Offset1D,x);
#endif
}



uint32_t 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, uint32_t 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;
#if defined(uint64_t_defined)
   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);
	}
     }
   }
   //printf("CreateRaster2D |%p|",Raster->Data2D);

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  5:Raster=new Raster2D_16Bit565; break;
   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(Data3D)
 {
   if(NewSize1D==Size1D && NewSize2D==Size2D && NewSize3D==Size3D) return; // No change occurs
   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);
}


uint32_t 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, uint32_t 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;
#if defined(uint64_t_defined)
   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

