/////////////////////////////////////////////////////////////
// CINEMA 4D SDK                                           //
/////////////////////////////////////////////////////////////
// (c) 1989-2004 MAXON Computer GmbH, all rights reserved  //
/////////////////////////////////////////////////////////////

#ifndef __C4DBASEBITMAP_H
#define __C4DBASEBITMAP_H

#include "ge_math.h"
#include "operatingsystem.h"
#include "c4d_gedata.h"
#include "c4d_baseplugin.h"

class BaseContainer;
class Filename;

#define MODE_ALPHA			(1)   // only alpha channel

// number of color info bits
#define BITDEPTH_SHIFT	4

#define PIX_UCHAR(p)		((PIX_C*)(p))
#define BITDEPTH_UCHAR	(0)
#define MODE_GREY8			(2)
#define MODE_GREYA8		  (3)
#define MODE_RGB				(4)
#define MODE_RGBA				(5)
#define MODE_CMYK				(6)
#define MODE_CMYKA			(7)
#define MODE_MASK				(8)  // gray map as mask
#define MODE_MASKA			(9)  // gray map as mask

// 16 bit modes
#define PIX_UWORD(p)		((PIX_W*)(p))
#define BITDEPTH_UWORD	(1)
#define MODE_GREYw			(MODE_GREY8    |(BITDEPTH_UWORD<<BITDEPTH_SHIFT))
#define MODE_GREYAw			(MODE_GREYA8   |(BITDEPTH_UWORD<<BITDEPTH_SHIFT))
#define MODE_RGBw				(MODE_RGB      |(BITDEPTH_UWORD<<BITDEPTH_SHIFT))
#define MODE_RGBAw			(MODE_RGBA     |(BITDEPTH_UWORD<<BITDEPTH_SHIFT))

// 32 bit modes
#define PIX_FLOAT(p)		((PIX_F*)(p))
#define BITDEPTH_FLOAT	(2)
#define MODE_GREYf			(MODE_GREY8    |(BITDEPTH_FLOAT<<BITDEPTH_SHIFT))
#define MODE_GREYAf			(MODE_GREYA8   |(BITDEPTH_FLOAT<<BITDEPTH_SHIFT))
#define MODE_RGBf				(MODE_RGB      |(BITDEPTH_FLOAT<<BITDEPTH_SHIFT))
#define MODE_RGBAf			(MODE_RGBA     |(BITDEPTH_FLOAT<<BITDEPTH_SHIFT))

#define B3D_BITDEPTH(mode)		((mode>>BITDEPTH_SHIFT) & (BITDEPTH_UCHAR|BITDEPTH_UWORD|BITDEPTH_FLOAT))
#define B3D_COLOR_MODE(mode)	(mode & ~((BITDEPTH_UCHAR|BITDEPTH_UWORD|BITDEPTH_FLOAT)<<BITDEPTH_SHIFT))

#define B3D_IS_CHAR(mode)		(B3D_BITDEPTH(mode)==BITDEPTH_UCHAR)
#define B3D_IS_UWORD(mode)	(B3D_BITDEPTH(mode)==BITDEPTH_UWORD)
#define B3D_IS_FLOAT(mode)	(B3D_BITDEPTH(mode)==BITDEPTH_FLOAT)

#define MODE_MAXCOLOR		((1<<6)-1)

#define PIXELCNT_DITHERING								(1<<0)	// allow dithering
#define PIXELCNT_B3DLAYERS								(1<<1)	// merge b3d layers (multipassbmp)
#define PIXELCNT_COLORCORRECTION					(1<<2)	// apply gamma when accessing 32 bit images

class BaseBitmap
{
	private:
		BaseBitmap();
		~BaseBitmap();
	public:
		BaseBitmap *GetClone(void);
		BaseBitmap *GetClonePart(LONG x, LONG y, LONG w, LONG h);
		Bool CopyTo(BaseBitmap *dst);
	
		void FlushAll(void); 
		
		LONG  GetBw (void) {	return C4DOS.Bm->GetBw(this); }
		LONG  GetBh (void) {	return C4DOS.Bm->GetBh(this); }
		LONG  GetBt (void) {	return C4DOS.Bm->GetBt(this); }
		LONG  GetBpz(void) { return C4DOS.Bm->GetBpz(this); }
		LONG  GetColorMode(void);

