-- 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, 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,  2.50 } n=n+1
_l_AE_LIMIT_LUT[n] = {   90, 0.01,  2.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_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.72, true)

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

-- 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__sun_adjust", "ls_Saturation", 0.90 + 0.30 * sun_curve, true)
	SOL__set_config("nerd__sun_adjust", "ls_Level", 0.95 + 0.30 * sun_curve, true)
	SOL__set_config("nerd__speculars_adjust", "Level", (1.0 - 0.1 * sun_compensate(0)), 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.75 + 0.60*night_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)

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

	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(1.3 + 0.8 * sun_compensate(0) + 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))
		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]*from_twilight_compensate(0)))
		
		CamOcclusion = 1 - 0.50*ac.getCameraOcclusion(vec3(0,1,0)) - 0.50*ac.getCameraLookOcclusion()

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

		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

		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

					- __IntD(0.130, 0, 0.6) -- adapt AE to sunangle
					- 0.200*(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.200*weather__get_badness()*day_compensate(0) 

					-- lower it a little bit in cloud shadows
					- 0.050*overcast
		
					-- 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)
					))

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

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

	SOL__set_config("nerd__sky_adjust", "Level", 1.00 + (0.2 - 0.50 * overcast) * duskdawn_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "Saturation", 1.00 + (0.35 - 0.35 * overcast) * duskdawn_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "AnisotropicIntensity", 1.00 - 0.60 * duskdawn_compensate(0), true)
	SOL__set_config("nerd__sky_adjust", "GradientStyle", 0.60 + 0.40*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-2.4)*0.055 + 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))))

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

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

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

	local brightness = 1--0.5
					-- + 0.55 * night_compensate(0)
					-- + (0.10+0.40*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()
	ac.setPpBrightness(brightness)

	local contrast = 1.00
				   -- do some more contrast with overcast/cloud shadow and bad weather
				   + 0.025 * overcast * (1-0.75*weather__get_badness()) * sun_compensate(0)
	ac.setPpContrast(contrast)

	ac.setPpSepia(0)
	ac.setPpSaturation(0.98 + 0.03 * 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 *
						math.max(__IntD(0.97, 0.925, 0.7),
						(1 - math.min(0.08, 0.025*cloud_shadow_mod + 0.05*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*from_twilight_compensate(0)*(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 = math.min(1.5, math.max(-1, (WB_ratio-1)*-100)) * overcast * from_twilight_compensate(0)
	ac.setPpHue(hue)

	ac.setPpColorGradingIntensity(( 0.25
								  + 0.35 * overcast * (1-weather__get_badness())
								) *sun_compensate(0))

	--adapt fake shadow
	ac.setWeatherFakeShadowOpacity(0.85 + (0.30) * sun_compensate(0))
	ac.setWeatherFakeShadowConcentrarion(0.75 + 0.25 * day_compensate(0) - (0.65+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


	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