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

# ------------------- CONFIG -------------------
WINDOW_WIDTH, WINDOW_HEIGHT = 1280, 720
NUM_PARTICLES = 30000
NUM_SLOTS = 4096  # Fibonacci/prime harmonic lattice
NUM_STRANDS = 32  # full prismatic strands
GLYPH_COUNT = 8000
PHI = 1.6180339887

# ------------------- GPU DATA -------------------
def generate_fib_table(n):
    fibs = np.zeros(n, dtype=np.float32)
    fibs[0], fibs[1] = 0.0, 1.0
    for i in range(2, n):
        fibs[i] = fibs[i-1] + fibs[i-2]
        if fibs[i] > 1e6:
            fibs /= fibs[i]
    fibs /= fibs.max() if fibs.max() != 0 else 1.0
    return fibs

def generate_prime_table(n):
    primes = np.zeros(n, dtype=np.float32)
    primes_list = [2]
    candidate = 3
    while len(primes_list) < n:
        is_prime = all(candidate % p != 0 for p in primes_list)
        if is_prime: primes_list.append(candidate)
        candidate += 2
    primes[:n] = primes_list[:n]
    primes /= primes.max()
    return primes

fib_table = generate_fib_table(NUM_SLOTS)
prime_table = generate_prime_table(NUM_SLOTS)

# ------------------- SHADERS -------------------
VERTEX_SHADER = """
#version 330
layout(location=0) in vec3 position;
void main() {
    gl_Position = vec4(position,1.0);
}
"""

FRAGMENT_SHADER = f"""
#version 330
out vec4 fragColor;
uniform float time;
uniform int num_slots;
uniform int num_strands;
uniform sampler2D glyphTex;
uniform float fibTable[{NUM_SLOTS}];
uniform float primeTable[{NUM_SLOTS}];

float prismaticRecursion(int strand, int slot, float r) {{
    float phi_harm = pow({PHI}, float((strand + slot) % 16));
    float fib_harm = fibTable[slot % {NUM_SLOTS}];
    float prime_harm = primeTable[slot % {NUM_SLOTS}];
    float Omega = 0.5 + 0.5*sin(time + float(strand*slot)*0.01);
    float r_dim = pow(r, float((slot % 7) + 1));
    return sqrt(phi_harm*fib_harm*prime_harm*Omega) * r_dim;
}}

void main() {{
    float r = length(gl_FragCoord.xy/vec2({WINDOW_WIDTH},{WINDOW_HEIGHT}) - 0.5)*2.0;
    vec4 acc = vec4(0.0);
    for(int s=0; s<num_strands; s++) {{
        for(int slot=0; slot<num_slots; slot++) {{
            float val = prismaticRecursion(s, slot, r);
            // Map strand to RGBA channels + alpha stacking
            if(s%4==0) acc.r += val;
            else if(s%4==1) acc.g += val;
            else if(s%4==2) acc.b += val;
            else acc.a += val;
        }}
    }}
    acc /= float(num_strands*num_slots);
    // glyph overlay (from procedural texture)
    vec2 uv = gl_FragCoord.xy/vec2({WINDOW_WIDTH},{WINDOW_HEIGHT});
    float glyph_val = texture(glyphTex, uv).r;
    fragColor = acc * glyph_val;
}}
"""

# ------------------- GLUT & OpenGL -------------------
window = None
shader = None

def init_gl():
    global shader
    shader = compileProgram(
        compileShader(VERTEX_SHADER, GL_VERTEX_SHADER),
        compileShader(FRAGMENT_SHADER, GL_FRAGMENT_SHADER)
    )
    glUseProgram(shader)
    glClearColor(0.0, 0.0, 0.0, 1.0)

def display():
    glClear(GL_COLOR_BUFFER_BIT)
    time_loc = glGetUniformLocation(shader, "time")
    glUniform1f(time_loc, glutGet(GLUT_ELAPSED_TIME)/1000.0)
    num_slots_loc = glGetUniformLocation(shader, "num_slots")
    glUniform1i(num_slots_loc, NUM_SLOTS)
    num_strands_loc = glGetUniformLocation(shader, "num_strands")
    glUniform1i(num_strands_loc, NUM_STRANDS)
    # Draw full-screen quad
    glBegin(GL_TRIANGLES)
    glVertex2f(-1,-1)
    glVertex2f(3,-1)
    glVertex2f(-1,3)
    glEnd()
    glutSwapBuffers()
    glutPostRedisplay()

def main():
    global window
    glutInit(sys.argv)
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA)
    glutInitWindowSize(WINDOW_WIDTH, WINDOW_HEIGHT)
    window = glutCreateWindow(b"HDGL Superglyphs 32-Strand Prismatic GPU Overlay")
    init_gl()
    glutDisplayFunc(display)
    glutMainLoop()

if __name__ == "__main__":
    main()
