/*****************************************************************************/
// Copyright 2006-2008 Adobe Systems Incorporated
// All Rights Reserved.
//
// NOTICE:  Adobe permits you to use, modify, and distribute this file in
// accordance with the terms of the Adobe license agreement accompanying it.
/*****************************************************************************/

/* $Id: //mondo/dng_sdk_1_4/dng_sdk/source/dng_pixel_buffer.h#1 $ */ 
/* $DateTime: 2012/05/30 13:28:51 $ */
/* $Change: 832332 $ */
/* $Author: tknoll $ */

/** \file
 * Support for holding buffers of sample data.
 */

/*****************************************************************************/

#ifndef __dng_pixel_buffer__
#define __dng_pixel_buffer__

/*****************************************************************************/

#include "dng_assertions.h"
#include "dng_rect.h"
#include "dng_safe_arithmetic.h"
#include "dng_tag_types.h"

/*****************************************************************************/

/// Compute best set of step values for a given source and destination area and stride.

void OptimizeOrder (const void *&sPtr,
					void *&dPtr,
					uint32 sPixelSize,
					uint32 dPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &sStep0,
					int32 &sStep1,
					int32 &sStep2,
					int32 &dStep0,
					int32 &dStep1,
					int32 &dStep2);

void OptimizeOrder (const void *&sPtr,
					uint32 sPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &sStep0,
					int32 &sStep1,
					int32 &sStep2);

void OptimizeOrder (void *&dPtr,
					uint32 dPixelSize,
					uint32 &count0,
					uint32 &count1,
					uint32 &count2,
					int32 &dStep0,
					int32 &dStep1,
					int32 &dStep2);

/*****************************************************************************/

#define qDebugPixelType 0

#if qDebugPixelType

#define ASSERT_PIXEL_TYPE(typeVal) CheckPixelType (typeVal)

#else

#define ASSERT_PIXEL_TYPE(typeVal) DNG_ASSERT (fPixelType == typeVal, "Pixel type access mismatch")

#endif

/*****************************************************************************/

/// \brief Holds a buffer of pixel data with "pixel geometry" metadata.
///
/// The pixel geometry describes the layout in terms of how many planes, rows and columns
/// plus the steps (in bytes) between each column, row and plane.

