/*
 * 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/.
 */

#pragma once

#include <cinttypes>
#include <compare>

namespace OpenVulkano::Scene
{
	enum class TextureSamplerFilter : int
	{
		NEAREST = 0,
		LINEAR = 1,
		CUBIC = 1000015000
	};

	enum class TextureSamplerEdgeMode : int
	{
		REPEAT = 0,
		MIRRORED_REPEAT = 1,
		CLAMP_TO_EDGE = 2,
		CLAMP_TO_BORDER = 3,
		MIRROR_CLAMP_TO_EDGE = 4
	};

	enum class TextureSamplerMipmapMode : int
	{
		NEAREST = 0,
		LINEAR = 1
	};

	class SamplerConfig final
	{
	public:
		using bool32_t = uint32_t;

	private:
		uint32_t type = 31; // To allow casting to vulkan struct
		const void* next = nullptr; // To allow casting to vulkan struct

	public:
		uint32_t flags = 0;
		TextureSamplerFilter magFilter = TextureSamplerFilter::NEAREST;
		TextureSamplerFilter minFilter = TextureSamplerFilter::NEAREST;
		TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST;
		TextureSamplerEdgeMode edgeModeU = TextureSamplerEdgeMode::REPEAT;
		TextureSamplerEdgeMode edgeModeV = TextureSamplerEdgeMode::REPEAT;
		TextureSamplerEdgeMode edgeModeW = TextureSamplerEdgeMode::REPEAT;
		float mipLoadBias = 0;
		bool32_t anisotropyEnabled = false;
		float maxAnisotropy = 0;
		bool32_t compareEnabled = false;
		uint32_t compareOp = 0; //TODO
		float minLod = 0, maxLod = 0;
		uint32_t borderColor = 0;
		bool32_t unnormalizedCoordinates = false;

		SamplerConfig(TextureSamplerEdgeMode edgeMode, TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST,
				TextureSamplerFilter magFilter = TextureSamplerFilter::NEAREST, TextureSamplerFilter minFilter = TextureSamplerFilter::NEAREST)
				: magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode), edgeModeU(edgeMode), edgeModeV(edgeMode), edgeModeW(edgeMode)
		{}

		SamplerConfig(uint32_t flags = 0, TextureSamplerFilter magFilter = TextureSamplerFilter::LINEAR,
				TextureSamplerFilter minFilter = TextureSamplerFilter::LINEAR,
				TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST,
				TextureSamplerEdgeMode edgeModeU = TextureSamplerEdgeMode::REPEAT,
				TextureSamplerEdgeMode edgeModeV = TextureSamplerEdgeMode::REPEAT,
				TextureSamplerEdgeMode edgeModeW = TextureSamplerEdgeMode::REPEAT,
				float mipLoadBias = 0, bool32_t anisotropyEnabled = false, float maxAnisotropy = 0,
				bool32_t compareEnabled = false, uint32_t compareOp = 0, //TODO
				float minLod = 0, float maxLod = 0, uint32_t borderColor = 0, bool32_t unnormalizedCoordinates = false)
				: flags(flags), magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode)
				, edgeModeU(edgeModeU), edgeModeV(edgeModeV), edgeModeW(edgeModeW)
				, mipLoadBias(mipLoadBias), anisotropyEnabled(anisotropyEnabled), maxAnisotropy(maxAnisotropy)
				, compareEnabled(compareEnabled), compareOp(compareOp)
				, minLod(minLod), maxLod(maxLod), borderColor(borderColor), unnormalizedCoordinates(unnormalizedCoordinates)
		{}
		
		SamplerConfig(TextureSamplerFilter magFilter, TextureSamplerFilter minFilter = TextureSamplerFilter::LINEAR,
					  TextureSamplerMipmapMode mipmapMode = TextureSamplerMipmapMode::NEAREST,
					  bool32_t anisotropyEnabled = false, float maxAnisotropy = 0)
			: magFilter(magFilter), minFilter(minFilter), mipmapMode(mipmapMode), anisotropyEnabled(anisotropyEnabled), maxAnisotropy(maxAnisotropy)
		{}

		auto operator <=>(const SamplerConfig& other) const = default;

	public:
		// Default configs
		static const SamplerConfig DEFAULT;
		static const SamplerConfig NEAREST;
		static const SamplerConfig LINEAR;
		static const SamplerConfig BILINEAR;
		static const SamplerConfig TIRILINEAR;
		static const SamplerConfig ANISOTROPIC_LOW;
		static const SamplerConfig ANISOTROPIC_HIGH;
		
		// Not supported on most consumer grphics cards!
		static const SamplerConfig ANISOTROPIC_PRO;
	};
}
