
in vec2 uv;
in vec2 uvn;


uniform int prev_gi_tex;
uniform int col_tex;
uniform int norm_mat_tex;
uniform int depth_tex;

layout (location = 0) out vec4 C;


float load_depth(vec2 u){ return depth_to_linear(texFetch(depth_tex,u).x); }
vec3 load_albedo(vec2 u){ return texFetch(col_tex,u).rgb; }
vec3 load_norm_mat(vec2 u, out uint mat){
	uvec4 s = texelFetch(textures_u[norm_mat_tex], ivec2(u),0);
	mat = s.y;
	return i_octahedral_16( s.x );
}

void main(){
	seed = 215125125;
	C = vec4(0);

	vec3 albedo_input = load_albedo(U);
	float depth_input = load_depth(U);  // ------- TOFIX

	uint mat_input;
	vec3 norm_input = load_norm_mat(U, mat_input);

	vec3 col = vec3(0);

	vec2 uv = uv;
//	uv.x *= R.x/R.y;


	#define EPS 0.001
	#define SUN true
	#define SUN_COL vec3(1,0.8,0.6)*50.0

//	var cam = stor.cam;
//	var cam_prev = stor.prev_cam;

	vec3 ro_input;
	vec3 rd_input;
	get_ro_and_rd(ro_input, rd_input, uv, false);
	vec3 ws_pos = ro_input + rd_input * depth_input;
	vec3 ws_pos_input = ws_pos;

	//	var dir_to_sun = DIR_TO_SUN;
	vec3 dir_to_sun = normalize(vec3(2.7 + sin(T),-1,1));



//	atomicAdd(one, 1u);
//	let isnt_env = depth_input < 99.;
	bool isnt_env = depth_input < cam_far - 0.1;
//	let SSGI_RAYS = int(max(custom.SSGI_RAYS*140,1));
	int SSGI_RAYS = int(1);
	bool debug = all(equal(uvec2(U), uvec2(560,240)));

	bool HBIL = true;
	bool INDIRECT = true;

	ivec2 id = ivec2(U);
	uvec2 Ru = uvec2(textureSize(textures[col_tex],0));

	if(debug){
		dbg_print_buff[print_idx].cnt = 0;
	}

	if(!isnt_env){

	} else {
		float hbil_intergal = 0.0;
		float hbil_intergal_b = 0.0;
		vec3 hbil_irradiance_accum = vec3(0);
		float hbil_ao_fac = 0.0;
		if(HBIL){
			for(int ray_idx = 0; ray_idx < SSGI_RAYS; ray_idx++){
				vec3 p = ws_pos + norm_input * EPS;
				vec3 thr = vec3(1);
				vec3 dir_to_cam = normalize(cam_pos - ws_pos);

				float zenith = pi*0.001;
				float azim = 0.7;
				azim += float(ray_idx) / float(SSGI_RAYS) * tau;
//				azim += T;
//				 azim += hash_f_s(uint(F*100 + ray_idx)) * tau / float(SSGI_RAYS)*1.0;
				float n = IGN( vec2(U.xy ) );

				// ------------- DITHER
				n += IGN(vec2(float(F%10),0))*40.;
				n = fract(n);
				azim += n * tau / float(SSGI_RAYS)*1.0;



				vec3 samp = vec3(cos(azim),sin(azim),0.);
				mat3 v = get_orth_mat(cam_pos, cam_pos + cam_dir);
				samp = v * samp;
				vec3 s = samp - dir_to_cam * intersectPlane(samp, -dir_to_cam, norm_input);
				vec3 rd = normalize(s);

				float aspect_ratio = R.y/R.x;

				bool hit = false;

				float ang_accum = 0.0;

				vec2 p_ss_march = world_to_view(p, P, V).xy;

				vec3 rd_dda_ws_start = rd;
				float max_ang = acos(clamp(dot(dir_to_cam,rd_dda_ws_start),-1., 1.0));

				vec2 rd_ss_march = normalize(
					world_to_view(p + rd_dda_ws_start, P, V).xy - p_ss_march
				);


				float step_sz = 4./mix(R.y,R.x, abs(rd_ss_march.x) );


				vec3 rd_ws_temp = rd;
				vec3 samp_ws;

				float dith = IGN(vec2(id.xy));
				// --------------- DITH
				dith += IGN(vec2(float(F%10),0))*40;
				dith = fract(dith);
				// dith = fract(dith + float((time.frame % 10))/10.);
				// dith = 0.;

				int max_iters = 700;
				float prev_st = step_sz;
				for(int k = 0; k < max_iters; k++){
					// p_ss_march += rd_ss_march.xy * (step_sz * (1. + exp(54.*float(k)/float(max_iters))));
					float st = (step_sz * (1. + exp(54.*float(k)/float(max_iters))));
					p_ss_march += rd_ss_march.xy * mix(prev_st, st, dith);
					prev_st = st;
					ivec2 p_proj_i = ivec2(p_ss_march.xy*R.xy);
					uvec2 p_proj_u = uvec2(p_proj_i);

					float depth_tex_samp = load_depth(p_proj_u); // ------- TOFIX
					uint mat_samp;
					vec3 norm_tex_samp = load_norm_mat(p_proj_u, mat_samp);
					Mat mat = get_mat(mat_samp);


					if(debug) {
						//						stor_b.tex[p_proj_i.y][p_proj_i.x] += 0.01;
						dbg_plot_ws(samp_ws);
//						dbg_plot_ss(p_ss_march);
					}
//					vec3 load_albedo(vec2 u){ return texFetch(col_tex,u).rgb; }

					if(
						// out of screen
						any(lessThan(p_proj_i, ivec2(0))) || any(greaterThanEqual( p_proj_i, ivec2(Ru)))
					){
						break;
					} else if (depth_tex_samp < 99.0 ) {
						// -- samp ws get
						vec2 p_norm_uv = p_ss_to_norm_uv(p_ss_march);
//									vec3 ro_samp;
//									vec3 rd_samp;
//			//						get_ro_and_rd(ro_input, rd_input, uv, false);
//									get_ro_and_rd(ro_samp, rd_samp, p_norm_uv, false);
//									samp_ws = cam_pos + rd_samp * depth_tex_samp;
						samp_ws = depth_to_world(linear_to_depth(depth_tex_samp), p_ss_march, V, P);

							// var ro_samp_prev_fr: vec3f;
							// var rd_samp_prev_fr: vec3f;
							// get_ro_and_rd(p_norm_uv, &ro_samp_prev_fr, &rd_samp_prev_fr, prev_cam);
	//						var samp_prev_ss = vec2u(p_ws_to_ss(samp_ws, stor.prev_cam, aspect).xy*R);
						uvec2 samp_prev_ss = uvec2(
							world_to_view(samp_ws, P_prev, V_prev).xy * R
//							p_ws_to_ss(samp_ws, stor.prev_cam, aspect).xy*R
						);

						bool samp_behind = dot(samp_ws - ws_pos, norm_input) < 0.;


						vec3 origin_to_samp = normalize(samp_ws - ws_pos);
						float cos_ang_to_samp = dot(rd_dda_ws_start, origin_to_samp);
						cos_ang_to_samp = clamp(cos_ang_to_samp, -1., 1.0); // unneeded, but why not
						float ang_to_samp = acos(cos_ang_to_samp);


						if(ang_to_samp > ang_accum && !samp_behind){
							rd_ws_temp = origin_to_samp;
							float d_ang = ang_to_samp - ang_accum;
//							if(debug){
//								dbg_plot_ws(samp_ws);
//							}


								// hbil_intergal += abs(cos(ang_to_samp)) * d_ang*0.1;
							float lambert = max(dot(norm_input, origin_to_samp), 0.0);
								// lambert *= lambert;
								// hbil_intergal += abs(cos(ang_to_samp)) * d_ang * lambert;

								// --------- INDIRECT
								// hbil_intergal += pow(abs(cos(ang_to_samp)),1.) * d_ang * lambert;
								// hbil_intergal_b += pow(abs(sin(ang_to_samp)), 1.0) * d_ang;


								// let prev_frame_gi_denoised = textureLoad(pass_in, p_proj_u, 3,0).rgb;
								// var albedo_mat_id: vec4f = load_albedo_and_mat_id(p_proj_u).rgba;
								// var samp_albedo_mul_gi = albedo_mat_id.rgb * prev_frame_gi_denoised.rgb;

							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
//							vec3 samp_albedo_mul_gi =
//								// dbg.prev_frame_gi_mul_albedo[p_proj_u.y][p_proj_u.x];
//								stor_b.prev_frame_gi_mul_albedo[samp_prev_ss.y][samp_prev_ss.x];
//							vec3 samp_albedo_mul_gi = imageLoad(
//								f_images[prev_gi_tex],
//								ivec2(samp_prev_ss)
//							).rgb * mat.albedo*1.;
							vec3 samp_albedo_mul_gi = texelFetch(
								textures[prev_gi_tex],
								ivec2(samp_prev_ss),
								0
							).rgb * mat.albedo*1.;
							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
							// --------- TOFIX --------- //
								// var albedo = get_mat(albedo_mat_id.w).albedo;

								// if(dot(prev_frame_gi_denoised, prev_frame_gi_denoised) > 0.01){
								// if(abs(albedo_and_mat_id.w - 2.0) < 0.001){
							if(INDIRECT){
//								if(dot(origin_to_samp, -norm_tex_samp) > 0.0){
								if(dot(origin_to_samp, -norm_tex_samp) > 0.0){
									hbil_irradiance_accum +=
										1.0
										* samp_albedo_mul_gi
										* d_ang
										* abs(cos(ang_to_samp))
										* lambert
										/ pi;
								}
							}
							//    albedo * prev_frame_gi_denoised *  d_ang*1.0;
							// hbil_intergal += d_ang;
							ang_accum = ang_to_samp;


//							if(debug){
//								print(ang_accum);
//							}
							// -- max ang exit
							if(ang_accum > max_ang){
								ang_accum = min(ang_accum, max_ang);
								if(debug){
									print(3);
								}
								break;
							}
						}


					}

				}
				// env map sample
				{
					// integrate cos(theta)
					{
						if(false){
							// var a = rd;
							// var b = rd_ws_temp;

							// // var ang = acos(dot(a,b));
							// // var ang = acos(dot(a,b));
							// var ang = max_ang - ang_accum;

							// var x = normalize(cross(a,b));
							// var z = normalize(cross(x,a));

							// var lambert_integral = dot(norm_input, (sin(ang) * a + z - z * cos(ang)));
							// lambert_integral = abs(lambert_integral);
							// lambert_integral = max(lambert_integral,0.);

							// var sin_theta_to_eye_integral: float = 0.0;
							// var int_iters: float = 50.0;

							// for(var i = 0.0; i < int_iters; i+=1.0){
							//     var an = mix(ang_accum, max_ang, i/int_iters);
							//     sin_theta_to_eye_integral += abs(cos(an))/int_iters;
							// }

							// hbil_intergal += lambert_integral;

							// ang = mix(max_ang,ang_accum, hash_f());
							// var env_map_dir = cos(ang) * a + sin(ang) * z;

							// var env_map_samp: vec3f = sample_env_map(env_map_dir);
							// col += env_map_samp
							//     * 1.5  * sin_theta_to_eye_integral
							//     * lambert_integral
							//     * ENV_MAP_BRIGHTNESS;
						} else {
							float iters = 15.0;
							vec3 env_integr = vec3(0);

							vec3 a = rd_ws_temp;
							vec3 b = dir_to_cam;
							// a = normalize(a);
							// b = normalize(b);

							// var ang_btw = acos(dot(a,b));
							// var ang = acos(dot(a,b));
							float ang = max_ang - ang_accum;

							vec3 x = normalize(cross(a,b));
							vec3 z = normalize(cross(x,a));

							float ang_to_norm = acos(clamp(dot(dir_to_cam, norm_input),-1.,1.0));

							if(debug){
//								print(ang);
							}

							float d_ang = ang * 1./iters;
							for(float i = 0.0; i < iters; i+=1.){
								float an = ang_accum + ang * i/iters;
								an = ang_accum + hash_f()*ang;
								vec3 p = cos(ang * i/iters) * a + sin(ang * i/iters) * z;

							vec3 env_map_samp = sample_env_map(p, false);


								if (true){
									float theta = acos(
										clamp(abs(dot(dir_to_cam, p)), -1., 1.0)
									);
									theta = an;
									// var _cos = max(cos(theta - ang_to_norm), 0.0001);
									float _cos = (cos(theta - ang_to_norm));
									_cos = max(_cos,0.0);
									_cos = abs(_cos);
									float _sin = abs(sin(theta));


									// var _sin = (cos(mix(ang_accum, max_ang, i/iters)));
									// _sin = abs(_sin);
									// var lamb = max(dot(norm_input, p), 0.0);

									// var d_ang = ang * 1./iters;

									col += d_ang
										* _sin
										* _cos
										// * pow(_sin,1.0)
										// * pow(lamb,1.0)
										* env_map_samp / pi / pi ;

								} else {
//									var _sin = (cos(mix(ang_accum, max_ang, i/iters)));
//									_sin = abs(_sin);
//									var lamb = max(dot(norm_input, p), 0.0);
//
//
//									col += 0.6
//										* d_ang
//										* pow(_sin,1.0)
//										* pow(lamb,1.0)
//										* env_map_samp / pi;
								}
							}
						}
					}
				}
//				bent_norm = mix(bent_norm, rd_ws_temp, 1./(float(ray_idx) + 1.0));
			}
		}
		col += hbil_irradiance_accum;
	}
//	if(isnt_env){
//
//		var bent_norm: vec3f = norm_input;
//var hbil_intergal: float = 0.0;
//var hbil_intergal_b: float = 0.0;
//var hbil_irradiance_accum = vec3f(0);
//var hbil_ao_fac: float = 0.0;
//
//if(!PATHTRACED || HBIL){
//	for(var ray_idx = 0u; ray_idx < uint(SSGI_RAYS); ray_idx += 1u){
//
//		// let debug = all(id.xy == vec2u(350,350));
//		if(HBIL){
//}
	{
		vec3 z = ws_pos_input;
		for(float i = 0; i < 100;i++){
			z += norm_input*0.01;
			if(debug){
				dbg_plot_ws(z);
			}
		}
		if(debug){
//			print_float(5.0);

//			print_v(vec4(-0.6,-0.6,-0.2,0.1));
//			print_float(7.0);
//			print(9.0);
		}
	}

	col /= float(SSGI_RAYS);

	vec3 sun = vec3(0.0);
	// --- sun
//	if(SUN && isnt_env){
//		TraceRes res = trace( ws_pos + norm_input*EPS*10.0, dir_to_sun );
//		bool hit = res.success;
//		float mat_id = res.mat_id;
//		if(!res.success){
//			float lamb = max(dot(norm_input, dir_to_sun), 0.001);
//			sun += SUN_COL*lamb/pi;
//		}
//		// store_gi(id.xy, vec4f(col,1.0));
//		col += sun;
//	}
	// blorba

	{
		vec3 q = ws_pos;
		q.xz *= rot(0.5);
		q.xy *= rot(T);
		if(mod(floor(q.x/0.2), 2.0) < 0.5){
			col += SUN_COL;
		}
	}

	C = vec4(1);
	C.rgb = col;

//	C.rgb = fract(ws_pos.rgb);

//	C = vec4(1)*0.1;
//	C.rgb *= fract(depth_input);

//	C.rgb = norm_input*0.5 + 0.5;
}















































