// define a custom data type to hold info about the rings
struct Ring {
    float index;
    float radOut;
    float radIn;
    float squishVal;
    vec2 trans;
    vec2 offset;
    float scale;
};
// build arrays to hold info about the ring colors and gaps
const int NUM_RINGS = 7;
vec3 colRings[NUM_RINGS];
Ring rings[NUM_RINGS]; // array of our custom data type
const int MAX_GAPS = 6;
float ringGaps[NUM_RINGS * MAX_GAPS]; // pseudo multi-dimensional array

const float logo_y = 0.15; // constants defined globally like this can be used anywhere in the main.glsl file

// a void function with no inputs. it does its work by reading and writing to the global variables we defined. this is just a way to organize code
void initRings() {
    // here we're defining the logo rings using our custom type
    // this array structure will be easy to loop through later on
    float dilate_scaler = 0.5 + 0.3*syn_Presence;
    rings[0] = Ring(1.0, 0.45, 0.405, 0.92, vec2(0.0,-0.01), ring_off1, 1-.2*ring_dil1*dilate_scaler);
    rings[1] = Ring(2.0, 0.38, 0.34, 0.925, vec2(0.0,-0.01), ring_off2, 1-.3*ring_dil2*dilate_scaler);
    rings[2] = Ring(3.0, 0.33, 0.29, 0.95, vec2(0.0,-0.005), ring_off3, 1-.4*ring_dil3*dilate_scaler);
    rings[3] = Ring(4.0, 0.281, 0.245, 1.0, vec2(0.002,-0.000), ring_off4, 1-.5*ring_dil4*dilate_scaler);
    rings[4] = Ring(5.0, 0.245, 0.203, 1.0, vec2(0.002,-0.000), ring_off5, 1-.4*ring_dil5*dilate_scaler);
    rings[5] = Ring(6.0, 0.202, 0.167, 1.0, vec2(0.002,-0.000), ring_off6, 1-.3*ring_dil6*dilate_scaler);
    rings[6] = Ring(7.0, 0.1225, 0.094, 1.0, vec2(0.002,-0.000), ring_off7, 1-.4*smoothstep(0.,0.6,ring_dil8)-0.1*ring_dil7*dilate_scaler);
    
    // now we define our ring gaps. OpenGL 3.3 doesn't support multi-dimensional arrays, so we allow up to 6 array slots for each ring to encode up to 3 gaps (start + end)
    // Ring 1 gaps
    ringGaps[0] = 0.16; ringGaps[1] = 0.34; ringGaps[2] = 0.585; ringGaps[3] = 0.92;
    // Ring 2 gaps
    ringGaps[6] = 0.14; ringGaps[7] = 0.365; ringGaps[8] = 0.57; ringGaps[9] = 0.937;
    // Ring 3 gaps
    ringGaps[12] = 0.13; ringGaps[13] = 0.3; ringGaps[14] = 0.57; ringGaps[15] = 0.63; ringGaps[16] = 0.81; ringGaps[17] = 0.844;
    // Ring 4 gaps
    ringGaps[18] = 0.645; ringGaps[19] = 0.9;
    // Ring 5 gaps
    ringGaps[24] = 0.667; ringGaps[25] = 0.965;
    // Ring 6 gaps
    ringGaps[30] = 0.175; ringGaps[31] = 0.49;
    // Ring 7 gaps
    ringGaps[36] = 0.53; ringGaps[37] = 0.88;
}
// defining the eye component "rings" which have slightly different traits
Ring white = Ring(1.0, 0.203, 0.094+syn_BassLevel*0.015+syn_BassPresence*0.015, 1.0, vec2(0.002,-0.000), ring_off6, 1-ring_dil3*.1);
float dilation = smoothstep(0,0.4,ring_dil8)*.35;
Ring pupil = Ring(1.0, 0.093, 0.0, 1., vec2(0.002,-0.000), ring_off7, 1.-dilation);
Ring pupilShine = Ring(0.0, 0.083, 0.053, 1.0, vec2(0.002,-0.000), ring_off7, 1.-dilation);

// generate the mask for a ring
float genRing(Ring ringIn, float modVal, bool modIfTrue) {
    float retVal = 0.0;
    // offset and scale the position
    vec2 pos = _uvc;
    pos.y -= logo_y;
    pos -= ringIn.offset;  // Apply the offset here
    pos *= ringIn.scale;
    // convert to polar coords
    vec2 polPos = _toPolar(2.0*pos*vec2(ringIn.squishVal,1.0)+ringIn.trans);
    float modder = float(modIfTrue);
    vec2 polPos2 = _toPolarTrue(1.5*pos);

    // audio reactive variances
    float pushOut = (1.0+ringIn.index/7.0)*(1.0+ringIn.index/7.0)*syn_MidPresence*syn_MidPresence*0.05*modder;
    float ripples = pow(ringIn.radIn,1.8)*(syn_HighPresence+syn_MidHighPresence)*pow(syn_HighHits,1.7)*_rand(polPos2*vec2(1.0,10.0)+syn_HighTime)*0.1;

    // based on the polar position, the ring position, and the audio reactive variances, did we hit the mask?
    float inner = ringIn.radIn+pushOut+ripples;
    float outer = ringIn.radOut+pushOut+ripples;
    float stepUp = step(inner, polPos.x);
    float stepDown = step(polPos.x, outer);
    retVal = stepUp*stepDown;
    return retVal;
}