		LONG  Init(const Filename &name, LONG frame=-1, Bool *ismovie=NULL);
		LONG  Init(LONG x, LONG y, LONG depth=24);
	  LONG  Save(const Filename &name, LONG format, BaseContainer *data, LONG savebits);

		void	GetLine(LONG y, void *data);
		void	SetLine(LONG y, void *data, LONG depth);
		void	SetCMAP(LONG i, LONG r, LONG g, LONG b);

		void  SetPixelCnt(LONG x, LONG y, LONG cnt, UCHAR *buffer, LONG inc, LONG srcmode=MODE_RGB, LONG flags=0) { C4DOS.Bm->SetPixelCnt(this,x,y,cnt,buffer,inc,srcmode,flags); }
		void  GetPixelCnt(LONG x, LONG y, LONG cnt, UCHAR *buffer, LONG inc, LONG dstmode=MODE_RGB, LONG flags=0) { C4DOS.Bm->GetPixelCnt(this,x,y,cnt,buffer,inc,dstmode,flags); }

		void	ScaleIt(BaseBitmap *dst, LONG intens, Bool sample, Bool nprop);
		void	ScaleBicubic(BaseBitmap *dst, LONG src_xmin, LONG src_ymin, LONG src_xmax, LONG src_ymax, LONG dst_xmin, LONG dst_ymin, LONG dst_xmax, LONG dst_ymax);

		void	SetPen(LONG r, LONG g, LONG b) { C4DOS.Bm->SetPen(this,r,g,b); }
		void	Clear(LONG r, LONG g, LONG b);
		void	Clear(LONG x1, LONG y1, LONG x2, LONG y2, LONG r, LONG g, LONG b);
		void	Line(LONG x1, LONG y1, LONG x2, LONG y2) { C4DOS.Bm->Line(this,x1,y1,x2,y2); }
		void	SetPixel(LONG x, LONG y, LONG r, LONG g, LONG b) {	C4DOS.Bm->SetPixel(this,x,y,r,g,b); }
		void	GetPixel(LONG x, LONG y, UWORD *r, UWORD *g, UWORD *b) { C4DOS.Bm->GetPixel(this,x,y,r,g,b); }
		AlphaBitmap *AddChannel(Bool internal, Bool straight);
		void	RemoveChannel(AlphaBitmap *channel);
		void	GetAlphaPixel(AlphaBitmap *channel, LONG x, LONG y, UWORD *val) { C4DOS.Bm->GetAlphaPixel(this,channel,x,y,val); }
		void	SetAlphaPixel(AlphaBitmap *channel, LONG x, LONG y, LONG val) {	C4DOS.Bm->SetAlphaPixel(this,channel,x,y,val); }
		AlphaBitmap *GetInternalChannel(void);
		LONG	GetChannelCount(void);
		AlphaBitmap *GetChannelNum(LONG num);

		Bool IsMultipassBitmap(void);
		Bool SetData(LONG id,const GeData &data);
		GeData GetData(LONG id, const GeData &t_default);
#define BASEBITMAP_DATA_GAMMA					1000
#define BASEBITMAP_DATA_EXPOSURE			1001
#define BASEBITMAP_DATA_TARGETGAMMA		1002

		static BaseBitmap *Alloc(void);
		static void Free(BaseBitmap *&bc);

		ULONG GetDirty() { return C4DOS.Bm->GetDirty(this); }
		void SetDirty() { C4DOS.Bm->SetDirty(this); }
};

class MultipassBitmap : public BaseBitmap
{
	private:
		MultipassBitmap();
		~MultipassBitmap();

