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

#ifndef __C4DPAINTER_H
#define __C4DPAINTER_H

#include "c4d_string.h"
#include "c4d_baselist.h"
#include "c4d_basebitmap.h"
#include "operatingsystem.h"

class BaseDocument;

void *SendPainterCommand(LONG command, BaseDocument *doc, PaintTexture *tex, BaseContainer *bc);
	#define PAINTER_SAVETEXTURE					1000 // save textures (if doc -> all doc associated, if -> tex only tex, otherwise all textures)
		#define PAINTER_SAVETEXTURE_FLAGS						1
			#define PAINTER_SAVEBIT_SAVEAS						(1<<0)
			#define PAINTER_SAVEBIT_SAVECOPY					(1<<1)
			#define PAINTER_SAVEBIT_SAVEALLOWWARNING	(1<<2)
			#define PAINTER_SAVEBIT_RENAMEINSCENE			(1<<3)
	#define	PAINTER_BRINGTOFRONT				1001 // brings the bp window to front
	#define PAINTER_LOADTEXTURE					1002 // load texture to BP2
		#define LOADTEXTURE_FILENAME				1		// bc arguments
	#define PAINTER_FORCECLOSETEXTURE		1003 // remove the texture from memory
	#define PAINTER_CLOSETEXTURE				1004 // remove the texture from memory, but ask if texture is unsaved
	#define PAINTER_SAVETEXTURE_DIRECT	1005 // save textures
	#define PAINTER_RELOADTEXTURE				1006 // reload a texture in BP and c4d locklist for renderer!
		#define RELOADTEXTURE_FILENAME			1		// bc arguments
//-------
// new in BP2
//-------

struct TempUVHandle
{
	private:
		TempUVHandle();
		~TempUVHandle();

	public:

		// not allowed to change
		LONG GetMode();
		const Vector* GetPoint();
		const CPolygon* GetPoly();
		BaseSelect* GetPolySel();
		BaseSelect* GetUVPointSel(); // 4*polycnt!!! 0..3 = a,b,c,d
		LONG GetPointCount();
		LONG GetPolyCount();
		BaseObject* GetBaseObject();
		Bool IsEditable();

		// allowed to change
		UVWStruct* GetUVW();

		Bool SetUVW(UVWStruct* uv);
};

TempUVHandle *GetActiveUVSet(BaseDocument* doc, LONG flags);
	#define GETACTIVEUVSET_CHECKENABLING				(1<<0)
	#define GETACTIVEUVSET_UVWS									(1<<1)
	#define GETACTIVEUVSET_POLYS								(1<<2)
	#define GETACTIVEUVSET_POLYSELECTION				(1<<3)
	#define GETACTIVEUVSET_POINTS								(1<<4)
	#define GETACTIVEUVSET_POINTSELECTION				(1<<5)
	#define GETACTIVEUVSET_OBJECT								(1<<6)
	#define GETACTIVEUVSET_MODE									(1<<7)

	#define GETACTIVEUVSET_ALL_CHECKENABLING		(0xFFFF)
	#define GETACTIVEUVSET_ALL									(0xFFFF & ~GETACTIVEUVSET_CHECKENABLING)

void FreeActiveUVSet(TempUVHandle *handle);

//-------

//-------


Bool CallUVCommand(const Vector *padr,LONG PointCount, const CPolygon *polys, LONG lPolyCount, UVWStruct *uvw, BaseSelect *polyselection,
                   BaseSelect* pointselection, BaseObject*op, LONG mode, LONG cmdid, const BaseContainer &settings);
#define UVCOMMAND_OPTIMALMAPPING		10000
#define UVCOMMAND_OPTIMALCUBICMAPPING			10001
#define UVCOMMAND_REALIGN           10002
  #define OPTIMALMAPPING_PRESERVEORIENTATION	1000	// BOOL (c, a, r)
  #define OPTIMALMAPPING_STRETCHTOFIT					1001	// BOOL (c, a, r)
  #define OPTIMALMAPPING_DISTORTION						1002	// REAL (a)
  #define OPTIMALMAPPING_SPACING							1003	// REAL (c, a, r)
  #define OPTIMALMAPPING_AREAFAK							1004  // REAL (c)
  #define OPTIMALMAPPING_TWOD									1005  // BOOL (c)
  #define OPTIMALMAPPING_PROGRESSBAR          1006  // BOOL (c, a, r)
  #define OPTIMALMAPPING_RELAXCOUNT           1007  // LONG (c, a)
