-- This is just an example, how custom sol config could be used
-- This file must have the same name like your PPFilter and the extension lua

-- For your release version, this file should be placed in the folder /system/cfg/ppfilters/sol_custom_configs/
-- For realtime editing, you can place it in /extension/weather/sol as well.


-- define a LUT (Look Up Table) / The following one is for FOV depandency of Autoexposure
n = 1                  
local _l_FOV_LUT = {}
_l_FOV_LUT[n] = {  0, 0.00, 1.00 } n=n+1
_l_FOV_LUT[n] = { 30, 0.00, 1.00 } n=n+1
_l_FOV_LUT[n] = { 40, 0.15, 1.00 } n=n+1
_l_FOV_LUT[n] = { 50, 0.30, 1.00 } n=n+1
_l_FOV_LUT[n] = { 60, 0.40, 1.00 } n=n+1
_l_FOV_LUT[n] = { 70, 0.50, 1.00 } n=n+1
_l_FOV_LUT[n] = { 80, 0.57, 1.00 } n=n+1
_l_FOV_LUT[n] = { 90, 0.65, 1.00 } n=n+1
_l_FOV_LUT[n] = {180, 0.70, 1.00 } n=n+1
_l_FOV_LUT[n] = {360, 0.70, 1.00 } 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.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {    0, 0.70,  5.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {    5, 0.25,  5.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {   15, 0.05,  5.00 } n=n+1
_l_AE_LIMIT_LUT[n] = {   90, 0.05,  5.00 } 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", 13)
	SOL__set_config("pp", "modify_godrays", true)
	SOL__set_config("pp", "modify_spectrum", true)

	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_day", 0.6)
	SOL__set_config("nerd__csp_lights_adjust", "emissive_night", 0.9)
	
	-- initial values of weatherFX settings
	ac.setWeatherFakeShadowOpacity(1.10)

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

	SOL__set_config("nerd__fog_custom_distant_fog", "use", true)
	SOL__set_config("nerd__fog_custom_distant_fog", "Saturation", 0.75)
	--SOL__set_config("nerd__fog_custom_distant_fog", "Level", 1.25)

	
	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 _l_camFOV = 60
local cam_exterior = false

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

	_l_camFOV = ac.getCameraFOV()
	
	SOL__set_config("nerd__speculars_adjust", "Level", (1.0 - 0.1 * sun_compensate(0)), true)

	SOL__set_config("nerd__sun_adjust", "ls_Level", (1 + 0.125*sun_compensate(0)), true)
	--SOL__set_config("nerd__sun_adjust", "ls_Saturation", (1 + 0.25*sun_compensate(0)), true)

	SOL__set_config("nerd__fog_custom_distant_fog", "exponent", 1.0+1.0*from_twilight_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "Saturation", (1 + 0.20*sun_compensate(0)), true)
	SOL__set_config("nerd__fog_custom_distant_fog", "Level", (2.5 - 1.25*sun_compensate(0)), 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.10*night_compensate(0)) -- raise exposure with night

	exp = exp * math.lerp(math.lerp( exp_at_twilight, exp_at_day, sun_compensate(0)), exp_at_night, night_compensate(0))
	--exp = exp*(12-8*night_compensate(0))
	exp = exp * (1.00 + 0.75*from_twilight_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)

	ac.setPpTonemapMappingFactor(3.5 - 0.5 * night_compensate(0))

	-- 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_compensate(0)

	-- 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))*1.42)
		end
	end
	]]
	local target_multi = SOL_filter__predict_interiorAE()

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

		-- 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)

		-- 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]*from_twilight_compensate(0)))
		
		CamOcclusion = 1 - 0.75*ac.getCameraOcclusion(vec3(0,1,0)) - 0.25*ac.getCameraLookOcclusion()

		target_multi = math.lerp(1, target_multi, from_twilight_compensate(0)*0.75)

		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.75*ac.getCameraOcclusion(vec3(0,1,0)) - 0.25*ac.getCameraLookOcclusion()

		target_multi = 1

		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.05, -- never set this to 0 !
					( 0.40 -- daylight target value

					- 0.050*(1-sun_compensate(0)) -- lower it with setting sun
					- 0.280*(1-from_twilight_compensate(0)) -- lower it for twilight time
					- 0.100*(1-day_compensate(0)) -- lower it for night
					-- all together will set the value for night
					-- 0.4 - 0.1(*1) - 0.1(*1) - 0.17(*1) = 0.03

					-- lower it for bad weather
					- 0.150*weather__get_badness()*from_twilight_compensate(0) 

					-- lower it a little bit in cloud shadows
					- 0.085*cloud_shadow_mod
		
					-- raise it with fog, because fog makes the picture very bright and AE will start
					-- darken the picture, but we want to show bright fog !
					+ 0.100*weather__get_fog_dense()*from_twilight_compensate(0)
					
					-- raise it with overcast, but not with starting twilight and not with bad weather
					-- just to adapt the dark scene like eyes do
					+ 0.150*weather__get_overcast()*(1-0.9*weather__get_badness())*sun_compensate(0)
					))
	
	ac.setAutoExposureTarget(target*target_multi)
	-- 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])


	-- 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-2.4)*0.05 + 0.25*(1-from_twilight_compensate(0)) + CamOcclusion), 1.5))
	SOL__set_config("nerd__csp_lights_adjust", "emissive_day", (math.max(0, math.min(1, 0.6+0.1 * auto_bounced_light))))
	SOL__set_config("nerd__csp_lights_adjust", "bounced_day",  (math.max(0, math.min(1, 0.0+1.0 * auto_bounced_light))))

	SOL__set_config("nerd__sky_adjust", "Level", 1.00 + (0.2 - 0.50 * overcast) * duskdawn_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "AnisotropicIntensity", 1.00 - 0.60 * duskdawn_compensate(0), true)


	local hdr_drift = 0.01*(math.min(AE, 10)-2.4)

	ac.setPpTonemapFilmicContrast( 0.42
								 - 0.30 * overcast * from_twilight_compensate(0)
								 -- 0.00 * weather__get_badness() * from_twilight_compensate(0)
								 -- hdr_drift
								 )

								 --ac.setPpTonemapFilmicContrast(1)

	local gamma = 1.05
				- hdr_drift
				- 0.10 * overcast * sun_compensate(0)
				-- 0.00 * weather__get_badness()
				+ 0.10 * night_compensate(0)
				-- this helps with visibility in the transition of day to night
				+ 0.4 *(1-from_twilight_compensate(0))
				- 0.4 *(night_compensate(0))
	ac.setPpTonemapGamma(gamma)

	local brightness = 1.40
					 + 0.10 * night_compensate(0)
					 + (0.1+0.2*day_compensate(0))*AE
					 - 0.0 * weather__get_badness()
	ac.setPpBrightness(brightness*(1.0))

	local contrast = 1.00
				   + 0.05 * weather__get_overcast() * (1-0.75*weather__get_badness()) * sun_compensate(0)
	ac.setPpContrast(contrast)    ---contrast*(0.90 + (0.10-0.001*AE)*night_compensate(0)))

	ac.setPpSepia(0)
	ac.setPpSaturation(1.18 - 0.01 * night_compensate(0))

	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 *
						(1+(0.10*night_compensate(0))) *
						(1-0.015*AE_WB_comp*(0.25+1.25*from_twilight_compensate(0)*(1-0.50*cloud_shadow_mod)))
	ac.setPpColorTemperatureK( color_temp )

	-- adapt hue a little bit for overcast weather
	local hue = math.max(-1, (WB_ratio-1)*5) * overcast * from_twilight_compensate(0)
	ac.setPpHue(hue)

	--adapt fake shadow
	ac.setWeatherFakeShadowOpacity(0.85 + (0.15) * sun_compensate(0))
	ac.setWeatherFakeShadowConcentrarion(0.75 + 0.25 * day_compensate(0) - (0.55+0.01*AE) * sun_compensate(0))

	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
end