fragmentShaderSource top-level constant

String const fragmentShaderSource

Implementation

const String fragmentShaderSource = """precision highp float;

// required for all gradients
uniform int gradientType;
uniform vec4 colors[32];
uniform float stops[32];
uniform int gradientStops;
uniform int tileMode;

// required for linear gradient
uniform vec2 gradientStart;
uniform vec2 gradientEnd;

// required for radial gradient
uniform float radius;

// required for sweeping gradient
uniform float bias;
uniform float scale;

// metaball values
uniform vec3 metaballs[138];
uniform int metaballCount;
uniform float minimumGlowSum;
uniform float glowIntensity;
uniform float time;

vec4 noise(vec4 v){
  // ensure reasonable range
  v = fract(v) + fract(v*1e4) + fract(v*1e-4);
  // seed
  v += vec4(0.12345, 0.6789, 0.314159, 0.271828);
  // more iterations => more random
  v = fract(v*dot(v, v)*123.456);
  v = fract(v*dot(v, v)*123.456);
  return v;
}

vec4 getGradientColor(vec2 coords) {
  float t = 0.0;

  if(gradientType == 0) {
    // linear gradient
    float len = length(gradientEnd - gradientStart);
    float dot = dot(
      coords - gradientStart,
      gradientEnd - gradientStart
    );
    t = dot / (len * len);
  } else if(gradientType == 1) {
    // radial gradient
    float len = length(coords - gradientStart);
    t = len / radius;
  } else if(gradientType == 2) {
    // sweep gradient
    vec2 coord = coords - gradientStart;
    float angle = atan(-coord.y, -coord.x);

    t = (angle * 0.1591549430918 + 0.5 + bias) * scale;
  } else {
    // single color
    return colors[0];
  }

  // apply tilemode

  if ((t < 0.0 || t > 1.0) && tileMode == 3) {
    // decal
    return vec4(0);
  } else if (tileMode == 0) {
    // clamp
    t = clamp(t, 0.0, 1.0);
  } else if (tileMode == 1) {
    // repeat
    t = fract(t);
  } else if (tileMode == 2) {
    // mirror
    float t1 = t - 1.0;
    float t2 = t1 - 2.0 * floor(t1 * 0.5) - 1.0;
    t = abs(t2);
  }

  // convert point on gradient to color

  if (gradientStops == 1) {
    return colors[0];
  } else if (gradientStops > 1) {
    vec4 returnColor = colors[0];
    for (int i = 0; i < 32 - 1; i++) {
      if (i < gradientStops - 1) {
        returnColor = mix(returnColor, colors[i + 1], smoothstep(
          stops[i],
          stops[i + 1],
          t
        ));
      } else {
        break;
      }
    }
    return returnColor;
  }
}

void main(){
  vec2 coords = gl_FragCoord.xy;

  float sum = 0.0;

  for (int i = 0; i < 138; i++) {
    if(i < metaballCount) {
      vec3 metaball = metaballs[i];
      float dx = metaball.x - coords.x;
      float dy = metaball.y - coords.y;
      float radius = metaball.z;
      sum += ((radius * radius) / (dx * dx + dy * dy));
    } else {
      break;
    }
  }

  if(sum >= 1.0) {
    gl_FragColor = getGradientColor(coords);
  } else if(sum > minimumGlowSum) {
    float n = ((sum - minimumGlowSum) / (1.0 - minimumGlowSum)) * glowIntensity;
    gl_FragColor = getGradientColor(coords) * n + ((noise(vec4(coords, time, 0.0)) - 0.5) / 255.0);
  } else {
    gl_FragColor = vec4(0, 0, 0, 0);
  }
}""";