#define DRKSC_CORE_PI 3.14159265359

float sin_gt_pos(float pos, float speed, float power, float time) {
    return float(pow((sin(pos / 8.0 * DRKSC_CORE_PI + time * speed) + 1) / 2, power));
}

float blob(float size, vec3 pos, float speed, vec3 direction, float time) {
    return sin_gt_pos(pos.x, direction.x * speed, size, time) * sin_gt_pos(pos.z, direction.z * speed, size, time) + sin_gt_pos(pos.z, direction.z * speed, size, time) * sin_gt_pos(pos.z, direction.z * speed, size, time) * sin_gt_pos(pos.x, direction.x * speed, size, time);
}

vec4 lava_modulated(vec3 coord, float time) {
    float blob0 = 0.3 * blob(5.0, coord, 500, vec3(1.0, -0.2, 0.7), time);
    float blob1 = 0.6 * blob(10.0, coord, 740, vec3(-1.0, 0.4, -0.7), time);
    float blob2 = 0.1 * blob(2.0, coord, 460, vec3(0.9, 0.8, 0.4), time);
    float blob3 = 0.5 * blob(6.0, coord, 710, vec3(-0.8, -0.5, 1.0), time);
    float blob4 = 0.1 * blob(8.0, coord, 620, vec3(-0.4, 0.4, 0.4), time);
    float blob5 = 0.3 * blob(1.0, coord - vec3(6.0), 550, vec3(0.8, 0.4, 0.4), time);
    float blob6 = 0.1 * blob(1.0, coord, 500, vec3(-0.2, -0.3, 1.0), time);
    float blob7 = 0.4 * blob(2.0, coord - vec3(8.0), 630, vec3(0.9, 0.1, 0.4), time);

    vec3 col = vec3(0.8 + blob0 + blob1 + blob2 + blob3 + blob4 + blob5 + blob6 + blob7);

    vec4 color = vec4(col, 1.0);

    if (color.r >= 1.2) {
        return color;
    }

    //color.r += 1.0 - pow(color.r, 4.0);
    float gBase = color.g - 0.2;
    color.g = (gBase * gBase * gBase) + 0.2;

    float bBase = color.b - 0.2;
    color.b = (bBase * bBase * bBase) + 0.2;

    return color;
}

vec4 sin_pattern(vec3 coords, float time) {
    return vec4(0.5 + 0.5 * sin(coords.x * DRKSC_CORE_PI),
                0.5 + 0.5 * sin(coords.y * DRKSC_CORE_PI),
                0.5 + 0.5 * sin(coords.z * DRKSC_CORE_PI), 1.0);
}




vec2 noise2x2(vec2 p) {
    float x = dot(p, vec2(123.4, 234.5));
    float y = dot(p, vec2(345.6, 456.7));
    vec2 noise = vec2(x, y);
    noise = sin(noise);
    noise *= 43758.5353;
    noise = fract(noise);
    return noise;
}

int index(int x, int y) {
    return y * 3 + x; // can be used to extract or write to or from the "matrix"
}

float calcVoroNoiseValue(vec2 position, float time) {
    vec2 pos = position * 128.0; // Position in 'Sub-Pixeln' oder Noise-Einheiten
    vec2 currentGridId = floor(pos / 16.0); // Die ID der Zelle, in der wir sind

    float lowestDistance = 1000.0; // Startwert hoch setzen

    // Standard 3x3 Neighbor Loop
    for (int y = -1; y <= 1; y++) {
        for (int x = -1; x <= 1; x++) {
            // 1. Wir bestimmen die ID der Nachbarzelle
            vec2 neighborGridId = currentGridId + vec2(float(x), float(y));

            // 2. Wir berechnen den zufälligen Versatz DIESER Nachbarzelle
            // Wichtig: Wir nutzen neighborGridId für den Zufall, nicht pos!
            
            // Dazu brauchen wir eine angepasste gridPointVersatz Logik oder wir machen es direkt hier:
            // Wir simulieren deinen gridPointVersatz inline für die Korrektheit:
            
            // Deine noise2x2 Logik basierte auf fract(indexPos... + floor). 
            // Wir vereinfachen das für Stabilität:
            
            vec2 noiseInput = neighborGridId / 8.0; // Skalierung beibehalten wie im Original
            vec2 randomOffset = noise2x2(fract(noiseInput));
            
            // Der Punkt in Weltkoordinaten:
            // Zellen-Start (ID * 16) + Basis-Offset (wir nehmen mal die Mitte) + Zufalls-Bewegung
            vec2 cellOrigin = neighborGridId * 16.0;
            
            // Dein Original hatte einen komplexen 'index' Versatz (mod index 3 etc).
            // Das ist für Voronoi eigentlich unnötig kompliziert. 
            // Ein einfacher 'sin' Schwinger reicht für Lava:
            vec2 animate = sin(time * randomOffset * 2.0) * 6.0; 
            
            vec2 pointPos = cellOrigin + vec2(8.0) + animate; // +8.0 um es in der Mitte der 16er Zelle zu zentrieren

            float dist = length(pointPos - pos);
            if (dist < lowestDistance) {
                lowestDistance = dist;
            }
        }
    }

    return lowestDistance * 0.0625;
}

