//////////////////////////////////////////
// Complementary Shaders by EminGT      //
// With Euphoria Patches by SpacEagle17 //
//////////////////////////////////////////

//Common//
#include "/lib/common.glsl"

//////////Fragment Shader//////////Fragment Shader//////////Fragment Shader//////////
#ifdef FRAGMENT_SHADER

//Pipeline Constants//

//Common Variables//

//Common Functions//

//Includes//

//Program//
void main() {
    discard;
}

#endif

//////////Vertex Shader//////////Vertex Shader//////////Vertex Shader//////////
#ifdef VERTEX_SHADER

//Pipeline Constants//
#if END_CRYSTAL_VORTEX_INTERNAL > 0 || DRAGON_DEATH_EFFECT_INTERNAL > 0 || defined END_PORTAL_BEAM_INTERNAL
    #extension GL_ARB_shader_image_load_store : enable
#endif

//Uniforms//
#if END_CRYSTAL_VORTEX_INTERNAL > 0 || DRAGON_DEATH_EFFECT_INTERNAL > 0 || defined END_PORTAL_BEAM_INTERNAL
    layout(r32i) uniform iimage2D endcrystal_img;
#endif
//Attributes//

//Common Variables//

//Common Functions//

//Includes//

//Program//
void main() {
    #if END_CRYSTAL_VORTEX_INTERNAL > 0 || DRAGON_DEATH_EFFECT_INTERNAL > 0 || defined END_PORTAL_BEAM_INTERNAL
        vec4 position0 = ftransform();
        if (position0.x < 0.0 && position0.y > 0.0) {
            #if END_CRYSTAL_VORTEX_INTERNAL % 2 == 1
                // update temporally stable end crystal data
                for (int index = 0; index < 20; index++) {
                    int state = imageLoad(endcrystal_img, ivec2(index, 8)).r;
                    state -= max(1, int(10000 * frameTime));
                    if (state < 0) {
                        for (int i = 0; i < 5; i++) {
                            imageStore(endcrystal_img, ivec2(index, i+5), ivec4(0));
                        }
                    } else {
                        ivec4 writeData = ivec4(
                            imageLoad(endcrystal_img, ivec2(index, 5)).r,
                            imageLoad(endcrystal_img, ivec2(index, 6)).r,
                            imageLoad(endcrystal_img, ivec2(index, 7)).r,
                            state
                        );
                        writeData.xyz += ivec3(10000 * (previousCameraPosition - cameraPosition));
                        for (int i = 0; i < 4; i++) {
                            imageStore(endcrystal_img, ivec2(index, i+5), ivec4(writeData[i]));
                        }
                        imageStore(endcrystal_img, ivec2(index, 9), ivec4(
                            imageLoad(endcrystal_img, ivec2(index, 9)).r + int(10000 * frameTime)
                        ));
                    }
                }
                // crystals
                for (int index = 0; index < 20; index++) {
                    ivec4 newData = ivec4(
                        imageLoad(endcrystal_img, ivec2(index, 1)).r,
                        imageLoad(endcrystal_img, ivec2(index, 2)).r,
                        imageLoad(endcrystal_img, ivec2(index, 3)).r,
                        imageLoad(endcrystal_img, ivec2(index, 4)).r
                    );
                    if (newData.w > 0) {
                        vec3 pos = vec3(newData.xyz) / newData.w;
                        int temporalIndex = -1;
                        for (int k = 0; k < 20; k++) {
                            ivec4 temporalData = ivec4(
                                imageLoad(endcrystal_img, ivec2(k, 5)).r,
                                imageLoad(endcrystal_img, ivec2(k, 6)).r,
                                imageLoad(endcrystal_img, ivec2(k, 7)).r,
                                imageLoad(endcrystal_img, ivec2(k, 8)).r
                            );
                            vec3 temporalPos = 0.0001 * temporalData.xyz;
                            if (temporalData.w > 0 && length((temporalPos - pos) * vec3(1.0, 0.3, 1.0)) < 1.0) {
                                temporalIndex = k;
                                break;
                            }
                        }
                        if (temporalIndex == -1) {
                            for (int k = 0; k < 20; k++) {
                                int previousWeight = imageAtomicCompSwap(endcrystal_img, ivec2(k, 8), 0, -1);
                                if (previousWeight == 0) {
                                    temporalIndex = k;
                                    break;
                                }
                            }
                        }
                        if (temporalIndex >= 0) {
                            ivec4 storeData = ivec4(10000 * pos, 16000);
                            for (int i = 0; i < 4; i++) {
                                imageStore(endcrystal_img, ivec2(temporalIndex, i+5), ivec4(storeData[i]));
                            }
                        }
                    }
                }
            #endif
            #if END_CRYSTAL_VORTEX_INTERNAL / 2 == 1
                // healing beams
                for (int index = 20; index < 35; index++) {
                    ivec4 writeData = ivec4(
                        imageLoad(endcrystal_img, ivec2(index, 1)).r,
                        imageLoad(endcrystal_img, ivec2(index, 2)).r,
                        imageLoad(endcrystal_img, ivec2(index, 3)).r,
                        imageLoad(endcrystal_img, ivec2(index, 4)).r
                    );
                    for (int i = 0; i < 4; i++) {
                        imageStore(endcrystal_img, ivec2(index, i + 5), ivec4(writeData[i]));
                    }
                }
            #endif
            #if END_CRYSTAL_VORTEX_INTERNAL / 2 == 1 || DRAGON_DEATH_EFFECT_INTERNAL > 0
                // dragon position
                {
                    const int index = 35;
                    int isDying = imageLoad(endcrystal_img, ivec2(index, 0)).r;
                    // if (isDying == 0) isDying = 10000; // Helpful for debugging
                    ivec4 readData = ivec4(
                        imageLoad(endcrystal_img, ivec2(index, 1)).r,
                        imageLoad(endcrystal_img, ivec2(index, 2)).r,
                        imageLoad(endcrystal_img, ivec2(index, 3)).r,
                        imageLoad(endcrystal_img, ivec2(index, 4)).r
                    );
                    ivec4 temporalData = ivec4(
                        imageLoad(endcrystal_img, ivec2(index, 5)).r,
                        imageLoad(endcrystal_img, ivec2(index, 6)).r,
                        imageLoad(endcrystal_img, ivec2(index, 7)).r,
                        imageLoad(endcrystal_img, ivec2(index, 8)).r
                    );
                    ivec4 writeData = ivec4( // is 0 if dragon is dead, otherwise contains dragon position
                        isDying <= 9000 && temporalData.w > 0 ? ivec3(0.0) : 
                        readData.w > 0 ? 10000.0 * readData.xyz / readData.w : 
                        abs(length(vec3(readData.xyz)) - length(vec3(temporalData.xyz))) <= 0.001 ? ivec3(0.0) : 
                        temporalData.xyz + ivec3(10000 * (previousCameraPosition - cameraPosition)),
                        isDying > 0 ? temporalData.w + int(10000 * frameTime) : 0
                    );
                    imageStore(endcrystal_img, ivec2(index, 0), ivec4(max(0, isDying - int(1000 * frameTime))));
                    for (int i = 0; i < 4; i++) {
                        imageStore(endcrystal_img, ivec2(index, i + 1), ivec4(0));
                        imageStore(endcrystal_img, ivec2(index, i + 5), ivec4(writeData[i]));
                    }
                }
            #endif
            
            #ifdef END_PORTAL_BEAM_INTERNAL
                for (int k = 0; k < 4; k++) {
                    imageStore(
                        endcrystal_img,
                        ivec2(35, k+5),
                        imageLoad(endcrystal_img, ivec2(35, k))
                    );
                }
            #endif
            // clear temporally unstable data
            for (int index = 0; index < 36; index++) {
                #if DRAGON_DEATH_EFFECT_INTERNAL > 0
                    if (index == 35) {
                        continue;
                    }
                #endif
                for (int i = 0; i < 5; i++) {
                    imageStore(endcrystal_img, ivec2(index, i), ivec4(0));
                }
            }
        }
        gl_Position = vec4(-1);
    #endif
}

#endif
