/*
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "DataFormat.hpp"

#import <Metal/MTLPixelFormat.h>

namespace OpenVulkano
{
	DataFormat DataFormat::GetFromMetalPixelFormat(int formatId)
	{
		switch(formatId)
		{
			case MTLPixelFormatA8Unorm: // 1
				// Unavailable -> map to R8_UNORM
			case MTLPixelFormatR8Unorm: // 10
				return DataFormat::R8_UNORM;
			case MTLPixelFormatR8Unorm_sRGB: // 11
				return DataFormat::R8_SRGB;
			case MTLPixelFormatR8Snorm: // 12
				return DataFormat::R8_SNORM;
			case MTLPixelFormatR8Uint: // 13
				return DataFormat::R8_UINT;
			case MTLPixelFormatR8Sint: // 14
				return DataFormat::R8_SINT;

			/* Normal 16 bit formats */
			case MTLPixelFormatR16Unorm: // 20
				return DataFormat::R16_UNORM;
			case MTLPixelFormatR16Snorm: // 22
				return DataFormat::R16_SNORM;
			case MTLPixelFormatR16Uint: // 23
				return DataFormat::R16_UINT;
			case MTLPixelFormatR16Sint: // 24
				return DataFormat::R16_SINT;
			case MTLPixelFormatR16Float: // 25
				return DataFormat::R16_SFLOAT;

			case MTLPixelFormatRG8Unorm: // 30
				return DataFormat::R8G8_UNORM;
			case MTLPixelFormatRG8Unorm_sRGB: // 31
				return DataFormat::R8G8_SRGB;
			case MTLPixelFormatRG8Snorm: // 32
				return DataFormat::R8G8_SNORM;
			case MTLPixelFormatRG8Uint: // 33
				return DataFormat::R8G8_UINT;
			case MTLPixelFormatRG8Sint: // 34
				return DataFormat::R8G8_SINT;

			/* Packed 16 bit formats */
			case MTLPixelFormatB5G6R5Unorm: // 40
				return DataFormat::B5G6R5_UNORM_PACK16;
			case MTLPixelFormatA1BGR5Unorm: // 41
				throw std::runtime_error("No mapping form A1BGR5 to vk type");
			case MTLPixelFormatABGR4Unorm: // 42
				return DataFormat::A4B4G4R4_UNORM_PACK16;
			case MTLPixelFormatBGR5A1Unorm: // 43
				return DataFormat::B5G5R5A1_UNORM_PACK16;

			/* Normal 32 bit formats */
			case MTLPixelFormatR32Uint: // 53
				return DataFormat::R32_UINT;
			case MTLPixelFormatR32Sint: // 54
				return DataFormat::R32_SINT;
			case MTLPixelFormatR32Float: // 55
				return DataFormat::R32_SFLOAT;

			case MTLPixelFormatRG16Unorm: // 60
				return DataFormat::R16G16_UNORM;
			case MTLPixelFormatRG16Snorm: // 62
				return DataFormat::R16G16_SNORM;
			case MTLPixelFormatRG16Uint: // 63
				return DataFormat::R16G16_UINT;
			case MTLPixelFormatRG16Sint: // 64
				return DataFormat::R16G16_SINT;
			case MTLPixelFormatRG16Float: // 65
				return DataFormat::R16G16_SFLOAT;

			case MTLPixelFormatRGBA8Unorm: // 70
				return DataFormat::R8G8B8A8_UNORM;
			case MTLPixelFormatRGBA8Unorm_sRGB: // 71
				return DataFormat::R8G8B8A8_SRGB;
			case MTLPixelFormatRGBA8Snorm: // 72
				return DataFormat::R8G8B8A8_SNORM;
			case MTLPixelFormatRGBA8Uint: // 73
				return DataFormat::R8G8B8A8_UINT;
			case MTLPixelFormatRGBA8Sint: // 74
				return DataFormat::R8G8B8A8_SINT;

			case MTLPixelFormatBGRA8Unorm: // 80
				return DataFormat::B8G8R8A8_UNORM;
			case MTLPixelFormatBGRA8Unorm_sRGB: // 81
				return DataFormat::B8G8R8A8_SRGB;

			/* Packed 32 bit formats */

			case MTLPixelFormatRGB10A2Unorm: // 90
				return DataFormat::A2B10G10R10_UNORM_PACK32;
			case MTLPixelFormatRGB10A2Uint: // 91
				return DataFormat::A2B10G10R10_UINT_PACK32;

			case MTLPixelFormatRG11B10Float: // 92
				return DataFormat::B10G11R11_UFLOAT_PACK32;
			case MTLPixelFormatRGB9E5Float: // 93
				return DataFormat::E5B9G9R9_UFLOAT_PACK32;

			case MTLPixelFormatBGR10A2Unorm: // 94
				return DataFormat::A2R10G10B10_UNORM_PACK32;

			case MTLPixelFormatBGR10_XR: // 554
			case MTLPixelFormatBGR10_XR_sRGB: // 555
				throw std::runtime_error("Unimplemented format");

			/* Normal 64 bit formats */

			case MTLPixelFormatRG32Uint: // 103
				return DataFormat::R32G32_UINT;
			case MTLPixelFormatRG32Sint: // 104
				return DataFormat::R32G32_SINT;
			case MTLPixelFormatRG32Float: // 105
				return DataFormat::R32G32_SFLOAT;

			case MTLPixelFormatRGBA16Unorm: // 110
				return DataFormat::R16G16B16A16_UNORM;
			case MTLPixelFormatRGBA16Snorm: // 112
				return DataFormat::R16G16B16A16_SNORM;
			case MTLPixelFormatRGBA16Uint: // 113
				return DataFormat::R16G16B16A16_UINT;
			case MTLPixelFormatRGBA16Sint: // 114
				return DataFormat::R16G16B16A16_SINT;
			case MTLPixelFormatRGBA16Float: // 115
				return DataFormat::R16G16B16A16_SFLOAT;

			case MTLPixelFormatBGRA10_XR: // 552
			case MTLPixelFormatBGRA10_XR_sRGB: // 553
				throw std::runtime_error("Unimplemented format");

			/* Normal 128 bit formats */

			case MTLPixelFormatRGBA32Uint: // 123
				return DataFormat::R32G32B32A32_UINT;
			case MTLPixelFormatRGBA32Sint: // 124
				return DataFormat::R32G32B32A32_SINT;
			case MTLPixelFormatRGBA32Float: // 125
				return DataFormat::R32G32B32A32_SFLOAT;

			/* Compressed formats. */
			/* S3TC/DXT */
			case MTLPixelFormatBC1_RGBA: // 130
			case MTLPixelFormatBC1_RGBA_sRGB: // 131
			case MTLPixelFormatBC2_RGBA: // 132
			case MTLPixelFormatBC2_RGBA_sRGB: // 133
			case MTLPixelFormatBC3_RGBA: // 134
			case MTLPixelFormatBC3_RGBA_sRGB: // 135

			/* RGTC */
			case MTLPixelFormatBC4_RUnorm: // 140
			case MTLPixelFormatBC4_RSnorm: // 141
			case MTLPixelFormatBC5_RGUnorm: // 142
			case MTLPixelFormatBC5_RGSnorm: // 143

			/* BPTC */
			case MTLPixelFormatBC6H_RGBFloat: // 150
			case MTLPixelFormatBC6H_RGBUfloat: // 151
			case MTLPixelFormatBC7_RGBAUnorm: // 152
			case MTLPixelFormatBC7_RGBAUnorm_sRGB: // 153

			/* PVRTC */
			case MTLPixelFormatPVRTC_RGB_2BPP: // 160
			case MTLPixelFormatPVRTC_RGB_2BPP_sRGB: // 161
			case MTLPixelFormatPVRTC_RGB_4BPP: // 162
			case MTLPixelFormatPVRTC_RGB_4BPP_sRGB: // 163
			case MTLPixelFormatPVRTC_RGBA_2BPP: // 164
			case MTLPixelFormatPVRTC_RGBA_2BPP_sRGB: // 165
			case MTLPixelFormatPVRTC_RGBA_4BPP: // 166
			case MTLPixelFormatPVRTC_RGBA_4BPP_sRGB: // 167

			/* ETC2 */
			case MTLPixelFormatEAC_R11Unorm: // 170
			case MTLPixelFormatEAC_R11Snorm: // 172
			case MTLPixelFormatEAC_RG11Unorm: // 174
			case MTLPixelFormatEAC_RG11Snorm: // 176
			case MTLPixelFormatEAC_RGBA8: // 178
			case MTLPixelFormatEAC_RGBA8_sRGB: // 179

			case MTLPixelFormatETC2_RGB8: // 180
			case MTLPixelFormatETC2_RGB8_sRGB: // 181
			case MTLPixelFormatETC2_RGB8A1: // 182
			case MTLPixelFormatETC2_RGB8A1_sRGB: // 183

			/* ASTC */
			case MTLPixelFormatASTC_4x4_sRGB: // 186
			case MTLPixelFormatASTC_5x4_sRGB: // 187
			case MTLPixelFormatASTC_5x5_sRGB: // 188
			case MTLPixelFormatASTC_6x5_sRGB: // 189
			case MTLPixelFormatASTC_6x6_sRGB: // 190
			case MTLPixelFormatASTC_8x5_sRGB: // 192
			case MTLPixelFormatASTC_8x6_sRGB: // 193
			case MTLPixelFormatASTC_8x8_sRGB: // 194
			case MTLPixelFormatASTC_10x5_sRGB: // 195
			case MTLPixelFormatASTC_10x6_sRGB: // 196
			case MTLPixelFormatASTC_10x8_sRGB: // 197
			case MTLPixelFormatASTC_10x10_sRGB: // 198
			case MTLPixelFormatASTC_12x10_sRGB: // 199
			case MTLPixelFormatASTC_12x12_sRGB: // 200

			case MTLPixelFormatASTC_4x4_LDR: // 204
			case MTLPixelFormatASTC_5x4_LDR: // 205
			case MTLPixelFormatASTC_5x5_LDR: // 206
			case MTLPixelFormatASTC_6x5_LDR: // 207
			case MTLPixelFormatASTC_6x6_LDR: // 208
			case MTLPixelFormatASTC_8x5_LDR: // 210
			case MTLPixelFormatASTC_8x6_LDR: // 211
			case MTLPixelFormatASTC_8x8_LDR: // 212
			case MTLPixelFormatASTC_10x5_LDR: // 213
			case MTLPixelFormatASTC_10x6_LDR: // 214
			case MTLPixelFormatASTC_10x8_LDR: // 215
			case MTLPixelFormatASTC_10x10_LDR: // 216
			case MTLPixelFormatASTC_12x10_LDR: // 217
			case MTLPixelFormatASTC_12x12_LDR: // 218


			// ASTC HDR (High Dynamic Range) Formats
			case MTLPixelFormatASTC_4x4_HDR: // 222
			case MTLPixelFormatASTC_5x4_HDR: // 223
			case MTLPixelFormatASTC_5x5_HDR: // 224
			case MTLPixelFormatASTC_6x5_HDR: // 225
			case MTLPixelFormatASTC_6x6_HDR: // 226
			case MTLPixelFormatASTC_8x5_HDR: // 228
			case MTLPixelFormatASTC_8x6_HDR: // 229
			case MTLPixelFormatASTC_8x8_HDR: // 230
			case MTLPixelFormatASTC_10x5_HDR: // 231
			case MTLPixelFormatASTC_10x6_HDR: // 232
			case MTLPixelFormatASTC_10x8_HDR: // 233
			case MTLPixelFormatASTC_10x10_HDR: // 234
			case MTLPixelFormatASTC_12x10_HDR: // 235
			case MTLPixelFormatASTC_12x12_HDR: // 236
				throw std::runtime_error("Conversion not yet implemented"); //TODO

					/*!
					 @constant			case MTLPixelFormatGBGR422
					 @abstract A pixel format where the red and green channels are subsampled horizontally.  Two pixels are stored in 32 bits, with shared red and blue values, and unique green values.
					 @discussion This format is equivalent to YUY2, YUYV, yuvs, or GL_RGB_422_APPLE/GL_UNSIGNED_SHORT_8_8_REV_APPLE.   The component order, from lowest addressed byte to highest, is Y0, Cb, Y1, Cr.  There is no implicit colorspace conversion from YUV to RGB, the shader will receive (Cr, Y, Cb, 1).  422 textures must have a width that is a multiple of 2, and can only be used for 2D non-mipmap textures.  When sampling, ClampToEdge is the only usable wrap mode.
					 */
			case MTLPixelFormatGBGR422: // 240
				return DataFormat::G8B8G8R8_422_UNORM;

					/*!
					 @constant			case MTLPixelFormatBGRG422
					 @abstract A pixel format where the red and green channels are subsampled horizontally.  Two pixels are stored in 32 bits, with shared red and blue values, and unique green values.
					 @discussion This format is equivalent to UYVY, 2vuy, or GL_RGB_422_APPLE/GL_UNSIGNED_SHORT_8_8_APPLE. The component order, from lowest addressed byte to highest, is Cb, Y0, Cr, Y1.  There is no implicit colorspace conversion from YUV to RGB, the shader will receive (Cr, Y, Cb, 1).  422 textures must have a width that is a multiple of 2, and can only be used for 2D non-mipmap textures.  When sampling, ClampToEdge is the only usable wrap mode.
					 */
			case MTLPixelFormatBGRG422: // 241
				return DataFormat::B8G8R8G8_422_UNORM;

			/* Depth */
			case MTLPixelFormatDepth16Unorm: // 250
				return DataFormat::D16_UNORM;
			case MTLPixelFormatDepth32Float: // 252
				return DataFormat::D32_SFLOAT;

			/* Stencil */
			case MTLPixelFormatStencil8: // 253
				return DataFormat::S8_UINT;

			/* Depth Stencil */
			//case MTLPixelFormatDepth24Unorm_Stencil8: // 255
				return DataFormat::D24_UNORM_S8_UINT;
			case MTLPixelFormatDepth32Float_Stencil8: // 260
				return DataFormat::D32_SFLOAT_S8_UINT;

			case MTLPixelFormatX32_Stencil8: // 261
			//case MTLPixelFormatX24_Stencil8: // 262
				throw std::runtime_error("Conversion not yet implemented");
		}
		
		return UNDEFINED;
	}
}
