-- ###  customizable variables ###

-- The precision of white:
-- if this is 1.0, White is pure for 20°C and sunangles higher then 30°
local solHDR__WHITE_POINT_PRECISION = 0.5

-- set the peak brightness of the monitor
local solHDR__PEAK_BRIGHTNESS = 500


--[[

	Sol HDR PPfilter 1.1

	changelog:
	1.1
	- use custom distant fog
	- better distant color with sunset (use Sol 2.2 alpha 6 or later)
	- recalibrated brightness and gamma with solHDR__PEAK_BRIGHTNESS
	- more saturated sky
	- more cloud contrast 
	- some variables optimization

	1.2
	- adjusted sunlight hue
	- adjusted ambient light hue
	- more optimized white with solHDR__WHITE_POINT_PRECISION = 1.0 for clear and overcast weather
	- some adjustments to CSP light strenght while day
	- tweaked night brightness 

	1.3
	- remove VAO exponent control
	- AE tweaks
	- some brightness tweaks
	- addedc special color grading for more vibrant colors and better contrast
]]



n = 1                  
local _l_FOV_LUT = {}
_l_FOV_LUT[n] = {  0, 0.00, 0.01 } n=n+1
_l_FOV_LUT[n] = { 10, 0.00, 0.40 } n=n+1
_l_FOV_LUT[n] = { 30, 0.00, 0.70 } n=n+1
_l_FOV_LUT[n] = { 40, 0.15, 0.80 } n=n+1
_l_FOV_LUT[n] = { 50, 0.30, 0.90 } n=n+1
_l_FOV_LUT[n] = { 60, 0.40, 0.90 } n=n+1
_l_FOV_LUT[n] = { 70, 0.50, 0.90 } n=n+1
_l_FOV_LUT[n] = { 80, 0.57, 0.90 } n=n+1
_l_FOV_LUT[n] = { 90, 0.65, 0.90 } n=n+1
_l_FOV_LUT[n] = {180, 0.70, 0.90 } n=n+1
_l_FOV_LUT[n] = {360, 0.70, 0.90 } n=n+1


