// === combine === @vs vs_combine const vec2 positions[4] = { vec2(-1, 1), vec2(1, 1), vec2(1, -1), vec2(-1, -1) }; const vec2 uvs[4] = { vec2(0, 1), vec2(1, 1), vec2(1, 0), vec2(0, 0) }; const int indices[6] = { 0, 1, 2, 0, 2, 3 }; layout(binding=0) uniform Game { vec2 screen; vec2 cam; }; out vec2 uv; void main() { int idx = indices[gl_VertexIndex]; vec2 pos = positions[idx]; uv = uvs[idx]; gl_Position = vec4(pos, 1, 1); } @end @fs fs_combine layout(binding=0) uniform texture2D tex_tex; layout(binding=1) uniform texture2D tex_shadow; layout(binding=2) uniform texture2D tex_light; layout(binding=0) uniform sampler smp; in vec2 uv; out vec4 frag_color; void main() { vec4 tb = vec4(0.8,0.3,0.3,1); if (mod(floor(uv.x*10), 2) != mod(floor(uv.y*10),2)) { tb = vec4(0.3,0.3,0.8,1); } vec4 tt = texture(sampler2D(tex_tex, smp), uv); vec4 ts = texture(sampler2D(tex_shadow, smp), uv); vec4 tl = texture(sampler2D(tex_light, smp), uv); vec3 l = tt.a * (tt.rgb * tl.rgb) + (1-tt.a) * (tl.rgb * tl.a); l = ts.a * (l * ts.rgb) + (1-ts.a) * (l); frag_color = vec4(l, 1); vec3 a = (tb.rgb + tl.rgb) * tt.rgb * ts.rgb; // + tl.rgb * tl.a; frag_color = vec4(a, 1); vec3 bg = tb.rgb * tl.rgb; vec3 bg_s = bg * (1-ts.a) + bg * ts.rgb * 0.5 * ts.a; vec3 t = tt.rgb * tl.rgb; vec3 t_s = t * (1-ts.a) + t * ts.rgb * 0.5 * ts.a; vec3 bg_s_t_s = bg_s * (1-tt.a) + t_s * tt.a; frag_color = vec4(bg_s_t_s, 1); // frag_color = vec4(tl); } @end @program combine vs_combine fs_combine // === tex === @vs vs_tex const vec2 positions[4] = { vec2(0, 1), vec2(1, 1), vec2(1, 0), vec2(0, 0) }; const vec2 uvs[4] = { vec2(0, 0), vec2(1, 0), vec2(1, 1), vec2(0, 1) }; const int indices[6] = { 0, 1, 2, 0, 2, 3 }; layout(binding=0) uniform Game { vec2 screen; vec2 cam; }; in vec2 inst_pos; in ivec2 inst_size; out vec2 uv; void main() { int idx = indices[gl_VertexIndex]; vec2 pos = positions[idx]; uv = uvs[idx]; vec2 inst_pos_abs = inst_pos + inst_size * pos - cam - screen / 2; gl_Position = vec4(inst_pos_abs / screen * 2, 1, 1); } @end @fs fs_tex layout(binding=0) uniform texture2D tex; layout(binding=0) uniform sampler smp; in vec2 uv; out vec4 frag_color; void main() { vec4 tex_color = texture(sampler2D(tex, smp), uv); if (tex_color.a < 1) discard; frag_color = tex_color; } @end @program tex vs_tex fs_tex // === shadows === @vs vs_shadow const vec2 positions[3] = { vec2(0, 1), vec2(1, 1), vec2(0.5, 0) }; const vec2 uvs[3] = { vec2(0, 0), vec2(1, 0), vec2(0.5, 1) }; layout(binding=0) uniform Game { vec2 screen; vec2 cam; }; layout(binding=1) uniform Light { vec3 color; vec2 pos; float reach; float radius_glow; float intensity; float shadow_brightness; } light; in vec2 inst_pos; in ivec2 inst_size; out vec2 uv; out vec3 light_color; out float shadow_brightness; // https://gist.github.com/yiwenl/3f804e80d0930e34a0b33359259b556c vec2 rotate(vec2 v, float a) { float s = sin(a); float c = cos(a); mat2 m = mat2(c, s, -s, c); return m * v; } void main() { int idx = gl_VertexIndex; vec2 pos = positions[idx]; uv = uvs[idx]; light_color = light.color; shadow_brightness = light.shadow_brightness; if (idx == 2) { // keep pos for base vec2 inst_pos_abs = inst_pos + inst_size * pos - cam - screen / 2; gl_Position = vec4(inst_pos_abs / screen * 2, 1, 1); } else { vec2 anchor = vec2(0.5, 0); vec2 anchor_abs = inst_pos + inst_size * anchor - cam - screen / 2; vec2 light_pos_abs = light.pos - cam - screen / 2; vec2 dir = anchor_abs - light_pos_abs; vec2 left_right[] = { rotate(dir, 1.5708), rotate(dir, -1.5708), }; float light_radius_factor = 1.5 / log(light.reach); vec2 inst_pos_abs = anchor_abs + dir + left_right[idx] * light_radius_factor; gl_Position = vec4(inst_pos_abs / screen * 2, 1, 1); } } @end @fs fs_shadow layout(binding=0) uniform texture2D tex; layout(binding=0) uniform sampler smp; in vec2 uv; in vec3 light_color; in float shadow_brightness; out vec4 frag_color; vec3 brighten(vec3 c, float f) { vec3 d = vec3(1) - c; return c + d * f; } vec4 blur(float radius, float resolution) { float blur = radius/resolution; float hstep = 1; float vstep = 1; vec4 sum = vec4(0.0); sum += texture(sampler2D(tex, smp), vec2(uv.x - 4.0*blur*hstep, uv.y - 4.0*blur*vstep)) * 0.0162162162; sum += texture(sampler2D(tex, smp), vec2(uv.x - 3.0*blur*hstep, uv.y - 3.0*blur*vstep)) * 0.0540540541; sum += texture(sampler2D(tex, smp), vec2(uv.x - 2.0*blur*hstep, uv.y - 2.0*blur*vstep)) * 0.1216216216; sum += texture(sampler2D(tex, smp), vec2(uv.x - 1.0*blur*hstep, uv.y - 1.0*blur*vstep)) * 0.1945945946; sum += texture(sampler2D(tex, smp), vec2(uv.x, uv.y)) * 0.2270270270; sum += texture(sampler2D(tex, smp), vec2(uv.x + 1.0*blur*hstep, uv.y + 1.0*blur*vstep)) * 0.1945945946; sum += texture(sampler2D(tex, smp), vec2(uv.x + 2.0*blur*hstep, uv.y + 2.0*blur*vstep)) * 0.1216216216; sum += texture(sampler2D(tex, smp), vec2(uv.x + 3.0*blur*hstep, uv.y + 3.0*blur*vstep)) * 0.0540540541; sum += texture(sampler2D(tex, smp), vec2(uv.x + 4.0*blur*hstep, uv.y + 4.0*blur*vstep)) * 0.0162162162; return sum; } void main() { vec4 tex_color = blur(10, 1); tex_color = texture(sampler2D(tex, smp), uv); vec3 brighter = brighten(light_color, shadow_brightness); frag_color = vec4(brighter * tex_color.a + vec3(1) * (1-tex_color.a), tex_color.a); } @end @program shadow vs_shadow fs_shadow // === lights === @vs vs_light const vec2 positions[4] = { vec2(-0.5, 0.5), vec2(0.5, 0.5), vec2(0.5, -0.5), vec2(-0.5, -0.5) }; const int indices[6] = { 0, 1, 2, 0, 2, 3 }; layout(binding=0) uniform Game { vec2 screen; vec2 cam; }; layout(binding=1) uniform Light { vec3 color; vec2 pos; float reach; float radius_glow; float intensity; float shadow_brightness; } light; out vec3 light_col; out vec2 light_pos; out float light_rea; out float light_glo; out float light_intensity; out vec2 fragpos; void main() { int idx = indices[gl_VertexIndex]; vec2 pos = positions[idx]; vec2 inst_pos_ap = light.pos + light.reach * 2 * pos; vec2 inst_pos_rp = inst_pos_ap - cam - screen / 2; vec2 inst_pos_rw = inst_pos_rp / screen * 2; gl_Position = vec4(inst_pos_rw, 1, 1); light_col = light.color; light_pos = light.pos; light_rea = light.reach; light_glo = light.radius_glow; light_intensity = light.intensity; fragpos = inst_pos_ap; } @end @fs fs_light layout(binding=0) uniform Game { vec2 screen; vec2 cam; }; in vec3 light_col; in vec2 light_pos; in float light_rea; in float light_glo; in float light_intensity; in vec2 fragpos; out vec4 frag_color; float dist(vec2 a, vec2 b) { float d1 = a.x - b.x; float d2 = a.y - b.y; return sqrt(d1*d1 + d2*d2); } void main() { // vec2 frag_coord_abs = gl_FragCoord.xy * v_screen + v_cam + v_screen / 2; // float factor = dist(light_pos, frag_coord_abs) / light_rad; float factor_rea = 1 - (dist(light_pos, fragpos) / light_rea); float factor_glo = 1 - (dist(light_pos, fragpos) / light_glo); if (factor_rea > 1.0) discard; frag_color = vec4(light_col.rgb * factor_rea, factor_glo * light_intensity); // frag_color = vec4(vec3(mod(factor, 1.0)) * light_col, factor); } @end @program light vs_light fs_light