/***************************************************************************
 * Unit:    raster            release 0.19                                 *
 * Purpose: Prototypes for general manipulation n dimensional matrices     *
 * Modul:   raster.cc                                                      *
 * Licency: GPL or LGPL                                                    *
 * Copyright: (c) 1998-2020 Jaroslav Fojtik                                *
 ***************************************************************************/
#ifndef __Rasters_h
#define __Rasters_h

#include "typedfs.h"

#define RASTER_VERSION (0x100*0 | 19)

#ifndef No_Memory
 #define No_Memory    0x1
#endif


#ifdef _MSC_VER
 #pragma warning (push)
 #pragma warning (disable: 4250; disable: 4100) 
#endif
#ifdef __GNUC__
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
  #pragma GCC diagnostic push
 #endif
 #pragma GCC diagnostic ignored "-Wunused-parameter"
#endif


#define RASTER_2D_VIRTUALS virtual void Lock2D(unsigned pos2D)	{}; \
                           virtual void UnLock2D(unsigned pos2D) {};


#ifndef RASTER_2D_VIRTUALS
  /** This Macro allows to push extra wirtual methods into RASTER_2D parent. */
  #define RASTER_2D_VIRTUALS
#endif

#ifdef _REENTRANT
  #define MP_CONST const
#else
  #define MP_CONST
#endif