n = 1                  
local _l_AE_LIMIT_LUT = {}
_l_AE_LIMIT_LUT[n] = {  -90, 1.00, 10.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {  -12, 1.00, 10.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {   -9, 1.20,  8.40 } n=n+1
_l_AE_LIMIT_LUT[n] = {   -6, 1.50,  6.60 } n=n+1
_l_AE_LIMIT_LUT[n] = {   -3, 1.10,  5.50 } n=n+1
_l_AE_LIMIT_LUT[n] = {    0, 0.70,  5.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {    5, 0.25,  4.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {   15, 0.01,  3.50 } n=n+1
_l_AE_LIMIT_LUT[n] = {   90, 0.01,  3.50 } n=n+1

local isVR = false

function init_sol_custom_config()

	-- reset customs to default
	ac.resetGodraysCustomColor()
	ac.resetGodraysCustomDirection()
	ac.resetWeatherStaticAmbient()
	ac.resetShadowsResolution()
	ac.resetShadowsSplits()
	ac.resetSpecularColor()
	ac.resetHorizonFogMultiplier()
	ac.resetGlowBrightness()
	ac.resetWeatherLightsMultiplier()
	ac.resetEmissiveMultiplier()
	ac.resetCloudsLight()

	--------------------------------
	--activate extra Sol functions
	--------------------------------


	-- Sol controlled PPFilter effects
	SOL__set_config("pp", "modify_glare", true)
	SOL__set_config("pp", "glare_day_threshold", 2.0)
	SOL__set_config("pp", "modify_godrays", true)
	SOL__set_config("pp", "modify_spectrum", true)

	--SOL__set_config("pp", "brightness_sun_link", 2)
	SOL__set_config("pp", "brightness_sun_link_only_interior", false)

	-- Autoexposure
	-- Since CSP 1.69 a much better AE is possible, because the car's exposure multipliers can be deactivated
	-- So don't use self calibrating AE, use the YEBIS AE
	SOL__set_config("ae", "use_self_calibrating", false)
	-- But neutralise it, to have custom access...
	SOL__set_config("ae", "alternate_ae_mode", 1)

	-- deactivate cars exposure multiplier
	ac.setCarExposureActive(false)


	-- CSP lights
	SOL__set_config("csp_lights", "controlled_by_sol", true)
	SOL__set_config("nerd__csp_lights_adjust", "emissive_night", 0.60, true)


	--SOL__set_config("sky", "smog", 1.0, true)

	SOL__set_config("nerd__fog_custom_distant_fog", "use"		, true)
	SOL__set_config("nerd__fog_custom_distant_fog", "sky"		, -2.50)
	SOL__set_config("nerd__fog_custom_distant_fog", "Hue"		, 220)
	SOL__set_config("nerd__fog_custom_distant_fog", "Saturation", 1)

	
	-- initial values of weatherFX settings
	ac.setWeatherFakeShadowOpacity(1.10)

	--Dazzle effect
	SOL__set_config("sun", "dazzle_mix", 0.80)
	SOL__set_config("sun", "dazzle_strength", 0.80)
	SOL__set_config("sun", "dazzle_zenith_multi", 0)



	ac.setPpWhiteBalanceK(6250)
	ac.setPpColorTemperatureK(6250)

	local videomode = weather__get_Video_Settings("CAMERA", "MODE")
	if videomode and (videomode == "OCULUS" or videomode == "OPENVR") then
		isVR = true
	end
end

local sun_comp_zero 		= sun_compensate(0)
local twilight_comp_zero 	= from_twilight_compensate(0)

local _l_camFOV = 60
local cam_exterior = false

solHDR__WHITE_POINT_PRECISION = math.max(0, math.min(1, solHDR__WHITE_POINT_PRECISION))
local peak_brightness_factor = 0.000125*(math.max(250, math.min(10000, solHDR__PEAK_BRIGHTNESS)) - 500)

-- this is called not every frame
function update_sol_custom_config(dt)

	local sun_curve = __IntD(0, 1, 0.7)

	_l_camFOV = ac.getCameraFOV()

	--SOL__set_config("nerd__clouds_adjust", "Lit", 1.00 - 0.05*twilight_comp_zero, true)
	--SOL__set_config("nerd__clouds_adjust", "Contour", 1.00 + 0.15*twilight_comp_zero, true)
	SOL__set_config("nerd__clouds_adjust", "Saturation_limit", 1.00 - 0.3 * sun_curve, true)
	
	--SOL__set_config("nerd__sky_adjust", "Saturation", 1.45 - 0.3*twilight_comp_zero, true)
	SOL__set_config("nerd__sky_adjust", "Level", 1.0 + 0.1*sun_comp_zero, true)
	SOL__set_config("nerd__sky_adjust", "Hue", 1.0 - 0.5*sun_comp_zero, true)

	SOL__set_config("nerd__fog_custom_distant_fog", "sky"		, -0.50 - 2.25*sun_comp_zero*weather__get_overcast())
	SOL__set_config("nerd__fog_custom_distant_fog", "sun"		, sun_comp_zero)
	SOL__set_config("nerd__fog_custom_distant_fog", "Level"		, 0.50 + 1.0*sun_comp_zero)
	SOL__set_config("nerd__fog_custom_distant_fog", "Saturation", 1.25 - 0.45*weather__get_overcast())

	SOL__set_config("nerd__sun_adjust", "ls_Saturation", 0.95 + 0.10 * sun_curve, true)
	SOL__set_config("nerd__sun_adjust", "ls_Hue", 1.000 + 0.05 * sun_comp_zero, true)
	SOL__set_config("nerd__sun_adjust", "ls_Level", 0.95 + 0.35 * sun_curve, true)
	SOL__set_config("nerd__sun_adjust", "ap_Level", 3.5 - 2.5*math.pow(sun_comp_zero, 0.5), true)
	SOL__set_config("nerd__speculars_adjust", "Level", (1.0 - 0.1 * sun_comp_zero), true)

	
	
	-- dim lights a little bit with twilight, to adapt it to the still existing ambient light
	SOL__set_config("nerd__csp_lights_adjust", "bounced_night", 0.55 + 0.50*night_compensate(0), true)

	--SOL__set_config("nerd__sun_adjust", "ls_Level", (1 + 0.125*sun_comp_zero), true)
	--SOL__set_config("nerd__sun_adjust", "ls_Saturation", (1 + 0.25*ssun_comp_zero), true)

	-- some multiplier to adapt exposure to the main light situations
	local exp_at_night = 1.0
	local exp_at_twilight = 1.0
	local exp_at_day = 1.0

	-- do not modify exposure with auto exposure, because it will start to wobble (self oscillation)
	local exp
	exp = (0.15 + 0.00*night_compensate(0)) * 1.3-- raise exposure with night

	exp = exp * math.lerp(math.lerp( exp_at_twilight, exp_at_day, sun_comp_zero), exp_at_night, night_compensate(0))

	SOL_filter__set_exposure_base(exp)
	ac.setPpTonemapExposure(0.225)
end

local AE_backup = 0

-- this is called every frame
function update_sol_custom_config__every_frame(dt)
	
	-- update sun variables
	sun_comp_zero 		= sun_compensate(0)
	twilight_comp_zero 	= from_twilight_compensate(0)

	local sun_curve_steep = __IntD(0, 1, 0.6)

	-- for AE controlling, its better to check every frame

	-- speed of AE controlling
	-- If you like, modulate this for different situations
	local AE_reaction_speed = 1

	-- get cloud shadow state, prevent controlling in night
	local cloud_shadow_mod = weather__get_cloud_shadow() * sun_comp_zero

	-- do the same controlling for cloud shadows and overcast
	local overcast = math.max(weather__get_overcast(), cloud_shadow_mod)


	-- get Autoexposure from Sol
	local AE_from_PP = weather__get_AE()
	if AE_from_PP < AE_backup then
		-- fast reaction to bright scenery
		AE_reaction_speed = AE_reaction_speed * 125
		AE_backup = math.lerp(AE_backup, AE_from_PP, math.min(1, AE_reaction_speed*dt))
	else
		-- slower reaction to adapt on dark scenery (like the process with rhodopsin in retina)
		AE_reaction_speed = AE_reaction_speed * 4
		AE_backup = math.lerp(AE_backup, AE_from_PP, math.min(1, AE_reaction_speed*dt))
	end

	local AE = AE_backup
	local CamOcclusion = 0

	-- double the reflections amount to have a nice night look
	if ac.setReflectionEmissiveBoost then --check if function is present, for compatibility to older csp versions
		ac.setReflectionEmissiveBoost(from_twilight_compensate(2))
	end
	--[[
	if ac.isVertexAoPatchApplied() then
		if ac.setVAOExponent then --check if function is present, for compatibility to older csp versions
			-- Set VAO exponent, according to the height of the sun
			-- If sun is realy high, VAO could be very contrasty to the sun litten track parts
			ac.setVAOExponent(0.5 + __IntD(0,0.65))
		end
	end
	]]

	--ac.debug("####", ac.getCameraOcclusion(vec3(0,1,0))..","..ac.getCameraLookOcclusion())
	local target_multi = SOL_filter__predict_interiorAE()

	-- get the result of the LUT / _l_camFOV acts as the index
	local _l_FOV_LUT_r = interpolate__plan(_l_FOV_LUT, nil, _l_camFOV)

	if ac.isInteriorView() == true then 
		-- try to set the exposure measurement area to the windscreen area and expand it for the night

		

		-- use the result to form the measuring area
		ac.setAutoExposureMeasuringArea(vec2(0,-0.04+0.06*night_compensate(0)),
										vec2(1.0-_l_FOV_LUT_r[1]*day_compensate(0),
											 1.0-_l_FOV_LUT_r[1]*twilight_comp_zero))
		
		CamOcclusion = 1 - 0.50*ac.getCameraOcclusion(vec3(0,1,0)) - 0.50*ac.getCameraLookOcclusion()

		target_multi = math.lerp(1, target_multi, twilight_comp_zero)

		if cam_exterior and isVR then
			ac.setCarExposureActive(true)
			--___reset__Sol___()
		end
		cam_exterior = false
	else
		-- set the full exposure measurement area for extirior views
		ac.setAutoExposureMeasuringArea(vec2(0,0), vec2(1,0.67))
		
		CamOcclusion = 1 - 0.50*ac.getCameraOcclusion(vec3(0,1,0)) - 0.50*ac.getCameraLookOcclusion()
	
		target_multi = 1.10

		if not cam_exterior and isVR then
			ac.setCarExposureActive(true)
			--___reset__Sol___()
		end
		cam_exterior = true
	end

	-- adapt the AE target
	local target = math.max(0.01, -- never set this to 0 !
					( 0.40 -- daylight target value

					- 0.130*(1-sun_curve_steep) -- adapt AE to sunangle
					- 0.150*(1-twilight_comp_zero) -- lower it for twilight time
					- 0.125*(1-day_compensate(0)) -- lower it for night
					-- all together will set the value for night

					-- lower it for bad weather
					- 0.200*weather__get_badness()*day_compensate(0) 

					-- lower it a little bit in cloud shadows
					-- 0.025*overcast
					))

	ac.setAutoExposureTarget(target*target_multi*0.80)
	-- set a higher minimum AE level in nighttime, to have a good visibility
	-- set a higher maximum AE level in nighttime, to simulate adaption of the eye (bright stars)
	local _l_AE_LIMIT_LUT_r = interpolate__plan(_l_AE_LIMIT_LUT)
	ac.setAutoExposureLimits(_l_AE_LIMIT_LUT_r[1], _l_AE_LIMIT_LUT_r[2])




	ac.setPpTonemapMappingFactor((math.min(7.5 - 5.5*weather__get_overcast()*day_compensate(0), math.max(1, 1.50 + (0.5 - 0.6*night_compensate(0)) * AE  + 0.25 * sun_compensate(0) + 1.00 * night_compensate(0)))))



	SOL__set_config("nerd__ambient_adjust", "Level", 		(1.00 + 0.100 * sun_comp_zero * (1-overcast)), true)
	SOL__set_config("nerd__ambient_adjust", "Saturation", 	(1.00 - 0.050 * sun_comp_zero * (1-overcast)), true)
	--SOL__set_config("nerd__ambient_adjust", "Hue", 			(1.00 - 0.025 * sun_comp_zero), true)

	--SOL__set_config("nerd__sky_adjust", "Level", 1.00 + (0.75 - 0.50 * overcast) * sun_comp_zero, true)
	--SOL__set_config("nerd__sky_adjust", "Saturation", 1.00 + (0.50 - 0.50 * overcast) * sun_comp_zero, true)
	--SOL__set_config("nerd__sky_adjust", "AnisotropicIntensity", 1.00 - 0.60 * duskdawn_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "GradientStyle", math.lerp(0.5 + 0.3*sun_comp_zero, 1, weather__get_overcast()), true)

	-- try to make stars brightness more realistic
	SOL__set_config("night", "starlight_multiplier", (0.25 + 0.002 * AE), true)

	local auto_bounced_light = math.min(1, math.pow(math.max(0,AE*0.10 + 0.25*(1-sun_comp_zero) + CamOcclusion), 1.5))
	SOL__set_config("nerd__csp_lights_adjust", "emissive_day", (math.max(0, math.min(1, 0.30 + 0.40 * auto_bounced_light))))
	SOL__set_config("nerd__csp_lights_adjust", "bounced_day",  (math.max(0, math.min(1, 0.00 + 1.00 * auto_bounced_light))))


	-- This only works if tonemapping is set to function 2 !!!
	ac.setPpTonemapFilmicContrast( 0.42
								 - 0.30 * overcast * twilight_comp_zero
								 + 0.20 * weather__get_badness() * twilight_comp_zero
								 -- hdr_drift
								 )

	local gamma = (0.925-0.085*sun_curve_steep)
				- peak_brightness_factor				 
				- 0.030 * overcast * sun_comp_zero
				- 0.15 * weather__get_badness()
				-- this helps with visibility in the transition of day to night
				+ 0.05 * night_compensate(0)
				
	ac.setPpTonemapGamma(gamma)

	local brightness = 1.25
					 - (4.5*peak_brightness_factor)
					 + 1.00 * night_compensate(0)
					 + (0.40+0.01*day_compensate(0))*math.pow(AE, 1 / math.max(0.5, math.min(1, AE))) -- for very bright light, lower brightness more
					 - 0.0 * weather__get_badness()
					 + 0.30 * weather__get_overcast() * twilight_comp_zero
	ac.setPpBrightness(brightness)

	local contrast = (0.9925 - 0.0025*sun_curve_steep)
				   -- do some more contrast with overcast/cloud shadow and bad weather
				   + 0.0025 * overcast * (1-0.75*weather__get_badness()) * sun_comp_zero
				   -- 0.0005 * (1-twilight_comp_zero)
	ac.setPpContrast(contrast)

	ac.setPpSepia(0)
	ac.setPpSaturation(1.10 + 0.05 * night_compensate(0)) -- adjust saturation for logarithmic tonemapping
	

	local WB_ratio = ac.getPpColorTemperatureK()/math.max(0.01, ac.getPpWhiteBalanceK())
								 -- colortemperature
	local AE_WB_comp = math.max(0, negative_pow(AE-2.4, 0.5))
	local color_temp = (6250 + (__IntD(-100*sun_curve_steep,100))*solHDR__WHITE_POINT_PRECISION*(1-overcast)*sun_comp_zero) *
						math.max(__IntD(0.97, 1-0.099*solHDR__WHITE_POINT_PRECISION, 0.6),
						(1 - math.min(0.1, 0.02*cloud_shadow_mod + 0.105*weather__get_overcast())) * -- achieve neutral colors with overcast weather
						(1+(0.10*night_compensate(0))) *
						(1-0.025*AE_WB_comp*(0.25+1.25*twilight_comp_zero*(1-0.50*cloud_shadow_mod))) -- adapt colorbalance with low light
						)
	ac.setPpColorTemperatureK( color_temp )

	-- adapt hue a little bit for overcast weather
	local hue = -2 + math.min(1.0, math.max(-1, (WB_ratio-1)*-100)) * overcast * twilight_comp_zero
	ac.setPpHue(hue)


	--ac.setPpColorGradingIntensity(ü(math.max(0, math.min(1, __IntD(-1.5,2.0,0.5))))) 

	--adapt fake shadow
	ac.setWeatherFakeShadowOpacity(0.85 + (0.30) * sun_comp_zero)
	ac.setWeatherFakeShadowConcentrarion(0.75 + 0.25 * day_compensate(0) - (0.65+0.01*AE) * sun_comp_zero)

	if SOL__config("debug", "custom_config") then
		-- show the main drift of Whitbalance
		ac.debug("CC", string.format('Bright %.2f, Gamma %.2f, AE %.2f, WB %.3f', brightness, gamma, AE, WB_ratio) )
	end


	ac.setGlareBloomFilterThreshold(0.01) --values higher than 0.1 will not work, with 0.1 you should see a blue bloom
	-- set GLARE shape to "Standard" to be sure star is processed
	-- make a FOV dependency of the star
	ac.setGlareStarFilterThreshold(_l_FOV_LUT_r[2]) 
end