// set the appropriate color for each ring
vec3 genRingCols(vec3 ringColsIn[NUM_RINGS], float ringSpacesIn[NUM_RINGS], float whiteSpace) {
    vec3 retCol = vec3(0.0);
    for (int i = 0; i < NUM_RINGS; i++) {
        // if (i!=0) continue;
        vec3 addCol = ringColsIn[i] * ringSpacesIn[i];
        if (length(retCol)<.01) { // this makes the colors stack exclusively
            retCol = addCol;
        }
        whiteSpace = whiteSpace - ringSpacesIn[i];
    }
    // adds the whites of the eye
    retCol += clamp(vec3(1.0)*whiteSpace, vec3(0.0), vec3(1.0));
    return retCol;
}

vec3 renderLogo() {
    initRings();
    
    // synesthesia logo colors
    // to convert a set of 0-255 encoded values to the vec3 ranging from 0-1 that GLSL expects, just divide by 255.0
    colRings = vec3[NUM_RINGS](
        vec3( 46, 191, 239)/255.0,
        vec3( 97, 164, 147)/255.0,
        vec3(102,  84, 164)/255.0, 
        vec3(238,  38, 141)/255.0,
        vec3(245, 135,  56)/255.0,
        vec3(248, 239,  36)/255.0,
        vec3( 46, 191, 239)/255.0
    );
    
    // rename the value provided from script.js
    float rotTime = script_time;
    
    // cut out the ring gaps
    float ringSpaces[NUM_RINGS];
    for (int i = 0; i < NUM_RINGS; i++) {
        vec2 pos = _uvc - vec2(0,logo_y) - rings[i].offset;
        pos *= rings[i].scale;
        vec2 polarPos = _toPolarTrue(pos);
        
        polarPos.y = fract(polarPos.y + mix(rotTime*(0.02*pow(2,i)), floor(rotTime*(0.02*pow(2,i))), pow(1.0-syn_FadeInOut, 3.0+float(i > 2))));
        ringSpaces[i] = genRing(rings[i], 2.11 - 0.3*float(i), true);
        
        int gapIndex = i * MAX_GAPS;
        for (int j = 0; j < MAX_GAPS; j += 2) {
            if (ringGaps[gapIndex + j] != 0.0 && ringGaps[gapIndex + j + 1] != 0.0) {
                if (polarPos.y > ringGaps[gapIndex + j] && polarPos.y < ringGaps[gapIndex + j + 1]) {
                    ringSpaces[i] *= 0.0;
                }
            }
        }
    }
    
    // prepping the inner eye components
    float whiteSpace = genRing(white, 0.0, false);
    float pupilSpace = genRing(pupil, 0.0, false);
    whiteSpace = min(whiteSpace, 1.-pupilSpace);
    float pupilShineSpace = genRing(pupilShine, syn_HighHits+1.0, false);
    float pupilShineGaps[2] = float[2](0.06, 0.2);
    vec2 polarPos = _toPolarTrue(_uvc - vec2(0,logo_y) - rings[6].offset);
    if ((polarPos.y < pupilShineGaps[0]) || (polarPos.y > pupilShineGaps[1])) {
        pupilShineSpace *= 0.0;
    }

    // putting it all together
    vec3 ringCol = genRingCols(colRings, ringSpaces, whiteSpace);
    ringCol += pupilShineSpace;

    return ringCol;
}

vec4 renderMain() {
    if (PASSINDEX == 0.0) {
        // prepare the text lookup coordinates
        vec2 coords = _correctImageCoords(textureSize(text, 0), _uv*4.5-vec2(1.44,0.55)*(4.5/3.7));
        // load the logo text image
        vec4 textColor = texture(text, clamp(coords,0.0,1.0));
        // multiply transparency into the rgb values
        vec3 textCol = textColor.rgb * textColor.a;
        // fade in and out based on audio presence variable
        textCol *= mix(1.0, 0.0, pow(syn_FadeInOut,0.2));
        // run all of the renderLogo logic defined above
        vec3 logoCol = renderLogo();
        // combine the text and logo for display
        // force the alpha to 1, we don't want transparency
        return vec4(logoCol + textCol, 1.0);
    } else if (PASSINDEX == 1.0) {
        // the second pass simply returns the first
        // this is only necessary so that we can do feedback in
        // the first pass without creating glitchy resampling artifacts
        return texture(logoPass, _uv); // "logoPass" is the pass name we defined in the scene config (scene.json). _uv is our current lookup coordinate normalized from 0-1, perfect for texture lookups
    }
}