#define UVCOMMAND_RELAX               10003
  #define RELAXUV_KEEP_BORDER                 1010  // BOOL
  #define RELAXUV_KEEP_NEIGHBORS              1011  // BOOL
  #define RELAXUV_KEEP_POINTSEL               1012  // BOOL
  #define RELAXUV_CUT_EDGESEL                 1013  // BOOL
  #define RELAXUV_EDGESEL_POINTER             1022  // BaseSelect*
  #define RELAXUV_MAX_ITERATIONS              1014  // LONG
#define UVCOMMAND_COPY_UV           10004
#define UVCOMMAND_PASTE_UV          10005
#define UVCOMMAND_MAX_UV            10006
#define UVCOMMAND_FLIP_SEQUENCE     10007
#define UVCOMMAND_MOVE_DOWN_SEQUENCE  10008
#define UVCOMMAND_MOVE_UP_SEQUENCE    10009
#define UVCOMMAND_TERRACE           10010
#define UVCOMMAND_FIT_TO_CANVAS     10011
#define UVCOMMAND_TRANSFORM         10012
#define UVCOMMAND_LINEUP            10013
#define UVCOMMAND_UNSTITCH          10014
  #define UVCOMMAND_TRANSFORM_MOVE_X          1020 // REAL
  #define UVCOMMAND_TRANSFORM_MOVE_Y          1021 // REAL
  #define UVCOMMAND_TRANSFORM_SCALE_X         1022 // REAL
  #define UVCOMMAND_TRANSFORM_SCALE_Y         1023 // REAL
  #define UVCOMMAND_TRANSFORM_ANGLE           1024 // REAL (Angle in Radians)

//-------

LONG IdentifyImage(const Filename &texpath);
Bool BPSetupWizardWithParameters(BaseDocument *doc, const BaseContainer &settings, AtomArray &objects, AtomArray &material);

struct TextureSize
{
	Real w,h;
};

Bool CalculateTextureSize(BaseDocument *doc, AtomArray &materials, TextureSize *&sizes);

// new for 9.1

// GetType() returns this for bodypaint objects
#define OBJECT_PAINTLAYERBMP						(501)
#define OBJECT_PAINTTEXTURE							(502)
#define OBJECT_PAINTBITMAP							(543) // for use of InstanceOf
#define OBJECT_PAINTLAYER								(544)

#ifndef __API_INTERN__

class PaintBitmap : public BaseList2D
{
	private:
		PaintBitmap();
		~PaintBitmap();

	public:
		LONG GetBw() { return C4DOS.Pa->PB_GetBw(this); }
		LONG GetBh() { return C4DOS.Pa->PB_GetBh(this); }

		PaintTexture *GetPaintTexture() { return C4DOS.Pa->PB_GetPaintTexture(this); }
		PaintBitmap *GetParent()				{ return C4DOS.Pa->PB_GetParent(this); }

		PaintLayer *GetLayerDownFirst() { return C4DOS.Pa->PB_GetLayerDownFirst(this); }
		PaintLayer *GetLayerDownLast()  { return C4DOS.Pa->PB_GetLayerDownLast(this); }

		PaintLayer *GetAlphaFirst()			{ return C4DOS.Pa->PB_GetAlphaFirst(this); }
		PaintLayer *GetAlphaLast()			{ return C4DOS.Pa->PB_GetAlphaLast(this); }

		PaintLayerBmp *AddAlphaChannel(LONG bitdepth,PaintLayer *prev=NULL,Bool undo=TRUE, Bool activate=TRUE) { return C4DOS.Pa->PB_AddAlphaChannel(this,bitdepth,prev,undo,activate); }
		Bool AskApplyAlphaMask()				{ return C4DOS.Pa->PB_AskApplyAlphaMask(this); }
		void ApplyAlphaMask(LONG x,LONG y,LONG cnt,PIX *bits,LONG mode,Bool inverted, LONG flags) { C4DOS.Pa->PB_ApplyAlphaMask(this,x,y,cnt,bits,mode,inverted,flags); }
		
		PaintLayerMask *FindSelectionMask(PaintBitmap **toplevel,LONG *bitdepth) { return C4DOS.Pa->PB_FindSelectionMask(this,toplevel,bitdepth); }

		LONG GetColorMode()	{ return C4DOS.Pa->PB_GetColorMode(this); };
		ULONG GetDirty(LONG flags) { return C4DOS.Pa->PB_GetDirty(this,flags); }