	public:
		LONG GetLayerCount() { return C4DOS.Bm->MPB_GetLayerCount(this); }
		LONG GetAlphaLayerCount() { return C4DOS.Bm->MPB_GetAlphaLayerCount(this); }
		LONG GetHiddenLayerCount() { return C4DOS.Bm->MPB_GetHiddenLayerCount(this); }
		MultipassBitmap *GetLayerNum(LONG num) { return C4DOS.Bm->MPB_GetLayerNum(this,num); }
		MultipassBitmap *GetAlphaLayerNum(LONG num) { return C4DOS.Bm->MPB_GetAlphaLayerNum(this,num); }
		MultipassBitmap *GetHiddenLayerNum(LONG num) { return C4DOS.Bm->MPB_GetHiddenLayerNum(this,num); }
		MultipassBitmap *AddLayer(MultipassBitmap *insertafter,LONG colormode,Bool hidden=FALSE) { return C4DOS.Bm->MPB_AddLayer(this,insertafter,colormode,hidden); }
		MultipassBitmap *AddFolder(MultipassBitmap *insertafter,Bool hidden=FALSE) { return C4DOS.Bm->MPB_AddFolder(this,insertafter,hidden); }
		MultipassBitmap *AddAlpha(MultipassBitmap *insertafter,LONG colormode) { return C4DOS.Bm->MPB_AddAlpha(this,insertafter,colormode); }
		Bool DeleteLayer(MultipassBitmap *&layer) { Bool ret=C4DOS.Bm->MPB_DeleteLayer(this,layer); layer=NULL; return ret; }
		MultipassBitmap *FindUserID(LONG id,LONG subid=0) { return C4DOS.Bm->MPB_FindUserID(this,id,subid); }
		void ClearImageData(void) { C4DOS.Bm->MPB_ClearImageData(this); }
		PaintBitmap* GetPaintBitmap() { return C4DOS.Bm->MPB_GetPaintBitmap(this); }

		void SetMasterAlpha(BaseBitmap *master) { C4DOS.Bm->MPB_SetMasterAlpha(this,master); }
		GeData GetParameter(LONG id) { return C4DOS.Bm->MPB_GetParameter(this,id); }
		Bool SetParameter(LONG id,const GeData &par) { return C4DOS.Bm->MPB_SetParameter(this,id,par); }

		static MultipassBitmap *Alloc(LONG bx, LONG by, LONG mode) { return C4DOS.Bm->MPB_AllocWrapperPB(bx,by,mode); }
		static MultipassBitmap *AllocWrapper(BaseBitmap *bmp) { return C4DOS.Bm->MPB_AllocWrapper(bmp); }
		static void Free(MultipassBitmap *&bc);
};

// parameter for Insert...
#define BMP_INSERTLAST ((MultipassBitmap*)-1)

// parameter for Get/SetParameter
#define MPB_SHOW						1000	// Bool, get, set
#define MPB_SAVE						1001	// Bool, get, set
#define MPB_PERCENT					1002	// Real, get, set
#define MPB_BLENDMODE				1003	// LONG, get, set
#define MPB_COLORMODE				1004	// LONG, get, set
#define MPB_BITMAPTYPE			1005	// LONG, get
#define MPB_NAME						1006	// String, get, set
#define MPB_DPI							1007	// LONG, get, set
#define MPB_USERID					1008	// LONG, get, set
#define MPB_USERSUBID				1009	// LONG, get, set


class MovieSaver
{
	private:
		MovieSaver();
		~MovieSaver();
	public:
		LONG Open(const Filename &name, BaseBitmap *bm, LONG fps, LONG format, BaseContainer *data, LONG savebits);
		LONG Write(BaseBitmap *bm);
		void Close(void);
		Bool Choose(LONG format, BaseContainer *bc);

		static MovieSaver *Alloc(void);
		static void Free(MovieSaver *&bc);
};

class PluginMovieData;

class BitmapLoaderPlugin : public BasePlugin
{
	private:
		BitmapLoaderPlugin();
		~BitmapLoaderPlugin();
	public:
		Bool BmIdentify(const Filename &name, UCHAR *probe, LONG size);
		LONG BmLoad(const Filename &name, BaseBitmap *bm, LONG frame);
		LONG BmGetSaver(void);
		Bool BmGetInformation(const Filename &name, LONG *frames, Real *fps);
};

class BitmapSaverPlugin : public BasePlugin
{
	private:
		BitmapSaverPlugin();
		~BitmapSaverPlugin();
	public:
		void BmGetDetails(LONG *alpha, String *suffix);
		Bool BmEdit(BaseContainer *data);
		LONG BmSave(const Filename &name, BaseBitmap *bm, BaseContainer *data, LONG savebits);
		LONG BmOpen(PluginMovieData *&md, const Filename &name, BaseBitmap *bm, BaseContainer *data, LONG savebits, LONG fps);
		LONG BmWrite(PluginMovieData *md, BaseBitmap *bm);
		void BmClose(PluginMovieData *&md);
};

BaseBitmap *InitResourceBitmap(LONG resource_id);

#endif