float VoronoiNoise(vec3 posInEightChunks, float time) {
    float value = calcVoroNoiseValue(posInEightChunks.xz, time * 400);
    return value;
}




vec2 quintic(vec2 p) {
  return p * p * p * (10.0 + p * (-15.0 + p * 6.0));
}

vec2 randomGradient(vec2 p, float time) {
  p = p + 0.02;
  float x = dot(p, vec2(123.4, 234.5));
  float y = dot(p, vec2(234.5, 345.6));
  vec2 gradient = vec2(x, y);
  gradient = sin(gradient);
  gradient = gradient * 43758.5453;

  gradient = sin(gradient + time);
  return gradient;
}

float calcPerlinNoiseValue(vec2 pos, float time, int size) {
    vec2 coordInChunk = pos * size;
    vec2 gridId = floor(coordInChunk);
    vec2 gridUv = fract(coordInChunk);


    // corners, mod to make a repeating pattern
    vec2 bl = mod(gridId + vec2(0.0, 0.0), size);
    vec2 br = mod(gridId + vec2(1.0, 0.0), size);
    vec2 tl = mod(gridId + vec2(0.0, 1.0), size);
    vec2 tr = mod(gridId + vec2(1.0, 1.0), size);
    

    // random gradient for each grid corner
    vec2 gradBl = randomGradient(bl, time);
    vec2 gradBr = randomGradient(br, time);
    vec2 gradTl = randomGradient(tl, time);
    vec2 gradTr = randomGradient(tr, time);

    // distances
    vec2 distFromPixelToBl = gridUv - vec2(0.0, 0.0);
    vec2 distFromPixelToBr = gridUv - vec2(1.0, 0.0);
    vec2 distFromPixelToTl = gridUv - vec2(0.0, 1.0);
    vec2 distFromPixelToTr = gridUv - vec2(1.0, 1.0);

    // dots
    float dotBl = dot(gradBl, distFromPixelToBl);
    float dotBr = dot(gradBr, distFromPixelToBr);
    float dotTl = dot(gradTl, distFromPixelToTl);
    float dotTr = dot(gradTr, distFromPixelToTr);

    // smooth uv
    gridUv = quintic(gridUv);

    // mix colors
    float b = mix(dotBl, dotBr, gridUv.x);
    float t = mix(dotTl, dotTr, gridUv.x);
    float perlin = mix(b, t, gridUv.y);


    return perlin;
}

float PerlinNoise(vec3 posInEightChunks, float time, int size) {
    float value = calcPerlinNoiseValue(posInEightChunks.xz, time * 500, size);
    return value;
}

float blendPegtopSoftLight(float base, float blend) {
    return (1.0 - 2.0 * blend) * base * base + 2.0 * blend * base;
}

vec4 lavaNoiseSim(vec3 posInEightChunks, float time) {
    float vN = 1.0 - clamp(VoronoiNoise(posInEightChunks, time), 0.0, 1.0);
    float pN0 = clamp(PerlinNoise(posInEightChunks, time, 16), 0.0, 1.0);
    float pN1 = clamp(PerlinNoise(posInEightChunks, time, 32), 0.0, 1.2);
    float pN2 = clamp(calcPerlinNoiseValue(posInEightChunks.xy, time * 500, 16), 0.0, 1.0);

    // blend

    float blended0 = blendPegtopSoftLight(vN, pN0);
    float blended = mix(blendPegtopSoftLight(blended0, pN1), blended0, 0.8);

    // color correct

    vec3 color = vec3(blended);
    vec3 lum = clamp(color * 1.5, 0.0, 1.0);
    vec3 corrected = 1.0 - clamp(pow(1.0 - lum, vec3(2.0)), 0.0, 1.0);
    vec3 colorClamped = ceil(corrected * 12.0) / 12.0;
    float r = 1.0 - clamp(pow(1.0 - colorClamped.r, 4.0), 0.0, 1.0);
    colorClamped.r = r;

    return vec4(colorClamped, 1.0);
}

float luminance(vec3 c) {
    return 0.2126 * c.r + 0.7152 * c.g + 0.0722 * c.b;
}