		void UpdateRefresh(LONG xmin,LONG ymin,LONG xmax,LONG ymax,ULONG flags) { C4DOS.Pa->PB_UpdateRefresh(this,xmin,ymin,xmax,ymax,flags); }

		void UpdateRefreshAll(ULONG flags,Bool reallyall) { C4DOS.Pa->PB_UpdateRefreshAll(this,flags,reallyall); }

		Bool ReCalc(BaseThread *thread,LONG x1,LONG y1,LONG x2,LONG y2,BaseBitmap *bmp,LONG flags,ULONG showbit)  { return C4DOS.Pa->PB_ReCalc(this,thread,x1,y1,x2,y2,bmp,flags,showbit); }
			#define RECALC_NOGRID					1
			#define RECALC_INITBMP				2

		// static
		static Bool ConvertBits(LONG cnt,PIX *src,LONG srcinc,LONG srcmode,PIX *dst,LONG dstinc,LONG dstmode,LONG dithery,LONG ditherx) { return C4DOS.Pa->PB_ConvertBits(cnt,src,srcinc,srcmode,dst,dstinc,dstmode,dithery,ditherx); }
};

class PaintLayer : public PaintBitmap
{
	private:
		PaintLayer();
		~PaintLayer();

	public:
};

class PaintLayerMask : public PaintLayer
{
	private:
		PaintLayerMask();
		~PaintLayerMask();

	public:
};

class PaintLayerFolder : public PaintLayer
{
	private:
		PaintLayerFolder();
		~PaintLayerFolder();

	public:
};

// Flags for GetPixelCnt
#define GETPIXEL_ALPHAMASKS					(1<<0) // calculate alpha masks
#define GETPIXEL_USEBLENDING				(1<<1) // calculate transparent value of layer
#define GETPIXEL_ALL								(GETPIXEL_ALPHAMASKS|GETPIXEL_USEBLENDING)
#define GETPIXEL_NOMASK							(1<<2) // calculate no mask
#define GETPIXEL_CACHE							(1<<3) // calculate no mask
#define GETPIXEL_NOWORK							(1<<4) // no work layer
#define GETPIXEL_ONLYWORK						(1<<5) // no work layer
#define GETPIXEL_TILED							(1<<6) // activate tiling
#define GETPIXEL_DONTAPPLYMASK			(1<<7) // do not apply mask on work
#define GETPIXEL_USESELECTED				(1<<8) // calculate no mask
#define GETPIXEL_DITHERING					(1<<9) // use dithering
#define GETPIXEL_PROJECTIONPIXEL		(1<<10) // use special projection paint RGBA color, a kind of hack
#define GETPIXEL_RECALCBRUSHSTROKE	(1<<11) // special flag for brushs stroke
#define GETPIXEL_VOXELCACHING				(1<<12) // use voxel caching
#define GETPIXEL_MERGE							(1<<13) // only merge, no get at collect

class PaintLayerBmp : public PaintLayer
{
	private:
		PaintLayerBmp();
		~PaintLayerBmp();

	public:

		// copies the content of BaseBitmap into the layer
		Bool ImportFromBaseBitmap(BaseBitmap *bmp, Bool usealpha) { return C4DOS.Pa->PLB_ImportFromBaseBitmap(this,bmp,usealpha); }
		Bool ImportFromBaseBitmapAlpha(BaseBitmap *bmp,AlphaBitmap *channel) { return C4DOS.Pa->PLB_ImportFromBaseBitmapAlpha(this,bmp,channel); }

		Bool GetPixelCnt(LONG x,LONG y,LONG cnt,PIX *dst,LONG dstmode,LONG flags) { return C4DOS.Pa->PLB_GetPixelCnt(this,x,y,cnt,dst,dstmode,flags); }
		void SetPixelCnt(LONG x,LONG y,LONG cnt,PIX *src,LONG incsrc,LONG srcmode,LONG flags) { C4DOS.Pa->PLB_SetPixelCnt(this,x,y,cnt,src,incsrc,srcmode,flags); }

		void GetBoundingBox(LONG &x1,LONG &y1,LONG &x2,LONG &y2, Bool hasselectionpixels=FALSE) { C4DOS.Pa->PLB_GetBoundingBox(this,x1,y1,x2,y2,hasselectionpixels); }
};

class PaintTexture : public PaintBitmap
{
	private:
		PaintTexture();
		~PaintTexture();

	public:

		PaintLayer *GetFirstLayer() { return C4DOS.Pa->PB_GetLayerDownFirst(this); }
		PaintLayer *GetLastLayer() { return C4DOS.Pa->PB_GetLayerDownLast(this); }

