/*
**  Vulkan backend
**  Copyright (c) 2016-2020 Magnus Norddahl
**
**  This software is provided 'as-is', without any express or implied
**  warranty.  In no event will the authors be held liable for any damages
**  arising from the use of this software.
**
**  Permission is granted to anyone to use this software for any purpose,
**  including commercial applications, and to alter it and redistribute it
**  freely, subject to the following restrictions:
**
**  1. The origin of this software must not be misrepresented; you must not
**     claim that you wrote the original software. If you use this software
**     in a product, an acknowledgment in the product documentation would be
**     appreciated but is not required.
**  2. Altered source versions must be plainly marked as such, and must not be
**     misrepresented as being the original software.
**  3. This notice may not be removed or altered from any source distribution.
**
*/

#include "volk/volk.h"
#include "c_cvars.h"
#include "v_video.h"

#include "hw_cvars.h"
#include "vulkan/system/vk_device.h"
#include "vulkan/system/vk_builders.h"
#include "vk_samplers.h"
#include "hw_material.h"
#include "i_interface.h"

struct VkTexFilter
{
	VkFilter minFilter;
	VkFilter magFilter;
	VkSamplerMipmapMode mipfilter;
	bool mipmapping;
} ;

VkTexFilter TexFilter[]={
	{VK_FILTER_NEAREST,		VK_FILTER_NEAREST,		VK_SAMPLER_MIPMAP_MODE_NEAREST, false},
	{VK_FILTER_NEAREST,		VK_FILTER_NEAREST,		VK_SAMPLER_MIPMAP_MODE_NEAREST, true},
	{VK_FILTER_LINEAR,		VK_FILTER_LINEAR,		VK_SAMPLER_MIPMAP_MODE_NEAREST, false},
	{VK_FILTER_LINEAR,		VK_FILTER_LINEAR,		VK_SAMPLER_MIPMAP_MODE_NEAREST, true},
	{VK_FILTER_LINEAR,		VK_FILTER_LINEAR,		VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
	{VK_FILTER_NEAREST,		VK_FILTER_NEAREST,		VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
	{VK_FILTER_LINEAR,		VK_FILTER_NEAREST,		VK_SAMPLER_MIPMAP_MODE_LINEAR, true},
};

struct VkTexClamp
{
	VkSamplerAddressMode clamp_u;
	VkSamplerAddressMode clamp_v;
};

VkTexClamp TexClamp[] ={
	{ VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT },
	{ VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT },
	{ VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE },
	{ VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE },
};

VkSamplerManager::VkSamplerManager(VulkanDevice *dev)
{
	vDevice = dev;
	Create();
}

VkSamplerManager::~VkSamplerManager()
{
	Destroy();
}

void VkSamplerManager::SetTextureFilterMode()
{
	Destroy();
	Create();
}

void VkSamplerManager::Create()
{
	int filter = sysCallbacks.DisableTextureFilter && sysCallbacks.DisableTextureFilter()? 0 : gl_texture_filter;
	
	for (int i = CLAMP_NONE; i <= CLAMP_XY; i++)
	{
		SamplerBuilder builder;
		builder.setMagFilter(TexFilter[filter].magFilter);
		builder.setMinFilter(TexFilter[filter].minFilter);
		builder.setAddressMode(TexClamp[i].clamp_u, TexClamp[i].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT);
		builder.setMipmapMode(TexFilter[filter].mipfilter);
		if (TexFilter[filter].mipmapping)
		{
			builder.setAnisotropy(gl_texture_filter_anisotropic);
			builder.setMaxLod(100.0f); // According to the spec this value is clamped so something high makes it usable for all textures.
		}
		else
		{
			builder.setMaxLod(0.25f);
		}
		mSamplers[i] = builder.create(vDevice);
		mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers");
	}
	{
		SamplerBuilder builder;
		builder.setMagFilter(TexFilter[filter].magFilter);
		builder.setMinFilter(TexFilter[filter].magFilter);
		builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT);
		builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
		builder.setMaxLod(0.25f);
		mSamplers[CLAMP_XY_NOMIP] = builder.create(vDevice);
		mSamplers[CLAMP_XY_NOMIP]->SetDebugName("VkSamplerManager.mSamplers");
	}
	for (int i = CLAMP_NOFILTER; i <= CLAMP_NOFILTER_XY; i++)
	{
		SamplerBuilder builder;
		builder.setMagFilter(VK_FILTER_NEAREST);
		builder.setMinFilter(VK_FILTER_NEAREST);
		builder.setAddressMode(TexClamp[i - CLAMP_NOFILTER].clamp_u, TexClamp[i - CLAMP_NOFILTER].clamp_v, VK_SAMPLER_ADDRESS_MODE_REPEAT);
		builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
		builder.setMaxLod(0.25f);
		mSamplers[i] = builder.create(vDevice);
		mSamplers[i]->SetDebugName("VkSamplerManager.mSamplers");
	}
	// CAMTEX is repeating with texture filter and no mipmap
	{
		SamplerBuilder builder;
		builder.setMagFilter(TexFilter[filter].magFilter);
		builder.setMinFilter(TexFilter[filter].magFilter);
		builder.setAddressMode(VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT);
		builder.setMipmapMode(VK_SAMPLER_MIPMAP_MODE_NEAREST);
		builder.setMaxLod(0.25f);
		mSamplers[CLAMP_CAMTEX] = builder.create(vDevice);
		mSamplers[CLAMP_CAMTEX]->SetDebugName("VkSamplerManager.mSamplers");
	}
}

void VkSamplerManager::Destroy()
{
	for (int i = 0; i < NUMSAMPLERS; i++)
		mSamplers[i].reset();
}