class dng_pixel_buffer
	{
	
	public:
	
		// Area this buffer holds.
	
		dng_rect fArea;
		
		// Range of planes this buffer holds.
		
		uint32 fPlane;
		uint32 fPlanes;
		
		// Steps between pixels.
		
		int32 fRowStep;
		int32 fColStep;
		int32 fPlaneStep;
		
		// Basic pixel type (TIFF tag type code).
	
		uint32 fPixelType;
		
		// Size of pixel type in bytes.
		
		uint32 fPixelSize;
		
		// Pointer to buffer's data.
		
		void *fData;
		
		// Do we have write-access to this data?
		
		bool fDirty;
		
	private:
	
		void * InternalPixel (int32 row,
							  int32 col,
					  	      uint32 plane = 0) const
			{
			
			// Ensure pixel to be accessed lies inside valid area.
			if (row < fArea.t || row >= fArea.b ||
				col < fArea.l || col >= fArea.r ||
				plane < fPlane || (plane - fPlane) >= fPlanes)
				{
				ThrowProgramError ("Out-of-range pixel access");
				}
			
			// Compute offset of pixel.
			const int64 rowOffset = SafeInt64Mult(fRowStep,
				static_cast<int64> (row) - static_cast<int64> (fArea.t));
			const int64 colOffset = SafeInt64Mult(fColStep,
				static_cast<int64> (col) - static_cast<int64> (fArea.l));
			const int64 planeOffset = SafeInt64Mult(fPlaneStep,
				static_cast<int64> (plane - fPlane));
			const int64 offset = SafeInt64Mult(static_cast<int64>(fPixelSize),
				SafeInt64Add(SafeInt64Add(rowOffset, colOffset), planeOffset));
			
			// Add offset to buffer base address.
			return static_cast<void *> (static_cast<uint8 *> (fData) + offset);
			
			}
			
		#if qDebugPixelType
			
		void CheckPixelType (uint32 pixelType) const;
		
		#endif
		
	public:
	
		dng_pixel_buffer ();
		
		/// Note: This constructor is for internal use only and should not be
		/// considered part of the DNG SDK API.
		///
		/// Initialize the pixel buffer according to the given parameters (see
		/// below). May throw an error if arithmetic overflow occurs when
		/// computing the row, column or plane step, or if an invalid value was
		/// passed for planarConfiguration.
		///
		/// \param size Area covered by the pixel buffer
		/// \param plane Index of the first plane
		/// \param planes Number of planes
		/// \param pixelType Pixel data type (one of the values defined in
		///        dng_tag_types.h)
		/// \param planarConfiguration Layout of the pixel planes in memory: One
		///        of pcInterleaved, pcPlanar, or pcRowInterleaved (defined in
		///        dng_tag_values.h)
		/// \param data Pointer to the pixel data
		dng_pixel_buffer (const dng_rect &area, uint32 plane, uint32 planes,
						  uint32 pixelType, uint32 planarConfiguration,
						  void *data);
		
		dng_pixel_buffer (const dng_pixel_buffer &buffer);
		
		dng_pixel_buffer & operator= (const dng_pixel_buffer &buffer);

		virtual ~dng_pixel_buffer ();
		
		/// Get the range of pixel values.
		/// \retval Range of value a pixel can take. (Meaning [0, max] for unsigned case. Signed case is biased so [-32768, max - 32768].)

		uint32 PixelRange () const;

		/// Get extent of pixels in buffer
		/// \retval Rectangle giving valid extent of buffer.

		const dng_rect & Area () const
			{
			return fArea;
			}

		/// Number of planes of image data.
		/// \retval Number of planes held in buffer.

		uint32 Planes () const
			{
			return fPlanes;
			}

		/// Step, in pixels not bytes, between rows of data in buffer.
		/// \retval row step in pixels. May be negative.

		int32 RowStep () const
			{
			return fRowStep;
			}
			
		/// Step, in pixels not bytes, between planes of data in buffer.
		/// \retval plane step in pixels. May be negative.

		int32 PlaneStep () const
			{
			return fPlaneStep;
			}

		/// Get read-only untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as void *.

		const void * ConstPixel (int32 row,
					  			 int32 col,
					  			 uint32 plane = 0) const
			{
			
			return InternalPixel (row, col, plane);
					 
			}
			
		/// Get a writable untyped (void *) pointer to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as void *.

		void * DirtyPixel (int32 row,
					  	   int32 col,
					  	   uint32 plane = 0)
			{
			
			DNG_ASSERT (fDirty, "Dirty access to const pixel buffer");
			
			return InternalPixel (row, col, plane);
			
			}

		/// Get read-only uint8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint8 *.
			
		const uint8 * ConstPixel_uint8 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttByte);

			return (const uint8 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint8 *.

		uint8 * DirtyPixel_uint8 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttByte);

			return (uint8 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int8 *.

		const int8 * ConstPixel_int8 (int32 row,
									  int32 col,
									  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSByte);

			return (const int8 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int8 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int8 *.

		int8 * DirtyPixel_int8 (int32 row,
								int32 col,
								uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSByte);

			return (int8 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only uint16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint16 *.

		const uint16 * ConstPixel_uint16 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttShort);

			return (const uint16 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint16 *.

		uint16 * DirtyPixel_uint16 (int32 row,
								    int32 col,
								    uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttShort);

			return (uint16 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int16 *.

		const int16 * ConstPixel_int16 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSShort);

			return (const int16 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int16 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int16 *.

		int16 * DirtyPixel_int16 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSShort);

			return (int16 *) DirtyPixel (row, col, plane);
			
			}

		/// Get read-only uint32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint32 *.

		const uint32 * ConstPixel_uint32 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttLong);

			return (const uint32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable uint32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as uint32 *.

		uint32 * DirtyPixel_uint32 (int32 row,
								    int32 col,
								    uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttLong);

			return (uint32 *) DirtyPixel (row, col, plane);
			
			}
			
		/// Get read-only int32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int32 *.

		const int32 * ConstPixel_int32 (int32 row,
										int32 col,
										uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttSLong);

			return (const int32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable int32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as int32 *.

		int32 * DirtyPixel_int32 (int32 row,
								  int32 col,
								  uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttSLong);

			return (int32 *) DirtyPixel (row, col, plane);
			
			}

		/// Get read-only real32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real32 *.

		const real32 * ConstPixel_real32 (int32 row,
										  int32 col,
										  uint32 plane = 0) const
			{
			
			ASSERT_PIXEL_TYPE (ttFloat);

			return (const real32 *) ConstPixel (row, col, plane);
			
			}
			
		/// Get a writable real32 * to pixel data starting at a specific pixel in the buffer.
		/// \param row Start row for buffer pointer.
		/// \param col Start column for buffer pointer.
		/// \param plane Start plane for buffer pointer.
		/// \retval Pointer to pixel data as real32 *.

		real32 * DirtyPixel_real32 (int32 row,
									int32 col,
									uint32 plane = 0)
			{
			
			ASSERT_PIXEL_TYPE (ttFloat);

			return (real32 *) DirtyPixel (row, col, plane);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant value to set pixels to.

		void SetConstant (const dng_rect &area,
					      uint32 plane,
					      uint32 planes,
					      uint32 value);
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 8-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint8 value to set pixels to.

		void SetConstant_uint8 (const dng_rect &area,
								uint32 plane,
								uint32 planes,
								uint8 value)
			{
			
			DNG_ASSERT (fPixelType == ttByte, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 16-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint16 value to set pixels to.

		void SetConstant_uint16 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 uint16 value)
			{
			
			DNG_ASSERT (fPixelType == ttShort, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant signed 16-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant int16 value to set pixels to.

		void SetConstant_int16 (const dng_rect &area,
								uint32 plane,
								uint32 planes,
								int16 value)
			{
			
			DNG_ASSERT (fPixelType == ttSShort, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, (uint32) (uint16) value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant unsigned 32-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant uint32 value to set pixels to.

		void SetConstant_uint32 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 uint32 value)
			{
			
			DNG_ASSERT (fPixelType == ttLong, "Mismatched pixel type");
			
			SetConstant (area, plane, planes, value);
			
			}
		
		/// Initialize a rectangular area of pixel buffer to a constant real 32-bit value.
		/// \param area Rectangle of pixel buffer to set.
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.
		/// \param value Constant real32 value to set pixels to.

		void SetConstant_real32 (const dng_rect &area,
								 uint32 plane,
								 uint32 planes,
								 real32 value)
			{
			
			DNG_ASSERT (fPixelType == ttFloat, "Mismatched pixel type");
			
			union
				{
				uint32 i;
				real32 f;
				} x;
				
			x.f = value;
			
			SetConstant (area, plane, planes, x.i);
			
			}

		/// Initialize a rectangular area of pixel buffer to zeros.
		/// \param area Rectangle of pixel buffer to zero.
		/// \param area Area to zero
		/// \param plane Plane to start filling on.
		/// \param planes Number of planes to fill.

		void SetZero (const dng_rect &area,
					  uint32 plane,
					  uint32 planes);
		
		/// Copy image data from an area of one pixel buffer to same area of another.
		/// \param src Buffer to copy from.
		/// \param area Rectangle of pixel buffer to copy.
		/// \param srcPlane Plane to start copy in src.
		/// \param dstPlane Plane to start copy in dst.
		/// \param planes Number of planes to copy.

		void CopyArea (const dng_pixel_buffer &src,
					   const dng_rect &area,
					   uint32 srcPlane,
					   uint32 dstPlane,
					   uint32 planes);
					   
		/// Copy image data from an area of one pixel buffer to same area of another.
		/// \param src Buffer to copy from.
		/// \param area Rectangle of pixel buffer to copy.
		/// \param plane Plane to start copy in src and this.
		/// \param planes Number of planes to copy.

		void CopyArea (const dng_pixel_buffer &src,
					   const dng_rect &area,
					   uint32 plane,
					   uint32 planes)
			{
			
			CopyArea (src, area, plane, plane, planes);
			
			}
					   
		/// Calculate the offset phase of destination rectangle relative to source rectangle.
		/// Phase is based on a 0,0 origin and the notion of repeating srcArea across dstArea.
		/// It is the number of pixels into srcArea to start repeating from when tiling dstArea.
		/// \retval dng_point containing horizontal and vertical phase.

		static dng_point RepeatPhase (const dng_rect &srcArea,
					   			   	  const dng_rect &dstArea);

		/// Repeat the image data in srcArea across dstArea.
		/// (Generally used for padding operations.)
		/// \param srcArea Area to repeat from.
		/// \param dstArea Area to fill with data from srcArea.

		void RepeatArea (const dng_rect &srcArea,
						 const dng_rect &dstArea);
						 
		/// Replicates a sub-area of a buffer to fill the entire buffer.
		
		void RepeatSubArea (const dng_rect subArea,
						    uint32 repeatV = 1,
						    uint32 repeatH = 1);

		/// Apply a right shift (C++ oerpator >>) to all pixel values. Only implemented for 16-bit (signed or unsigned) pixel buffers.
		/// \param shift Number of bits by which to right shift each pixel value.

		void ShiftRight (uint32 shift);
		
		/// Change metadata so pixels are iterated in opposite horizontal order.
		/// This operation does not require movement of actual pixel data.

		void FlipH ();
		
		/// Change metadata so pixels are iterated in opposite vertical order.
		/// This operation does not require movement of actual pixel data.

		void FlipV ();
		
		/// Change metadata so pixels are iterated in opposite plane order.
		/// This operation does not require movement of actual pixel data.

		void FlipZ ();	// Flip planes
		
		/// Return true if the contents of an area of the pixel buffer area are the same as those of another.
		/// \param rhs Buffer to compare against.
		/// \param area Rectangle of pixel buffer to test.
		/// \param plane Plane to start comparing.
		/// \param planes Number of planes to compare.
		/// \retval bool true if areas are equal, false otherwise.

		bool EqualArea (const dng_pixel_buffer &rhs,
					    const dng_rect &area,
					    uint32 plane,
					    uint32 planes) const;

		/// Return the absolute value of the maximum difference between two pixel buffers. Used for comparison testing with tolerance
		/// \param rhs Buffer to compare against.
		/// \param area Rectangle of pixel buffer to test.
		/// \param plane Plane to start comparing.
		/// \param planes Number of planes to compare.
		/// \retval larges absolute value difference between the corresponding pixels each buffer across area.

		real64 MaximumDifference (const dng_pixel_buffer &rhs,
								  const dng_rect &area,
								  uint32 plane,
								  uint32 planes) const;

	};

/*****************************************************************************/

#endif
	
/*****************************************************************************/