/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2014 Raytrix GmbH. All rights reserved.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma once

#include <cstdint>
#include "Rx.Interop.Runtime28/RxImageTypes.h"

// Define CUDA macros if compiled with CUDA compiler
#ifdef __CUDACC__
    #ifndef RX_CUDA_EXP
		#define RX_CUDA_EXP __host__ __device__ __forceinline__
    #endif
#else
    #ifndef RX_CUDA_EXP
		#define RX_CUDA_EXP
    #endif
#endif

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// namespace: Rx
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Rx
{
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	/// <summary>
	/// 	General pixel template structure.
	///
	/// 	This structure allows the definition of all possible pixel types in such a way, that template functions working on
	/// 	different image types can be written.
	/// </summary>
	/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
	template<class TDataType, unsigned int tuColorCnt, unsigned int tuAlphaCnt, int tiR, int tiG, int tiB, int tiA, int tiPT, int tiDT>
	struct TPixel
	{
		typedef TDataType TType;

		static const int iPixelType = tiPT;
		static const int iDataType  = tiDT;

		static const unsigned uColorCnt = tuColorCnt;
		static const unsigned uAlphaCnt = tuAlphaCnt;
		static const unsigned uCompoCnt = tuAlphaCnt + tuColorCnt;

		static const int iRedIdx   = tiR;
		static const int iGreenIdx = tiG;
		static const int iBlueIdx  = tiB;
		static const int iAlphaIdx = tiA;

		static const unsigned uSize      = (tuColorCnt + tuAlphaCnt) * sizeof(TDataType);
		static const unsigned uColorSize = tuColorCnt * sizeof(TDataType);
		static const unsigned uAlphaSize = tuAlphaCnt * sizeof(TDataType);

		TDataType value[uCompoCnt];

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		///    Default constructor.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		RX_CUDA_EXP TPixel()
		{
			// This constructor is empty to use it in CUDA
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>	Assignment operator. </summary>
		///
		/// <param name="rPix">	The pix. </param>
		///
		/// <returns>	A shallow copy of this object. </returns>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		RX_CUDA_EXP TPixel<TDataType, tuColorCnt, tuAlphaCnt, tiR, tiG, tiB, tiA, tiPT, tiDT>& operator=(const TPixel<TDataType, tuColorCnt, tuAlphaCnt, tiR, tiG, tiB, tiA,
															      tiPT, tiDT>& rPix)
		{
			for (int i = 0; i < tuColorCnt + tuAlphaCnt; ++i)
			{
				value[i] = rPix.value[i];
			}

			return *this;
		}

		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		/// <summary>
		/// 	Clears this object to its blank/initial state.
		/// </summary>
		/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
		RX_CUDA_EXP void Clear()
		{
			for (int i = 0; i < tuColorCnt + tuAlphaCnt; ++i)
			{
				value[i] = TDataType(0);
			}
		}

		RX_CUDA_EXP static bool IsOfType(int _iPixelType, int _iDataType)
		{
			return iPixelType == _iPixelType && iDataType == _iDataType;
		}

		RX_CUDA_EXP static bool IsOfType(Interop::Runtime28::EPixelType::ID _ePixelType, Interop::Runtime28::EDataType::ID _eDataType)
		{
			return iPixelType == int(_ePixelType) && iDataType == int(_eDataType);
		}

		RX_CUDA_EXP TDataType& r()
		{
			return value[tiR];
		}

		RX_CUDA_EXP TDataType& g()
		{
			return value[tiG];
		}

		RX_CUDA_EXP TDataType& b()
		{
			return value[tiB];
		}

		RX_CUDA_EXP TDataType& a()
		{
			return value[tiA];
		}

		RX_CUDA_EXP const TDataType& r() const
		{
			return value[tiR];
		}

		RX_CUDA_EXP const TDataType& g() const
		{
			return value[tiG];
		}

		RX_CUDA_EXP const TDataType& b() const
		{
			return value[tiB];
		}

		RX_CUDA_EXP const TDataType& a() const
		{
			return value[tiA];
		}
	};

	/////////////////////////////////////////////////////////////////
	// Specific pixel definitions
	typedef TPixel<char, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_BYTE> TPixel_RGBA_c;
	typedef TPixel<char, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_BYTE> TPixel_BGRA_c;
	typedef TPixel<char, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_BYTE> TPixel_RGB_c;
	typedef TPixel<char, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_BYTE> TPixel_BGR_c;
	typedef TPixel<char, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_BYTE> TPixel_L_c;
	typedef TPixel<char, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_BYTE> TPixel_LA_c;
	typedef TPixel<char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_BYTE> TPixel_Bay_BG_c;
	typedef TPixel<char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_BYTE> TPixel_Bay_GB_c;
	typedef TPixel<char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_BYTE> TPixel_Bay_GR_c;
	typedef TPixel<char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_BYTE> TPixel_Bay_RG_c;

	typedef TPixel<unsigned char, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_UNSIGNED_BYTE> TPixel_RGBA_uc;
	typedef TPixel<unsigned char, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_UNSIGNED_BYTE> TPixel_BGRA_uc;
	typedef TPixel<unsigned char, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_UNSIGNED_BYTE> TPixel_RGB_uc;
	typedef TPixel<unsigned char, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_UNSIGNED_BYTE> TPixel_BGR_uc;
	typedef TPixel<unsigned char, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_UNSIGNED_BYTE> TPixel_L_uc;
	typedef TPixel<unsigned char, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_UNSIGNED_BYTE> TPixel_LA_uc;
	typedef TPixel<unsigned char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_UNSIGNED_BYTE> TPixel_Bay_BG_uc;
	typedef TPixel<unsigned char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_UNSIGNED_BYTE> TPixel_Bay_GB_uc;
	typedef TPixel<unsigned char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_UNSIGNED_BYTE> TPixel_Bay_GR_uc;
	typedef TPixel<unsigned char, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_UNSIGNED_BYTE> TPixel_Bay_RG_uc;

	typedef TPixel<int16_t, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_SHORT> TPixel_RGBA_s;
	typedef TPixel<int16_t, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_SHORT> TPixel_BGRA_s;
	typedef TPixel<int16_t, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_SHORT> TPixel_RGB_s;
	typedef TPixel<int16_t, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_SHORT> TPixel_BGR_s;
	typedef TPixel<int16_t, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_SHORT> TPixel_L_s;
	typedef TPixel<int16_t, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_SHORT> TPixel_LA_s;
	typedef TPixel<int16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_SHORT> TPixel_Bay_BG_s;
	typedef TPixel<int16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_SHORT> TPixel_Bay_GB_s;
	typedef TPixel<int16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_SHORT> TPixel_Bay_GR_s;
	typedef TPixel<int16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_SHORT> TPixel_Bay_RG_s;

	typedef TPixel<uint16_t, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_UNSIGNED_SHORT> TPixel_RGBA_us;
	typedef TPixel<uint16_t, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_UNSIGNED_SHORT> TPixel_BGRA_us;
	typedef TPixel<uint16_t, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_UNSIGNED_SHORT> TPixel_RGB_us;
	typedef TPixel<uint16_t, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_UNSIGNED_SHORT> TPixel_BGR_us;
	typedef TPixel<uint16_t, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_UNSIGNED_SHORT> TPixel_L_us;
	typedef TPixel<uint16_t, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_UNSIGNED_SHORT> TPixel_LA_us;
	typedef TPixel<uint16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_UNSIGNED_SHORT> TPixel_Bay_BG_us;
	typedef TPixel<uint16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_UNSIGNED_SHORT> TPixel_Bay_GB_us;
	typedef TPixel<uint16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_UNSIGNED_SHORT> TPixel_Bay_GR_us;
	typedef TPixel<uint16_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_UNSIGNED_SHORT> TPixel_Bay_RG_us;

	typedef TPixel<int32_t, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_INT> TPixel_RGBA_i;
	typedef TPixel<int32_t, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_INT> TPixel_BGRA_i;
	typedef TPixel<int32_t, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_INT> TPixel_RGB_i;
	typedef TPixel<int32_t, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_INT> TPixel_BGR_i;
	typedef TPixel<int32_t, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_INT> TPixel_L_i;
	typedef TPixel<int32_t, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_INT> TPixel_LA_i;
	typedef TPixel<int32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_INT> TPixel_Bay_BG_i;
	typedef TPixel<int32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_INT> TPixel_Bay_GB_i;
	typedef TPixel<int32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_INT> TPixel_Bay_GR_i;
	typedef TPixel<int32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_INT> TPixel_Bay_RG_i;

	typedef TPixel<uint32_t, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_UNSIGNED_INT> TPixel_RGBA_ui;
	typedef TPixel<uint32_t, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_UNSIGNED_INT> TPixel_BGRA_ui;
	typedef TPixel<uint32_t, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_UNSIGNED_INT> TPixel_RGB_ui;
	typedef TPixel<uint32_t, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_UNSIGNED_INT> TPixel_BGR_ui;
	typedef TPixel<uint32_t, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_UNSIGNED_INT> TPixel_L_ui;
	typedef TPixel<uint32_t, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_UNSIGNED_INT> TPixel_LA_ui;
	typedef TPixel<uint32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_UNSIGNED_INT> TPixel_Bay_BG_ui;
	typedef TPixel<uint32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_UNSIGNED_INT> TPixel_Bay_GB_ui;
	typedef TPixel<uint32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_UNSIGNED_INT> TPixel_Bay_GR_ui;
	typedef TPixel<uint32_t, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_UNSIGNED_INT> TPixel_Bay_RG_ui;

	typedef TPixel<float, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_FLOAT> TPixel_RGBA_f;
	typedef TPixel<float, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_FLOAT> TPixel_BGRA_f;
	typedef TPixel<float, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_FLOAT> TPixel_RGB_f;
	typedef TPixel<float, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_FLOAT> TPixel_BGR_f;
	typedef TPixel<float, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_FLOAT> TPixel_L_f;
	typedef TPixel<float, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_FLOAT> TPixel_LA_f;
	typedef TPixel<float, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_FLOAT> TPixel_Bay_BG_f;
	typedef TPixel<float, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_FLOAT> TPixel_Bay_GB_f;
	typedef TPixel<float, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_FLOAT> TPixel_Bay_GR_f;
	typedef TPixel<float, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_FLOAT> TPixel_Bay_RG_f;

	typedef TPixel<double, 3, 1, 0, 1, 2, 3, RX_IMG_RGBA, RX_IMG_DOUBLE> TPixel_RGBA_d;
	typedef TPixel<double, 3, 1, 2, 1, 0, 3, RX_IMG_BGRA, RX_IMG_DOUBLE> TPixel_BGRA_d;
	typedef TPixel<double, 3, 0, 0, 1, 2, 0, RX_IMG_RGB, RX_IMG_DOUBLE> TPixel_RGB_d;
	typedef TPixel<double, 3, 0, 2, 1, 0, 0, RX_IMG_BGR, RX_IMG_DOUBLE> TPixel_BGR_d;
	typedef TPixel<double, 1, 0, 0, 0, 0, 0, RX_IMG_LUMINANCE, RX_IMG_DOUBLE> TPixel_L_d;
	typedef TPixel<double, 1, 1, 0, 0, 0, 1, RX_IMG_LUMINANCE_ALPHA, RX_IMG_DOUBLE> TPixel_LA_d;
	typedef TPixel<double, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_BG, RX_IMG_DOUBLE> TPixel_Bay_BG_d;
	typedef TPixel<double, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GB, RX_IMG_DOUBLE> TPixel_Bay_GB_d;
	typedef TPixel<double, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_GR, RX_IMG_DOUBLE> TPixel_Bay_GR_d;
	typedef TPixel<double, 1, 0, 0, 0, 0, 0, RX_IMG_BAYER_RG, RX_IMG_DOUBLE> TPixel_Bay_RG_d;
}
