using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[UnityEngine.ExecuteInEditMode]
public class TerrainOptimization : MonoBehaviour
{
	Material m_terrainMaterial;
	int m_preComputedValueID = 0;
	float [] m_preComputedValue = new float[36];
	// Start is called before the first frame update
	void Start()
    {
		Renderer renderer = GetComponent<Renderer>();
		if(renderer)
		{
			m_terrainMaterial = renderer.sharedMaterial;
		}
		m_preComputedValueID = Shader.PropertyToID("_preComputedValue");

		ComputedHSVValue();
	}

	void ComputeHSVShiftValue(Vector3 shiftValue, int startIndex)
	{
		const float FTNN_DEGREE_TO_RADIAN_FACTOR = 0.01745329f;		
		float vsu = shiftValue.z * shiftValue.y * Mathf.Cos(shiftValue.x * FTNN_DEGREE_TO_RADIAN_FACTOR);
		float vsw = shiftValue.z * shiftValue.y * Mathf.Sin(shiftValue.x * FTNN_DEGREE_TO_RADIAN_FACTOR);

		m_preComputedValue[startIndex++] = 0.299f * shiftValue.z + 0.701f * vsu + 0.168f * vsw;
		m_preComputedValue[startIndex++] = 0.587f * shiftValue.z - 0.587f * vsu + 0.330f * vsw;
		m_preComputedValue[startIndex++] = 0.114f * shiftValue.z - 0.114f * vsu - 0.497f * vsw;

		m_preComputedValue[startIndex++] = 0.299f * shiftValue.z - 0.299f * vsu - 0.328f * vsw;
		m_preComputedValue[startIndex++] = 0.587f * shiftValue.z + 0.413f * vsu + 0.035f * vsw;
		m_preComputedValue[startIndex++] = 0.114f * shiftValue.z - 0.114f * vsu + 0.292f * vsw;

		m_preComputedValue[startIndex++] = 0.299f * shiftValue.z - 0.3f * vsu + 1.25f * vsw;
		m_preComputedValue[startIndex++] = 0.587f * shiftValue.z - 0.588f * vsu - 1.05f * vsw;
		m_preComputedValue[startIndex++] = 0.114f * shiftValue.z + 0.886f * vsu - 0.203f * vsw;
	}

	void ComputeColorValue(float hsvRef, Vector3 additiveColor, int startIndex)
	{
		float value = 1 - hsvRef * (1 - additiveColor.x * 2);
		m_preComputedValue[startIndex++] = Mathf.Max(0, Mathf.Min(1, value));
		value = 1 - hsvRef * (1 - additiveColor.y * 2);
		m_preComputedValue[startIndex++] = Mathf.Max(0, Mathf.Min(1, value));
		value = 1 - hsvRef * (1 - additiveColor.z * 2);
		m_preComputedValue[startIndex++] = Mathf.Max(0, Mathf.Min(1, value));
	}

	Vector3 FastSRGBToLinear(Vector3 color)
	{
		color.x = color.x * (color.x * (color.x * 0.305306011f + 0.682171111f) + 0.012522878f);
		color.y = color.y * (color.y * (color.y * 0.305306011f + 0.682171111f) + 0.012522878f);
		color.z = color.z * (color.z * (color.z * 0.305306011f + 0.682171111f) + 0.012522878f);
		return color;
	}

	Vector3 ComputeShiftValue(float hsvRef, float hueShift, float satMultiplier, float valMultiplier)
	{
		return new Vector3(hueShift * hsvRef, 1 - (1 - satMultiplier) * hsvRef, 1 - (0.5f - valMultiplier) * hsvRef );
	}

	void ComputedHSVValue()
	{
		//compute hsv value with ref 1 (1, _HueShift, _Sat, _Val, _CMaskBottomG)
		float _HueShift = m_terrainMaterial.GetFloat("_HueShift");
		float _Sat = m_terrainMaterial.GetFloat("_Sat");
		float _Val = m_terrainMaterial.GetFloat("_Val");
		Vector3 _CMaskBottomG = m_terrainMaterial.GetVector("_CMaskBottomG");
		// must caculate in linear space
		_CMaskBottomG = FastSRGBToLinear(_CMaskBottomG);
		Vector3 shiftValue = ComputeShiftValue(1, _HueShift, _Sat, _Val);
		ComputeHSVShiftValue(shiftValue, 0);
		ComputeColorValue(1, _CMaskBottomG, 27);

		//compute hsv value with ref 1 (1, _HueShiftCM, _SatCM, _ValCM, _CMaskBottom)
		float _HueShiftCM = m_terrainMaterial.GetFloat("_HueShiftCM");
		float _SatCM = m_terrainMaterial.GetFloat("_SatCM");
		float _ValCM = m_terrainMaterial.GetFloat("_ValCM");		
		Vector3 _CMaskBottom = m_terrainMaterial.GetVector("_CMaskBottom");
		// must caculate in linear space
		_CMaskBottom = FastSRGBToLinear(_CMaskBottom);
		shiftValue = ComputeShiftValue(1, _HueShiftCM, _SatCM, _ValCM);
		ComputeHSVShiftValue(shiftValue, 9);
		ComputeColorValue(1, _CMaskBottom, 30);

		//compute  hsv value with ref  (1, _HueShiftFlipG, _SatFlipG, _ValFlipG, _Flip_CMaskBottomG)
		// float _HueShiftFlipG = m_terrainMaterial.GetFloat("_HueShiftFlipG");
		// float _SatFlipG = m_terrainMaterial.GetFloat("_SatFlipG");
		// float _ValFlipG = m_terrainMaterial.GetFloat("_ValFlipG");
		// Vector3 _Flip_CMaskBottomG = m_terrainMaterial.GetVector("_Flip_CMaskBottomG");
		// _Flip_CMaskBottomG = FastSRGBToLinear(_Flip_CMaskBottomG);
		// shiftValue = ComputeShiftValue(1, _HueShiftFlipG, _SatFlipG, _ValFlipG);
		// ComputeHSVShiftValue(shiftValue, 18);
		// ComputeColorValue(1, _Flip_CMaskBottomG, 33);
	}

	// Update is called once per frame
	void Update()
    {
#if UNITY_EDITOR
		ComputedHSVValue();
#endif
		if (m_preComputedValueID >= 0 && m_terrainMaterial != null)
		{
			m_terrainMaterial.SetFloatArray(m_preComputedValueID, m_preComputedValue);
		}
    }
}