#ifdef __cplusplus
extern "C" {
#endif

void Conv1_8(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv1_16(WORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv1_24(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv1_32(DWORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv4_1(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv4_8(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv4_16(WORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv4_32(DWORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_1(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_4(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_16(WORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_24(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_32(DWORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv16_1(BYTE *Dest, const WORD *Src, unsigned Size1D);
void Conv16_4(BYTE *Dest, const WORD *Src, unsigned Size1D);
void Conv16_8(BYTE *Dest, const WORD *Src, unsigned Size1D);
void Conv16_32(DWORD *Dest, const WORD *Src, unsigned Size1D);
void Conv24_8(BYTE *Dest, const BYTE *Src, unsigned Size1D);
void Conv32_1(BYTE *Dest, const DWORD *Src, unsigned Size1D);
void Conv32_4(BYTE *Dest, const DWORD *Src, unsigned Size1D);
void Conv32_8(BYTE *Dest, const DWORD *Src, unsigned Size1D);
void Conv32_16(WORD *Dest, const DWORD *Src, unsigned Size1D);

#ifdef QWORD
void Conv1_64(QWORD *Dest, const BYTE *Src, unsigned Size1D);
void Conv8_64(QWORD *Dest, const BYTE *Src, unsigned Size1D);
#endif


void Flip4(BYTE *b, unsigned len);
void Flip8(BYTE *b, unsigned len);
void Flip16(WORD *w, unsigned len);
void Flip24(BYTE *b, unsigned len);
void Flip32(DWORD *d, unsigned len);
#ifdef QWORD
void Flip64(QWORD *d, unsigned len);
#endif

#ifdef __cplusplus
}

#ifdef __BORLANDC__
 #include "common.h"
#endif


void AbstractError(const char *Name=NULL);
int NearAvailPlanes(int n);

/** Base class for 1D data. */
class Raster1DAbstract
{
public: mutable short UsageCount;
        bool Shadow;
	unsigned Size1D;
	void *Data1D;

	Raster1DAbstract(void) {Size1D=UsageCount=0;Data1D=NULL;Shadow=false;};
	virtual ~Raster1DAbstract() 		{Erase1DStub();};

	virtual void Allocate1D(unsigned NewSize1D);
	virtual void Erase(void)		{Erase1DStub();};
	virtual void Erase1D(void)		{Erase1DStub();};
	virtual void Cleanup(void);
	void Erase1DStub(void);

	virtual DWORD GetValue1D(unsigned x) const {return(0);};
	virtual double GetValue1Dd(unsigned x) const {return(GetValue1D(x));};
	virtual void SetValue1D(unsigned x, DWORD NewValue) {AbstractError("SetValue1D");};
	virtual void SetValue1Dd(unsigned x, double NewValue) {SetValue1D(x,(DWORD)NewValue);};

	virtual int GetPlanes(void) const {return(0);};
	virtual unsigned GetSize1D(void) const {return(Size1D);};
        virtual char Channels(void) const {return 1;};
	void *GetRow(void)          {return(Data1D);};

/* This set of functions copy internal data in the proper format to the given buffer. */
	virtual void Get(Raster1DAbstract &R1) const;

	virtual void Get24BitRGB(void *Buffer24Bit) const;

/* This set of functions receives given data and stores them to the internal structure. */
	virtual void Set(const Raster1DAbstract &R1);

/* Bitwise operation with raster buffer. */
	virtual void Peel1Bit(void *Buffer1Bit, char plane);
	virtual void Join1Bit(void *Buffer1Bit, char plane);
	virtual void Peel8Bit(BYTE *Buffer8Bit, char plane8);
	virtual void Join8Bit(BYTE *Buffer8Bit, char plane8);

	virtual Raster1DAbstract *GetPalette(void) {return(NULL);}
	virtual void SetPalette(Raster1DAbstract *NewPalette) {AbstractError("SetPalette");}
	friend Raster1DAbstract *CreateRaster1D(unsigned SizeX, int Planes);	

protected:
#ifdef _REENTRANT
        virtual DWORD PTR_GetValue1D(const void *RAW_Data1D, unsigned x) const {return(0);};
	virtual double PTR_GetValue1Dd(const void *RAW_Data1D, unsigned x) const {return(PTR_GetValue1D(RAW_Data1D,x));};
	virtual void PTR_SetValue1D(void *RAW_Data1D, unsigned x, DWORD NewValue) const {AbstractError("RAW_SetValue1D");};
	virtual void PTR_SetValue1Dd(void *RAW_Data1D, unsigned x, double NewValue) const {AbstractError("RAW_SetValue1Dd");};
        virtual void PTR_Get(const void *RAW_Data1D, Raster1DAbstract &R1) const;
        virtual void PTR_Set(void *RAW_Data1D, const Raster1DAbstract &R1);
#endif
};
Raster1DAbstract *CreateRaster1D(unsigned Size1D, int Planes);


class Raster1DAbstractRGB: virtual public Raster1DAbstract
{
public:
  virtual DWORD GetValue1DRAW(unsigned x) const {AbstractError("GetValue1DRAW");return 0;};
  virtual void SetValue1DRAW(unsigned x, DWORD NewValue) {AbstractError("SetValue1DRAW");};

  virtual unsigned GetSize1D(void) const {return(Size1D);};
  virtual char Channels(void) const {return 3;};

  virtual void Set(const Raster1DAbstract &R1);

  unsigned R(unsigned x) const {return(GetValue1DRAW(3*x));}
  unsigned G(unsigned x) const {return(GetValue1DRAW(3*x+1));}
  unsigned B(unsigned x) const {return(GetValue1DRAW(3*x+2));}

  void R(unsigned x, unsigned newR) {SetValue1DRAW(3*x,newR);};
  void G(unsigned x, unsigned newG) {SetValue1DRAW(3*x+1,newG);};
  void B(unsigned x, unsigned newB) {SetValue1DRAW(3*x+2,newB);};

  friend Raster1DAbstractRGB *CreateRaster1DRGB(unsigned SizeX, unsigned Planes);

#ifdef _REENTRANT
protected:
  virtual DWORD PTR_GetValue1DRAW(const void *RAW_Data1D, unsigned x) const {AbstractError("PTR_GetValue1DRAW");return 0;};
  virtual void PTR_SetValue1DRAW(void *RAW_Data1D, unsigned x, DWORD NewValue) {AbstractError("PTR_SetValue1DRAW");};
#endif
};
Raster1DAbstractRGB *CreateRaster1DRGB(unsigned Size1D, int Planes);


class Raster1DAbstractRGBA: virtual public Raster1DAbstract
{
public:
  virtual DWORD GetValue1DRAW(unsigned x) const {AbstractError("GetValue1DRAW");return 0;};
  virtual void SetValue1DRAW(unsigned x, DWORD NewValue) {AbstractError("SetValue1DRAW");};

  virtual unsigned GetSize1D(void) const {return(Size1D);};
  virtual char Channels(void) const {return 4;};

  virtual void Set(const Raster1DAbstract &R1);

  unsigned R(unsigned x) const {return(GetValue1DRAW(4*x));}
  unsigned G(unsigned x) const {return(GetValue1DRAW(4*x+1));}
  unsigned B(unsigned x) const {return(GetValue1DRAW(4*x+2));}
  unsigned A(unsigned x) const {return(GetValue1DRAW(4*x+3));}

  void R(unsigned x, unsigned newR) {SetValue1DRAW(4*x,newR);};
  void G(unsigned x, unsigned newG) {SetValue1DRAW(4*x+1,newG);};
  void B(unsigned x, unsigned newB) {SetValue1DRAW(4*x+2,newB);};
  void A(unsigned x, unsigned newA) {SetValue1DRAW(4*x+3,newA);};

  friend Raster1DAbstractRGBA *CreateRaster1DRGBA(unsigned Size1D, int Planes);

#ifdef _REENTRANT
protected:
  virtual DWORD PTR_GetValue1DRAW(const void *RAW_Data1D, unsigned x) const {AbstractError("PTR_GetValue1DRAW");return 0;};
  virtual void PTR_SetValue1DRAW(void *RAW_Data1D, unsigned x, DWORD NewValue) {AbstractError("PTR_SetValue1DRAW");};
#endif
};


class Raster2DAbstract: virtual public Raster1DAbstract
{
public: unsigned Size2D;
	void **Data2D;

	Raster2DAbstract(void) {Size2D=0;Data2D=NULL;}
	virtual ~Raster2DAbstract() 			{Erase2DStub();}

	virtual void Allocate2D(unsigned NewSize1D, unsigned NewSize2D);
	virtual void Erase(void)			{Erase2DStub();}
	virtual void Erase2D(void)			{Erase2DStub();}
	virtual void Cleanup(void);
        unsigned GetSize2D(void) const {return(Size2D);};

	DWORD GetValue2D(unsigned Offset1D, unsigned Offset2D) MP_CONST;
	double GetValue2Dd(unsigned Offset1D, unsigned Offset2D) MP_CONST;
	void SetValue2D(unsigned Offset1D, unsigned Offset2D, long x);
	void SetValue2Dd(unsigned Offset1D, unsigned Offset2D, double x);

	void *GetRow(unsigned Offset2D)   {if(Data2D==NULL || Offset2D>=Size2D) return(NULL);return(Data2D[Offset2D]);}
        const void *GetRow(unsigned Offset2D) const {if(Data2D==NULL || Offset2D>=Size2D) return(NULL);return(Data2D[Offset2D]);}

	Raster1DAbstract *GetRowRaster(unsigned Offset2D);

        void Get(unsigned Offset2D, Raster1DAbstract &R1) MP_CONST;
        void Set(unsigned Offset2D, const Raster1DAbstract &R1);

	friend Raster2DAbstract *CreateRaster2D(unsigned Size1D, unsigned Size2D, int Planes);

        RASTER_2D_VIRTUALS        

protected:
	void Erase2DStub(void);

#if defined(_REENTRANT) && defined(RASTER_3D)
        DWORD PTR_GetValue2D(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const;
	double PTR_GetValue2Dd(const void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D) const;
	void PTR_SetValue2D(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, DWORD NewValue) const;
	void PTR_SetValue2Dd(void **RAW_Data2D, unsigned Offset1D, unsigned Offset2D, double NewValue) const;
        void PTR_Get(const void **RAW_Data2D, unsigned Offset2D, Raster1DAbstract &R1) const;
        void PTR_Set(void **RAW_Data2D, unsigned Offset2D, const Raster1DAbstract &R1);
#endif
};

Raster2DAbstract *CreateRaster2D(unsigned Size1D, unsigned Size2D, int Planes);


/// 2D raster with RGB data interpretation and 8bits per channel.
class Raster2DAbstractRGB: virtual public Raster2DAbstract, virtual public Raster1DAbstractRGB
{
public:
	virtual DWORD GetValue2DRAW(unsigned Offset1D, unsigned Offset2D);
	virtual void SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x);

	unsigned R(unsigned x, unsigned y) {return(GetValue2DRAW(3*x,y));}
	unsigned G(unsigned x, unsigned y) {return(GetValue2DRAW(3*x+1,y));}
	unsigned B(unsigned x, unsigned y) {return(GetValue2DRAW(3*x+2,y));}

	void R(unsigned x, unsigned y, unsigned newR) {SetValue2DRAW(3*x,y,newR);};
	void G(unsigned x, unsigned y, unsigned newG) {SetValue2DRAW(3*x+1,y,newG);};
	void B(unsigned x, unsigned y, unsigned newB) {SetValue2DRAW(3*x+2,y,newB);};

	friend Raster2DAbstractRGB *CreateRaster2DRGB(unsigned SizeX, unsigned SizeY, int Planes);
};

Raster2DAbstractRGB *CreateRaster2DRGB(unsigned Size1D, unsigned Size2D, int Planes);


class Raster2DAbstractRGBA: virtual public Raster2DAbstract, virtual public Raster1DAbstractRGBA
{
public:
	virtual DWORD GetValue2DRAW(unsigned Offset1D, unsigned Offset2D);
	virtual void SetValue2DRAW(unsigned Offset1D, unsigned Offset2D, DWORD x);

	unsigned R(unsigned x, unsigned y) {return(GetValue2DRAW(4*x,y));}
	unsigned G(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+1,y));}
	unsigned B(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+2,y));}
	unsigned A(unsigned x, unsigned y) {return(GetValue2DRAW(4*x+3,y));}

	void R(unsigned x, unsigned y, unsigned newR) {SetValue2DRAW(4*x,y,newR);};
	void G(unsigned x, unsigned y, unsigned newG) {SetValue2DRAW(4*x+1,y,newG);};
	void B(unsigned x, unsigned y, unsigned newB) {SetValue2DRAW(4*x+2,y,newB);};
	void A(unsigned x, unsigned y, unsigned newA) {SetValue2DRAW(4*x+3,y,newA);};

	friend Raster2DAbstractRGBA *CreateRaster2DRGBA(unsigned SizeX, unsigned SizeY, int Planes);
};

Raster2DAbstractRGBA *CreateRaster2DRGBA(unsigned Size1D, unsigned Size2D, int Planes);




class Raster2DColorAbstract: public Raster1DAbstract
{
public: Raster1DAbstract *palette;

	virtual Raster1DAbstract *GetPalette(void) {return(palette);}
	virtual void SetPalette(Raster1DAbstract *NewPalette) {if(palette!=NULL) delete(palette); palette=NewPalette;}
};


#ifdef RASTER_3D
class Raster3DAbstract: virtual public Raster2DAbstract
	{
public: unsigned Size3D;
	void ***Data3D;

	Raster3DAbstract(void) {Size3D=0;Data3D=NULL;}
	virtual ~Raster3DAbstract() 			{Erase3DStub();}

	virtual void Allocate3D(unsigned NewSize1D, unsigned NewSize2D, unsigned NewSize3D);
	virtual void Erase(void)			{Erase3DStub();}
	virtual void Erase3D(void)			{Erase3DStub();}
        virtual void Cleanup(void);
        unsigned GetSize3D(void) const {return(Size3D);};

	DWORD GetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D) MP_CONST;
        double GetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D) MP_CONST;
	void SetValue3D(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, DWORD x);
        void SetValue3Dd(unsigned Offset1D, unsigned Offset2D, unsigned Offset3D, double x);

	void **GetRow(unsigned Offset3D)   {if(Data3D==NULL || Offset3D>=Size3D) return(NULL);return(Data3D[Offset3D]);}

        void Get(unsigned Offset2D, unsigned Offset3D, Raster1DAbstract &R1) MP_CONST;
        void Set(unsigned Offset2D, unsigned Offset3D, const Raster1DAbstract &R1);

        Raster1DAbstract *GetRowRaster(unsigned Offset2D, unsigned Offset3D);
	Raster2DAbstract *GetRowRaster(unsigned Offset3D);

        void *GetRow(unsigned Offset2D, unsigned Offset3D)   {if(Data3D==NULL || Offset3D>=Size3D) return(NULL);return(Data3D[Offset3D][Offset2D]);}
        const void *GetRow(unsigned Offset2D, unsigned Offset3D) const {if(Data3D==NULL || Offset3D>=Size3D) return(NULL);return(Data3D[Offset3D][Offset2D]);}

	void Erase3DStub(void);

        virtual Raster3DAbstract *CreateShadow(void);
	friend Raster3DAbstract *CreateRaster3D(unsigned Size1D, unsigned Size2D, unsigned Size3D, int Planes);
	};
Raster3DAbstract *CreateRaster3D(unsigned Size1D, unsigned Size2D, unsigned Size3D, int Planes);

void Flip1D(Raster3DAbstract *r3D);
void Flip2D(Raster3DAbstract *r3D);
void Flip3D(Raster3DAbstract *r3D);
#endif

/* ---------- Global class Image --------- */

/*Definition of errors while Loading/Saving File(s)*/
#define ErrOK		  0
#define ErrOpenFile	 -1
#define ErrReadFile	 -2
#define ErrWriteFile	 -3
#define ErrBadFileFormat -4

#define ErrNoMem	-10



#ifndef RGBQuad_DEFINED
#define RGBQuad_DEFINED
typedef struct
	{
	unsigned R,G,B,O;
	} RGBQuad;
#endif


struct RGB_Record
   {
   BYTE Red;
   BYTE Green;
   BYTE Blue;
   };



class APalette: virtual public Raster1DAbstractRGB
	{
public: virtual void Get(unsigned index, RGBQuad *RGB);
	friend APalette *BuildPalette(unsigned Indices, char type);
	};
APalette *BuildPalette(unsigned Indices, char type=0);


typedef enum
{
  ImageNone = 0,	 //-none,
  ImageGray = 0x100,	 //1-gray,
  ImagePalette = 0x200,	 //2-palette,
  ImageTrueColor = 0x300, //3-true color - RGB
  ImagePaletteF=0x2000,	 //there is used abundant palette
  ImageReal =   0x4000,  //Real numbers are used
  ImageSigned = 0x8000	 //image uses signed numbers
} IMAGE_TYPE;


typedef enum
{
  EPS_DrawElipse =   1,
  EPS_colorimage =   2,
  EPS_rlecmapimage = 4,
  EPS_accentshow  =  8,
  EPS_ACCENTSHOW  = 16,
} EPS_COMPONENTS;


class VectorImage;

class Image
	{
public: Raster2DAbstract *Raster;
	APalette *Palette;
	Image *Next;
	float x,y,dx,dy,RotAngle;
	VectorImage *VecImage;

	Image(void): VecImage(NULL)  {RotAngle=x=y=dx=dy=0;Raster=NULL;Next=NULL;Palette=NULL;};
	Image(const Image & I, bool AllFrames=true);
	Image(Raster2DAbstract *NewRaster): VecImage(NULL) {RotAngle=x=y=dx=dy=0;Next=NULL;Palette=NULL;if((Raster=NewRaster)!=NULL) Raster->UsageCount++;};
	~Image(void) {Erase();};
	IMAGE_TYPE ImageType(void) const;   // 0-none, 1-gray, 2-palette, 3-true color

	Raster2DAbstract *operator=(Raster2DAbstract *NewRaster);
	Image &operator=(const Image & I);

	DWORD GetPixel(unsigned Offset1D, unsigned Offset2D) const {return(Raster==NULL?0:Raster->GetValue2D(Offset1D,Offset2D));};
	DWORD GetPixelRGB(unsigned Offset1D, unsigned Offset2D) const;
	
	void SetPixel(unsigned SizeX, unsigned SizeY, DWORD x) {if(Raster) Raster->SetValue2D(SizeX,SizeY,x);};

	void Create(unsigned SizeX, unsigned SizeY, int Planes);
	void Erase(void);
	void AttachRaster(Raster2DAbstract *NewRaster);
        void AttachPalette(APalette *NewPalette);
        void AttachVecImg(VectorImage *NewVecImg);
	};


void Flip1D(Raster1DAbstract *r1D);

void Flip1D(Raster2DAbstract *r2D);
void Flip2D(Raster2DAbstract *r2D);
int ReducePalette(Image *Img, unsigned maxColors);
int GrayPalette(Raster1DAbstractRGB *Palette,int Planes=0);
int FillGray(Raster1DAbstractRGB *Palette,int Planes);


typedef struct
{
  float MinX;
  float MaxX;
  float MinY;
  float MaxY;
} FloatBBox;

void UpdateBBox(FloatBBox & bbx,
		float alpha, float x, float y, float dx, float dy);


/* -----File format loader dynamical list------ */
typedef Image (* TLoadPicture)(const char *Name);
typedef int (*TSavePicture)(const char *Name, const Image &Img);

class TImageFileHandler
	{
private:static TImageFileHandler *First;
	TImageFileHandler *Previous;
	TImageFileHandler *Next;

	const char *Extension;
        const char *Description;

public: TImageFileHandler(const char *NewShortKey, TLoadPicture LoadPicture_XXX = NULL, TSavePicture SavePicture_XXX=NULL, const char *NewDescription=NULL);
	~TImageFileHandler();

	TLoadPicture LoadPicture;
	TSavePicture SavePicture;
	const char *extension() {return(Extension);}
	const char *description() {return(Description);}

	static TImageFileHandler *first() {return(First);}
	TImageFileHandler *next() {return(Next);}
	};

int SavePicture(const char *Name,const Image &Img);
Image LoadPicture(const char *Name);

#endif // C++


#ifdef __GNUC__
 #if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
  #pragma GCC diagnostic pop
 #endif
#endif
#ifdef _MSC_VER 
 #pragma warning (pop)
#endif
#endif //__Rasters_h
