// Shmup Shader
// by Katsuomi Kobayashi (@KatsuomiK)
// http://framesynthesis.com/

#ifdef GL_ES
precision mediump float;
#endif

uniform float time;
uniform vec2 mouse;
uniform vec2 resolution;

#define SCREEN_W 0.7
#define SCROLL_SPEED 0.1

#define BLINK_INTERVAL 0.06
float blink = mod(time, BLINK_INTERVAL) / BLINK_INTERVAL;

vec2 p;

vec2 myfighter_pos;

float rand(vec2 co)
{
       return fract(sin(dot(co.xy ,vec2(12.9898, 78.233))) * 43758.5453);
}

float linear_map(float value, float s0, float s1, float d0, float d1)
{
       return d0 + (value - s0) * (d1 - d0) / (s1 - s0);
}

void set_myfighter_pos()
{
       myfighter_pos = mouse.xy - vec2(0.5, 0.5);

       float n = floor(time * 2.0);
       float t = fract(time * 2.0);

       float x0 = linear_map(rand(vec2(n, 0)), 0.0, 1.0, -0.3, 0.3);
       float x1 = linear_map(rand(vec2(n + 1.0, 0)), 0.0, 1.0, -0.3, 0.3);
       float y0 = linear_map(rand(vec2(0, n)), 0.0, 1.0, -0.4, -0.1);
       float y1 = linear_map(rand(vec2(0, n + 1.0)), 0.0, 1.0, -0.4, -0.1);

       float x = linear_map(t, 0.0, 1.0, x0, x1);
       float y = linear_map(t, 0.0, 1.0, y0, y1);

       myfighter_pos.x = x;
       myfighter_pos.y = y;
}

vec3 background()
{
       float interval = 0.1;
       float thick = 0.005;
       vec3 color = vec3(0.0, 0.2, 0.4);

       if (mod(p.y + time * SCROLL_SPEED, interval) < thick || mod(p.x, interval) < thick) {
               return color;
       }
       return vec3(0);
}

vec2 get_boss_pos(float offset)
{
       float x = sin(time - offset) * 0.2;

       return vec2(x, 0.35);
}

vec3 bullet(vec2 v, float t)
{
       vec2 pos = get_boss_pos(t) + v * t;

       if (length(p - pos) < 0.006) {
               return vec3(1);
       }
       if (length(p - pos) < 0.01) {
               return vec3(1, 0.4, 0.3);
       }
       return vec3(0);
}

vec3 myfighter(vec2 pos)
{
       float radius = 0.03;

       float dx = pos.x - p.x;
       float dy = pos.y - p.y;

       int px = int(floor(abs(dx) / 0.02));
       int py = int(floor(dy / 0.02));

       bool pixel = false;

       if (px == 0) {
               if (py >= -1 && py <= 1) {
                       pixel = true;
               }
       }
       if (px == 1) {
               if (py >= 1 && py <= 2) {
                       pixel = true;
               }
       }

       if (pixel) {
               return vec3(1, 1, 1);
       }
       return vec3(0);
}

float get_laser_hit_y()
{
       if (abs(myfighter_pos.x - get_boss_pos(0.0).x) < 0.09) {
               return 0.3;
       }
       return 2.0;
}

vec3 laser(vec2 pos)
{
       vec2 boss_pos = get_boss_pos(0.0);

       float a = 0.003 + blink * 0.004;

       float d;

       if (p.y > myfighter_pos.y && p.y < get_laser_hit_y()) {
               d = abs(p.x - pos.x);
       } else {
               d = length(p - pos);
       }
       float n = a / (d * 3.0);

       return vec3(2, 2, 5) * n;
}

vec3 laser_hit_effect()
{
       vec2 pos = vec2(myfighter_pos.x, get_laser_hit_y());

       float a = 0.02 + blink * 0.02;

       float d = length(p - pos);
       float n = a / (d * 5.0);

       return vec3(2, 2, 5) * n;
}

vec3 boss()
{
       vec2 pos = get_boss_pos(0.0);

       bool pixel = false;

       float dx = pos.x - p.x;
       float dy = pos.y - p.y;

       int px = int(floor(abs(dx) / 0.02));
       int py = int(floor(dy / 0.02));

       if (px >= -5 && px <= 5) {
               if (py >= -5 && py <= 3) {
                       if (rand(vec2(px, py)) > 0.5) {
                               pixel = true;
                       }
               }
       }

       if (pixel) {
               if (abs(myfighter_pos.x - pos.x) < 0.08 && blink > 0.5) {
                       return vec3(1);
               }
               return vec3(1, 0.5, 0);
       }
       return vec3(0);
}

void main(void)
{
       p = (gl_FragCoord.xy - resolution * 0.5) / resolution.y;

       if (abs(p.x) > SCREEN_W / 2.0) {
               discard;
       }

       set_myfighter_pos();

       vec3 c = background();

       c += boss();

       for (int i = -4; i <= 2; i++) {
               float t = fract(time * 0.5 + float(i) * 0.03);
               vec2 v = normalize(vec2(float(i) * 0.1, -1.0));
               c += bullet(v, t);
       }

       for (int i = -2; i <= 4; i++) {
               float t = fract(time * 0.5 + 0.5 + float(i) * -0.03);
               vec2 v = normalize(vec2(float(i) * 0.1, -1.0));
               c += bullet(v, t);
       }

       c += myfighter(myfighter_pos);
       c += laser(myfighter_pos);
       c += laser_hit_effect();

       gl_FragColor = vec4(c, 1);
}