import sys, time, numpy as np
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GL.shaders import compileProgram, compileShader

# ------------------ Configuration ------------------
NUM_SUPER = 8192       # increased
NUM_INSTANCES = 8192   # increased
MAX_SLICE = 16         # more RGBA slices
TIME_SLICES = 4        # multiple frames per virtual canvas
VIRT_WIDTH = 7680      # oversample
VIRT_HEIGHT = 4320
FPS_TARGET = 60.0

fibTable = np.array([1,1,2,3,5,8,13,21,34,55,89,144]*12, dtype=np.float32)[:128]
primeTable = np.array([2,3,5,7,11,13,17,19,23,29,31,37,41,43,47]*10, dtype=np.float32)[:128]

window = None
start_time = time.time()
phi = 1.61803398875
phiInv = 1.0/phi

# ------------------ Shader Sources ------------------
FRAGMENT_SRC = """
#version 330
in vec2 texCoord;
out vec4 fragColor;

uniform float cycle;
uniform float omegaTime;
uniform float phi;
uniform float phiInv;
uniform int instanceID;
uniform int TIME_SLICE;

uniform float fibTable[128];
uniform float primeTable[128];
uniform int MAX_SLICE;
uniform int NUM_SUPER;
uniform int NUM_INSTANCES;

float prismatic_recursion(int id, float r){
    float phi_harm = pow(phi, float(mod(id,16)));
    float fib_harm = fibTable[id % 128];
    float dyadic = float(1 << int(mod(float(id),16.0)));
    float prime_harm = primeTable[id % 128];
    float Omega = 0.5 + 0.5*sin(omegaTime + float(id)*0.01);
    float r_dim = pow(r, float(mod(id,7)+1));
    return sqrt(phi_harm * fib_harm * dyadic * prime_harm * Omega) * r_dim;
}

void main(){
    float r = length(texCoord - 0.5) * 2.0;
    float val = 0.0;

    // Multi-instance + multi-time-slice computation
    for(int t=0; t<TIME_SLICE; t++){
        for(int s=0; s<NUM_SUPER; s++){
            int idx = ((instanceID * NUM_SUPER + s) + t*NUM_INSTANCES) % NUM_INSTANCES;
            val += prismatic_recursion(idx, r);
        }
    }
    val /= float(NUM_SUPER * TIME_SLICE);

    float phase = sin(cycle*0.01 + val);
    float slice = mod(float(instanceID), float(MAX_SLICE));
    fragColor = vec4(val, phase, r, slice/float(MAX_SLICE));
}
"""

VERTEX_SRC = """
#version 330
in vec2 position;
out vec2 texCoord;
void main(){
    texCoord = (position + 1.0) * 0.5;
    gl_Position = vec4(position, 0.0, 1.0);
}
"""

# ------------------ OpenGL Setup ------------------
def init_gl():
    global shader, vao
    shader = compileProgram(
        compileShader(VERTEX_SRC, GL_VERTEX_SHADER),
        compileShader(FRAGMENT_SRC, GL_FRAGMENT_SHADER)
    )

    quad_vertices = np.array([-1.0,-1.0, 1.0,-1.0, 1.0,1.0, -1.0,1.0], dtype=np.float32)
    vao = glGenVertexArrays(1)
    glBindVertexArray(vao)

    vbo = glGenBuffers(1)
    glBindBuffer(GL_ARRAY_BUFFER, vbo)
    glBufferData(GL_ARRAY_BUFFER, quad_vertices.nbytes, quad_vertices, GL_STATIC_DRAW)

    pos_loc = glGetAttribLocation(shader, "position")
    glEnableVertexAttribArray(pos_loc)
    glVertexAttribPointer(pos_loc, 2, GL_FLOAT, GL_FALSE, 0, None)

# ------------------ Display Loop ------------------
def display():
    glClear(GL_COLOR_BUFFER_BIT)
    glUseProgram(shader)

    now = time.time() - start_time
    glUniform1f(glGetUniformLocation(shader, "cycle"), now*60.0)
    glUniform1f(glGetUniformLocation(shader, "omegaTime"), now*10.0)
    glUniform1f(glGetUniformLocation(shader, "phi"), phi)
    glUniform1f(glGetUniformLocation(shader, "phiInv"), phiInv)
    glUniform1i(glGetUniformLocation(shader, "instanceID"), 0)
    glUniform1i(glGetUniformLocation(shader, "NUM_SUPER"), NUM_SUPER)
    glUniform1i(glGetUniformLocation(shader, "NUM_INSTANCES"), NUM_INSTANCES)
    glUniform1i(glGetUniformLocation(shader, "MAX_SLICE"), MAX_SLICE)
    glUniform1i(glGetUniformLocation(shader, "TIME_SLICE"), TIME_SLICES)

    glUniform1fv(glGetUniformLocation(shader, "fibTable"), 128, fibTable)
    glUniform1fv(glGetUniformLocation(shader, "primeTable"), 128, primeTable)

    glBindVertexArray(vao)
    glDrawArrays(GL_TRIANGLE_FAN, 0, 4)
    glutSwapBuffers()
    glutPostRedisplay()

def main():
    global window
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)
    glutInitWindowSize(1920, 1080)
    glutInitWindowPosition(100,100)
    window = glutCreateWindow(b"HDGL Prismatic BaseI Fabric RX480 TFLOPs Max")
    init_gl()
    glutDisplayFunc(display)
    glutMainLoop()

if __name__ == "__main__":
    main()
