from ursina import *

cached_quads = {}
def Quad(radius=.1, segments=8, aspect=1, scale=(1,1), mode='ngon', thickness=1):

    if radius == 0 and aspect==1 and scale == (1,1) and mode == 'ngon':
        return Mesh(
            vertices=[Vec3(-0.5, -0.5, 0.0), Vec3(0.5, -0.5, 0.0), Vec3(0.5, 0.5, 0.0), Vec3(-0.5, 0.5, 0.0)],
            triangles=[(0,1,2,3), ],
            uvs=[Vec2(0,0), Vec2(1,0), Vec2(1,1), Vec2(0,1)],
            mode='triangle'
            )
    # copy a cached quad if a QuadMesh with the same settings have been created before
    quad_identifier = f'QuadMesh({radius}, {segments}, {aspect}, {scale}, {mode}, {thickness})'
    if quad_identifier in cached_quads and cached_quads[quad_identifier]:
        # print('load cached')
        return deepcopy(cached_quads[quad_identifier])

    return QuadMesh(radius, segments, aspect, scale, mode, thickness)


class QuadMesh(Mesh):
    corner_maker = None
    point_placer = None

    def __init__(self, radius=.1, segments=8, aspect=1, scale=(1,1), mode='ngon', thickness=1):
        if not QuadMesh.corner_maker: QuadMesh.corner_maker = Entity(eternal=True, add_to_scene_entities=False)
        if not QuadMesh.point_placer: QuadMesh.point_placer = Entity(parent=QuadMesh.corner_maker, x=-radius, eternal=True, add_to_scene_entities=False)


        super().__init__()
        self.vertices = [Vec3(0,0,0), Vec3(1,0,0), Vec3(1,1,0), Vec3(0,1,0)]
        self.radius = radius
        self.mode = mode
        self.thickness = thickness

        _segments = segments
        _segments += 1
        if _segments > 1:
            new_verts = list()
            QuadMesh.corner_maker.rotation_z = 0
            QuadMesh.corner_maker.position = Vec3(0,0,0)
            QuadMesh.corner_maker.rotation_z -= 90/_segments/2
            QuadMesh.point_placer.position = Vec3(-radius,0,0)

            corner_corrections = (Vec3(radius,radius,0), Vec3(-radius,radius,0), Vec3(-radius,-radius,0), Vec3(radius,-radius,0))
            for j in range(4):  # 4 corners
                QuadMesh.corner_maker.position = self.vertices[j] + corner_corrections[j]
                for i in range(_segments):
                    new_verts.append(QuadMesh.point_placer.world_position)
                    QuadMesh.corner_maker.rotation_z -= 90/_segments

            self.vertices = new_verts


        self.uvs = list()
        for v in self.vertices:
            self.uvs.append((v[0], v[1]))

        # scale corners horizontally with aspect
        for v in self.vertices:
            if v[0] < .5:
                v[0] /= aspect
            else:
                v[0] = lerp(v[0], 1, 1-(1/aspect))

        # move edges out to keep nice corners
        for v in self.vertices:
            if v[0] > .5:
                v[0] += (scale[0]-1)
            if v[1] > .5:
                v[1] += (scale[1]-1)


        # center mesh
        offset = sum(self.vertices) / len(self.vertices)
        self.vertices = [(v[0]-offset[0], v[1]-offset[1], v[2]-offset[2]) for v in self.vertices]


        # make the line connect back to start
        if mode == 'line':
            self.vertices.append(self.vertices[0])

        self.generate()
        cached_quads[f'QuadMesh({radius}, {segments}, {aspect}, {scale}, {mode}, {thickness})'] = self




if __name__ == '__main__':
    app = Ursina()
    from time import perf_counter
    t = perf_counter()
    # m =
    for i in range(100):
        Entity(model=Quad(scale=(3,1), thickness=3, segments=3, mode='line'), color = color.hsv(0,1,1,.7))
    # Entity(scale=(3,1), model=Quad(aspect=3), color = color.hsv(60,1,1,.3))
    print('-------', (perf_counter() - t))

    origin = Entity(model='quad', color=color.orange, scale=(.05, .05))
    # ed = EditorCamera(rotation_speed = 200, panning_speed=200)

    Entity(model=Quad(0), texture='shore', x=-1)

    camera.z = -5
    app.run()