		// adds a layer to this texture
		PaintLayerBmp			*AddLayerBmp(PaintLayer *insertafter,PaintLayer *layerset=NULL,LONG mode=MODE_RGBA,Bool useundo=TRUE, Bool activate=TRUE) { return C4DOS.Pa->PT_AddLayerBmp(this,insertafter,layerset,mode,useundo,activate); }
		PaintLayerFolder	*AddLayerFolder(PaintLayer *insertafter,PaintLayer *insertunder,Bool useundo=TRUE, Bool activate=TRUE) { return C4DOS.Pa->PT_AddLayerFolder(this,insertafter,insertunder,useundo,activate); }

		void SetActiveLayer(PaintLayer *layer,Bool activatetexture,Bool show=TRUE) { C4DOS.Pa->PT_SetActiveLayer(this,layer,activatetexture,show); }
		PaintLayer *GetActive() { return C4DOS.Pa->PT_GetActive(this); }
		void GetLinkLayers(AtomArray &layers, Bool addfolders) { C4DOS.Pa->PT_GetLinkLayers(this,layers,addfolders); }

		void SetColorMode(LONG newcolormode,Bool doundo) { C4DOS.Pa->PT_SetColorMode(this,newcolormode,doundo); }

		// static functions
		static GeListHead *GetPaintTextureHead() { return C4DOS.Pa->PT_GetPaintTextureHead(); }

		static PaintTexture *CreateNewTexture(const Filename &path, const BaseContainer &settings);
		static Bool GetTextureDefaults(LONG channel,BaseContainer &settings);

		// resolves the painttexture used in a basechannel
		static inline PaintTexture *GetPaintTextureOfBaseChannel(BaseDocument *doc,BaseChannel *bc) { return C4DOS.Pa->GetPaintTextureOfBaseChannel(doc,bc); }

		static Bool SetSelected_Texture(PaintBitmap *bmp, PaintMaterial *preferred) { return C4DOS.Pa->PT_SetSelected_Texture(bmp,preferred); }
		static PaintTexture *GetSelectedTexture() { return C4DOS.Pa->PT_GetSelectedTexture(); }
		static PaintTexture *GetSelectedTexturePP(PaintMaterial **ppmat=NULL) { return C4DOS.Pa->PT_GetSelectedTexturePP(ppmat); }
};

class PaintMaterial : public PaintBitmap
{
	private:
		PaintMaterial();
		~PaintMaterial();

	public:

		void EnableMaterial(BaseDocument *doc,Bool on,Bool suppressevent=FALSE,Bool domaterialundo=TRUE) { C4DOS.Pa->PM_EnableMaterial(this,doc,on,suppressevent,domaterialundo); }

		// static functions
		static PaintMaterial *GetActivePaintMaterial(BaseDocument *doc=NULL,BaseMaterial **mat=NULL) { return C4DOS.Pa->PM_GetActivePaintMaterial(doc,mat); }
		static PaintMaterial *GetPaintMaterialFromTexture(PaintTexture *tex,Bool onlyeditable) { return C4DOS.Pa->PM_GetPaintMaterialFromTexture(tex,onlyeditable); }
		static PaintMaterial *GetPaintMaterial(BaseDocument *doc,BaseMaterial *material,Bool create) { return C4DOS.Pa->PM_GetPaintMaterial(doc,material,create); }
		static Bool UnloadPaintMaterial(BaseDocument *doc,BaseMaterial *material,Bool forcesave) { return C4DOS.Pa->PM_UnloadPaintMaterial(doc,material,forcesave); }
};

#endif

// flags for PaintTexture::CreateNewTexture and PaintTexture::GetTextureDefaults
#define TEXTURE_FILEFORMAT			1000 // LONG
#define TEXTURE_WIDTH						1001 // LONG
#define TEXTURE_HEIGHT					1002 // LONG
#define TEXTURE_MODE						1003 // allowed MODE_GREY8,MODE_RGB,MODE_RGBw,MODE_GREYw,MODE_RGBf,MODE_GREYf
#define TEXTURE_COLOR						1004 // vector
#define TEXTURE_SAVE_IMMEDIATLY	1005 // bool: flag if save immediatly, otherwise it's only created in memory

#define GETALLSTRINGS_FILESTRING			1
#define GETALLSTRINGS_SUGGESTED_PATH	2
#define GETALLSTRINGS_CHANNEL_ID			3
Bool GetAllStrings_AddTexture(const void *msgdata, const BaseContainer &d);

#endif
