1
2-- needed optimizations
3--
4-- a. only stepframe / update once per frame (don't event-drive from other
5--    states, invalidate + preframe state is ok)
6-- b. synch / track the caster-set rather than rebuild
7-- c. occlusion-pass to filter non-visible
8-- d. use depth buffer?
9-- e. use shadow-map as lookup for each render-output? (awful to write)
10-- f. downscale + blur + upscale + discard full-opaque (or use alpha test)
11-- g. re-use deformed surfaces? (i.e. cloth-drag-window should cast shadow)
12-- h. alpha- only mode
13-- i. draw rt without background in shadow mode, just use rt as shadow map
14--    on composition and just ignore all the rest, but would need depth vals.
15-- j. memory consumption can be reduced with:
16--    https://github.com/mattdesl/lwjgl-basics/wiki/2D-Pixel-Perfect-Shadows
17-- g. just go nuts and go raytrace / gi / radiosity
18-- h. limit (a) to the rate of the output display, (pfp- mask needed in eh)
19--
20
21-- sketch for dynamic shadows,
22--
23-- for both versions we build a rendertarget with the shadow casters,
24-- 1. linearize active space
25-- 2. for each window, use the wnd.width/wnd.height if shadowcaster
26-- 3. draw into dst as opaque
27-- 4. hook to update on each animated frame with window animations
28--
29-- one options is:
30-- raytrace / render into 1D texture based on a point light (cursor)
31--
32-- other option is:
33--  gaussian blur step, draw as overlay and discard opaque
34--
35
36-- we keep the shaders and support script separate from the other
37-- subsystems so that the effects are easier to develop, test and
38-- share outside a full durden setup
39--
40
41local shadow_gaussian_h = [[
42uniform sampler2D map_tu0;
43uniform float obj_opacity;
44uniform vec2 obj_output_sz;
45varying vec2 texco;
46
47float get_alpha(float s, float t, float ra)
48{
49	vec4 cv = texture2D(map_tu0, vec2(s, t));
50	return cv.a; //float(ra > cv.a);
51}
52
53void main()
54{
55	float sum = .0;
56	float blurh = 1.0 / obj_output_sz.x;
57	float ra = texture2D(map_tu0, texco.st).a;
58
59	if (ra < 0.09)
60		discard;
61
62#ifdef PASS2
63	sum += get_alpha(texco.x - 4.0 * blurh, texco.y, ra) * 0.05;
64	sum += get_alpha(texco.x - 3.0 * blurh, texco.y, ra) * 0.09;
65	sum += get_alpha(texco.x - 2.0 * blurh, texco.y, ra) * 0.12;
66	sum += get_alpha(texco.x - 1.0 * blurh, texco.y, ra) * 0.15;
67	sum += get_alpha(texco.x - 0.0 * blurh, texco.y, ra) * 0.16;
68	sum += get_alpha(texco.x + 1.0 * blurh, texco.y, ra) * 0.15;
69	sum += get_alpha(texco.x + 2.0 * blurh, texco.y, ra) * 0.12;
70	sum += get_alpha(texco.x + 3.0 * blurh, texco.y, ra) * 0.09;
71	sum += get_alpha(texco.x + 4.0 * blurh, texco.y, ra) * 0.05;
72#else
73	sum += get_alpha(texco.x, texco.y - 4.0 * blurh, ra) * 0.05;
74	sum += get_alpha(texco.x, texco.y - 3.0 * blurh, ra) * 0.09;
75	sum += get_alpha(texco.x, texco.y - 2.0 * blurh, ra) * 0.12;
76	sum += get_alpha(texco.x, texco.y - 1.0 * blurh, ra) * 0.15;
77	sum += get_alpha(texco.x, texco.y - 0.0 * blurh, ra) * 0.16;
78	sum += get_alpha(texco.x, texco.y + 1.0 * blurh, ra) * 0.15;
79	sum += get_alpha(texco.x, texco.y + 2.0 * blurh, ra) * 0.12;
80	sum += get_alpha(texco.x, texco.y + 3.0 * blurh, ra) * 0.09;
81	sum += get_alpha(texco.x, texco.y + 4.0 * blurh, ra) * 0.05;
82#endif
83
84	float a = float(sum > 1.0);
85	gl_FragColor = vec4(sum, sum, sum, 1.0); // 1.0 * a); // sum > 1.0);
86}
87]];
88
89local shid = build_shader(nil, shadow_gaussian_h, "sgh");
90
91local function tiler_casters(tiler, fx, fy)
92	local lst = {};
93
94-- bin shadow caster order, encode into alpha channel (tradeoff in number
95-- of shadow caster levels) and then use the alpha value in the shader when
96-- doing the blur sampling
97	for j,k in ipairs(tiler.windows) do
98		local props = image_surface_resolve(k.border);
99		local nsrf = color_surface(props.width*fx, props.height*fy, 255, 255, 255);
100
101		if (not valid_vid(nsrf)) then
102			return;
103		else
104			show_image(nsrf);
105			move_image(nsrf, props.x * fx, props.y * fy);
106			blend_image(nsrf, 0.1 + props.order / 100);
107			order_image(nsrf, props.order);
108			force_image_blend(nsrf, BLEND_FORCE);
109			table.insert(lst, nsrf);
110		end
111	end
112
113-- other shadow casters can be added here, e.g. statusbar
114	return lst;
115end
116
117local function build_map(w, h)
118	local surf = alloc_surface(0.3 * w, 0.3 * h);
119
120	define_rendertarget(
121		surf, tiler_casters(active_display(), 0.4, 0.4),
122		RENDERTARGET_DETACH, RENDERTARGET_NOSCALE, 0,
123			bit.bor(RENDERTARGET_COLOR, RENDERTARGET_ALPHA));
124	image_color(surf, 0, 0, 0, 0);
125	order_image(surf, 1000);
126	blend_image(surf, 1.0);
127	resize_image(surf, w, h);
128	rendertarget_forceupdate(surf);
129	image_shader(surf, shid);
130	return surf;
131end
132
133return function()
134	return build_map(active_display().width, active_display().height);
135end
136