def draw_line_XZ(L=np.array([0,1,1],'f')):
    glClearColor(0,0,0,1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)

    eye = projector.RT[:3,3]
    with projector.viewpoint_projection(eye, 0):
        a,b,c = L

        # Solve for the point on the line nearest to the origin
        p = (a*c, b*c, -(a*a + b*b))
        within_eps = lambda a, b: np.abs(a-b) < 1e-5
        assert within_eps(np.dot(L, p), 0)

        perp = np.array([a, b],'f')
        v = np.array([b, -a],'f')
        p = np.array(p[:2])/p[2]

        glColor(1,1,1,1)
        glBegin(GL_QUADS)
        for p_ in (p - 10*v,
                   p - 10*v + 10*perp,
                   p + 10*v + 10*perp,
                   p + 10*v):
            glVertex(p_[0], 0, p_[1])
        glEnd()

    window.canvas.SwapBuffers()
def on_draw():
    glClearColor(0,0,0,1)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
    glEnable(GL_DEPTH_TEST)

    global projector
    if not 'projector' in globals(): return

    # Project decals directly to the projector, no eye needed
    with opengl_state():
        projector.setup_projection_matrix()
        # draw_decals() # Depth is inconsistent between decals and viewpoint

    # For each projection surface plane, we need to do a render
    for plane_index in [0, 1]:
        with projector.viewpoint_projection(eye, plane_index):
            draw_decals()
            draw_objects(eye)