
// ImageComposingCallback

// Declares the cImageComposingCallback class that implements a subset of cCallback for composing per-region images





#pragma once

#include "Callback.h"




/** Implements the plumbing for composing per-region images from multiple chunks.
To use this class, create a descendant that writes the image data using
SetPixel() or SetPixelURow() functions.

For the purpose of this class the image data is indexed U (horz) * V (vert), to avoid confusion with other coords.
The image is a 32bpp raw imagedata, written into a BMP file.
*/
class cImageComposingCallback :
	public cCallback
{
public:
	enum
	{
		INVALID_REGION_COORD = 99999,  ///< Used for un-assigned region coords
		IMAGE_WIDTH = 32 * 16,
		IMAGE_HEIGHT = 32 * 16,
		PIXEL_COUNT = IMAGE_WIDTH * IMAGE_HEIGHT,  ///< Total pixel count of the image data
	} ;
	
	cImageComposingCallback(const AString & a_FileNamePrefix);
	virtual ~cImageComposingCallback();

	// cCallback overrides:
	virtual bool OnNewRegion(int a_RegionX, int a_RegionZ) override;
	virtual void OnRegionFinished(int a_RegionX, int a_RegionZ) override;
	
	// New introduced overridable functions:
	
	/// Called when a file is about to be saved, to generate the filename
	virtual AString GetFileName(int a_RegionX, int a_RegionZ);
	
	/// Called before the file is saved
	virtual void OnBeforeImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
	
	/// Called after the image is saved to a file
	virtual void OnAfterImageSaved(int a_RegionX, int a_RegionZ, const AString & a_FileName) {}
	
	/// Called when a new region is beginning, to erase the image data
	virtual void OnEraseImage(void);
	
	// Functions for manipulating the image:
	
	/// Erases the entire image with the specified color
	void EraseImage(int a_Color);
	
	/// Erases the specified chunk's portion of the image with the specified color. Note that chunk coords are relative to the current region
	void EraseChunk(int a_Color, int a_RelChunkX, int a_RelChunkZ);
	
	/// Returns the current region X coord
	int GetCurrentRegionX(void) const { return m_CurrentRegionX; }
	
	/// Returns the current region Z coord
	int GetCurrentRegionZ(void) const { return m_CurrentRegionZ; }
	
	/// Sets the pixel at the specified UV coords to the specified color
	void SetPixel(int a_RelU, int a_RelV, int a_Color);
	
	/// Returns the color of the pixel at the specified UV coords; -1 if outside
	int GetPixel(int a_RelU, int a_RelV);
	
	/// Sets a row of pixels. a_Pixels is expected to be a_CountU pixels wide. a_RelUStart + a_CountU is assumed less than image width
	void SetPixelURow(int a_RelUStart, int a_RelV, int a_CountU, int * a_Pixels);
	
	/** "Shades" the given color based on the shade amount given
	Shade amount 0 .. 63 shades the color from black to a_Color.
	Shade amount 64 .. 127 shades the color from a_Color to white.
	All other shade amounts have undefined results.
	*/
	static int ShadeColor(int a_Color, int a_Shade);
	
	/// Mixes the two colors in the specified ratio; a_Ratio is between 0 and 256, 0 returning a_Src
	static int MixColor(int a_Src, int a_Dest, int a_Ratio);
	
protected:
	/// Prefix for the filenames, when generated by the default GetFileName() function
	AString m_FileNamePrefix;
	
	/// Coords of the currently processed region
	int m_CurrentRegionX, m_CurrentRegionZ;
	
	/// Raw image data; 1 MiB worth of data, therefore unsuitable for stack allocation. [u + IMAGE_WIDTH * v]
	int * m_ImageData;
	
	void SaveImage(const AString & a_FileName);
} ;




