3D Bowling
// This source code is subject to the terms of the Mozilla Public License 2.0 at https://mozilla.org/MPL/2.0/
// © peacefulLizard50262
//165
//@version=5
indicator("3D Engine", max_bars_back = 1, max_lines_count = 500, explicit_plot_zorder = true)

help = input.string("Ok", title = 'To play you will first be prompted to pick where you want to throw the ball. Next it will ask you to make a line in the direction you want to throw the ball. Enjoy!', confirm = true, group = "Help")

type vector2
    float x
    float y

type vector3
    float x
    float y
    float z

type vector4
    float x
    float y
    float z
    float w

type face
    int v1
    int v2
    int v3

type mesh
    array<vector4> v
    array<face> f
    array<vector3> fn

type mesh2d
    array<vector2> v
    array<face> f
    array<vector3> fn

type location
    vector3 position
    vector3 theta
    vector3 scale

type object
    mesh m
    location l

type poly4
    float x1
    float x2
    float y1
    float y2

type polyg
    poly4 l1 
    poly4 l2
    poly4 l3
    vector3 fn

type camera
    vector3 pos //position
    vector3 tar //target
    float fov //field of view
    vector2 ar //aspect ratio
    vector2 vd //view distance

type mat4
    float m11 = 1
    float m12 = 0
    float m13 = 0
    float m14 = 0
    float m21 = 0
    float m22 = 1
    float m23 = 0
    float m24 = 0
    float m31 = 0
    float m32 = 0
    float m33 = 1
    float m34 = 0
    float m41 = 0
    float m42 = 0
    float m43 = 0
    float m44 = 1

type play
    float lane
    float start_time
    poly4 direction

radians(degree)=>
    degree * math.pi/180


normalize_screen(float point)=>
    (((point - chart.left_visible_bar_time) / (chart.right_visible_bar_time - chart.left_visible_bar_time)) - 0.5) * 3 

cross_product(v1, v2) =>
    new_vector = vector3.new(
     v1.y * v2.z - v1.z * v2.y,
     v1.z * v2.x - v1.x * v2.z,
     v1.x * v2.y - v1.y * v2.x
     )
    new_vector

vector_normalize(vector3 v)=>
    length = math.sqrt(math.pow(v.x ,2)+math.pow(v.y ,2)+math.pow(v.z ,2))
    vector3.new(v.x/length, v.y/length, v.z/length)    

vector3_length(vector3 v)=>
    math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)

vector3_subtract(vector3 a, vector3 b) =>
    vector3.new(a.x - b.x, a.y - b.y, a.z - b.z)

dot_product(vector3 v1, vector3 v2)=>
    v1.x * v2.x + v1.y * v2.y + v1.z * v2.z

vector3_add(vector3 a, vector3 b) =>
    new_vector = vector3.new(a.x + b.x, a.y + b.y, a.z + b.z)
    new_vector

vector3_scale(vector3 v, float s) =>
    new_vector = vector3.new(v.x * s, v.y * s, v.z * s)
    new_vector

poly4_to_normal_xz_vector3(poly4 poly) =>
    float deltaX = poly.x2 - poly.x1
    float deltaY = poly.y2 - poly.y1
    vector2 vector = vector2.new(deltaX, deltaY)
    float magnitude = math.sqrt(vector.x * vector.x + vector.y * vector.y)
    normal_vector = vector3.new((vector.x/magnitude), 0, -(vector.y/magnitude))
    if normal_vector.y < 0
        vector3.new(normal_vector.x, 0, -normal_vector.z)

    normal_vector

mat4_multiply(a, b) =>
    mat4.new(
     a.m11 * b.m11 + a.m12 * b.m21 + a.m13 * b.m31 + a.m14 * b.m41,
     a.m11 * b.m12 + a.m12 * b.m22 + a.m13 * b.m32 + a.m14 * b.m42,
     a.m11 * b.m13 + a.m12 * b.m23 + a.m13 * b.m33 + a.m14 * b.m43,
     a.m11 * b.m14 + a.m12 * b.m24 + a.m13 * b.m34 + a.m14 * b.m44,
     a.m21 * b.m11 + a.m22 * b.m21 + a.m23 * b.m31 + a.m24 * b.m41,
     a.m21 * b.m12 + a.m22 * b.m22 + a.m23 * b.m32 + a.m24 * b.m42,
     a.m21 * b.m13 + a.m22 * b.m23 + a.m23 * b.m33 + a.m24 * b.m43,
     a.m21 * b.m14 + a.m22 * b.m24 + a.m23 * b.m34 + a.m24 * b.m44,
     a.m31 * b.m11 + a.m32 * b.m21 + a.m33 * b.m31 + a.m34 * b.m41,
     a.m31 * b.m12 + a.m32 * b.m22 + a.m33 * b.m32 + a.m34 * b.m42,
     a.m31 * b.m13 + a.m32 * b.m23 + a.m33 * b.m33 + a.m34 * b.m43,
     a.m31 * b.m14 + a.m32 * b.m24 + a.m33 * b.m34 + a.m34 * b.m44,
     a.m41 * b.m11 + a.m42 * b.m21 + a.m43 * b.m31 + a.m44 * b.m41,
     a.m41 * b.m12 + a.m42 * b.m22 + a.m43 * b.m32 + a.m44 * b.m42,
     a.m41 * b.m13 + a.m42 * b.m23 + a.m43 * b.m33 + a.m44 * b.m43,
     a.m41 * b.m14 + a.m42 * b.m24 + a.m43 * b.m34 + a.m44 * b.m44
     )

mat4_multiply_vec4(mtx, vector) =>
    x = mtx.m11 * vector.x + mtx.m21 * vector.y + mtx.m31 * vector.z + mtx.m41 * vector.w
    y = mtx.m12 * vector.x + mtx.m22 * vector.y + mtx.m32 * vector.z + mtx.m42 * vector.w
    z = mtx.m13 * vector.x + mtx.m23 * vector.y + mtx.m33 * vector.z + mtx.m43 * vector.w
    w = mtx.m14 * vector.x + mtx.m24 * vector.y + mtx.m34 * vector.z + mtx.m44 * vector.w
    vector4.new(x, y, z, w)

mat4_scale(mtx, scale_vector) =>
    _m11 = mtx.m11 * scale_vector.x
    _m12 = mtx.m12 * scale_vector.x
    _m13 = mtx.m13 * scale_vector.x
    _m14 = mtx.m14 * scale_vector.x
    
    _m21 = mtx.m21 * scale_vector.y
    _m22 = mtx.m22 * scale_vector.y
    _m23 = mtx.m23 * scale_vector.y
    _m24 = mtx.m24 * scale_vector.y
    
    _m31 = mtx.m31 * scale_vector.z
    _m32 = mtx.m32 * scale_vector.z
    _m33 = mtx.m33 * scale_vector.z
    _m34 = mtx.m34 * scale_vector.z
    
    _m41 = mtx.m41
    _m42 = mtx.m42
    _m43 = mtx.m43
    _m44 = mtx.m44
    
    mat4.new(_m11, _m12, _m13, _m14, _m21, _m22, _m23, _m24, _m31, _m32, _m33, _m34, _m41, _m42, _m43, _m44)

mat4_translate(mtx, translation_vector) =>
    _m11 = mtx.m11
    _m12 = mtx.m12
    _m13 = mtx.m13
    _m14 = mtx.m14
    
    _m21 = mtx.m21
    _m22 = mtx.m22
    _m23 = mtx.m23
    _m24 = mtx.m24
    
    _m31 = mtx.m31
    _m32 = mtx.m32
    _m33 = mtx.m33
    _m34 = mtx.m34
    
    _m41 = mtx.m11 * translation_vector.x + mtx.m21 * translation_vector.y + mtx.m31 * translation_vector.z + mtx.m41
    _m42 = mtx.m12 * translation_vector.x + mtx.m22 * translation_vector.y + mtx.m32 * translation_vector.z + mtx.m42
    _m43 = mtx.m13 * translation_vector.x + mtx.m23 * translation_vector.y + mtx.m33 * translation_vector.z + mtx.m43
    _m44 = mtx.m14 * translation_vector.x + mtx.m24 * translation_vector.y + mtx.m34 * translation_vector.z + mtx.m44
    
    mat4.new(_m11, _m12, _m13, _m14, _m21, _m22, _m23, _m24, _m31, _m32, _m33, _m34, _m41, _m42, _m43, _m44)

rot_x(angle) =>
    c = math.cos(angle)
    s = math.sin(angle)
    mat4.new(
     1, 0, 0, 0,
     0, c, -s, 0,
     0, s, c, 0,
     0, 0, 0, 1
     )

rot_y(angle) =>
    c = math.cos(angle)
    s = math.sin(angle)
    mat4.new(
     c, 0, s, 0,
     0, 1, 0, 0,
     -s, 0, c, 0,
     0, 0, 0, 1
     )

rot_z(angle) =>
    c = math.cos(angle)
    s = math.sin(angle)
    mat4.new(
     c, -s, 0, 0,
     s, c, 0, 0,
     0, 0, 1, 0,
     0, 0, 0, 1
     )


ticks(float start_time)=>
    time_quanta = (time[1] - last_bar_time)
    (time - start_time) / time_quanta

process_play(play input_play, float play_speed) =>
    location ball_initial_location  = location.new(vector3.new(-input_play.lane, 0, 0), vector3.new(0, 0, 0), vector3.new(1, 1, 1))

    location pin1_initial_location  = location.new(vector3.new(-0.4, 0, 4.4), vector3.new(0, 0, 0), vector3.new(1, 1, 1))
    location pin2_initial_location  = location.new(vector3.new(0, 0, 4), vector3.new(0, 0, 0), vector3.new(1, 1, 1))
    location pin3_initial_location  = location.new(vector3.new(0.4, 0, 4.4), vector3.new(0, 0, 0), vector3.new(1, 1, 1))

    vector3 direction = poly4_to_normal_xz_vector3(input_play.direction)
    float ticks = ticks(input_play.start_time)
    float power = play_speed
    float speed = power * ticks
    vector3 distance = vector3_scale(direction, speed)
    ball_moved_position = vector3_add(distance, ball_initial_location.position)
    ball_moved_theta = vector3_add(ball_initial_location.theta, distance)
    ball_new_location = location.new(ball_moved_position, ball_moved_theta, ball_initial_location.scale)
    // Initialize an array to store the updated pin locations

    if ball_moved_position.z > 4.6 and ball_moved_position.x <= 0.8 and ball_moved_position.x >= -0.8
        updated_pin1_position = vector3_add(pin1_initial_location.position, distance)
        updated_pin2_position = vector3_add(pin2_initial_location.position, distance)
        updated_pin3_position = vector3_add(pin3_initial_location.position, distance)
        updated_pin1_theta    = vector3_add(pin1_initial_location.theta, distance)
        updated_pin2_theta    = vector3_add(pin2_initial_location.theta, distance)
        updated_pin3_theta    = vector3_add(pin3_initial_location.theta, distance)
        updated_pin1_locatoin = location.new(updated_pin1_position, updated_pin1_theta, pin1_initial_location.scale)
        updated_pin2_locatoin = location.new(updated_pin2_position, updated_pin2_theta, pin2_initial_location.scale)
        updated_pin3_locatoin = location.new(updated_pin3_position, updated_pin3_theta, pin3_initial_location.scale)

        [ball_new_location, updated_pin1_locatoin, updated_pin2_locatoin, updated_pin3_locatoin]
    else
        [ball_new_location, pin1_initial_location, pin2_initial_location, pin3_initial_location]
    
screen_min = chart.left_visible_bar_time
screen_max = chart.right_visible_bar_time

create_transformation_matrix(position, rotation, scale) =>
    translation_matrix = mat4_translate(mat4.new(), position)
    rotation_matrix_x = rot_x(rotation.x)
    rotation_matrix_y = rot_y(rotation.y)
    rotation_matrix_z = rot_z(rotation.z)
    scale_matrix = mat4_scale(mat4.new(), scale)
    
    _transformation_matrix_1 = mat4_multiply(rotation_matrix_x, rotation_matrix_y)
    _transformation_matrix_2 = mat4_multiply(_transformation_matrix_1, rotation_matrix_z)
    _transformation_matrix_3 = mat4_multiply(_transformation_matrix_2, scale_matrix)
    transformation_matrix = mat4_multiply(_transformation_matrix_3, translation_matrix)
    transformation_matrix

apply_transformation_matrix(vertex, matrix) =>
    vec4 = mat4_multiply_vec4(matrix, vertex)
    vec4

perspective_transform(mesh msh, cam) =>
    transformed_vertices = array.new<vector2>(array.size(msh.v))
    fov_scale = math.tan(radians(cam.fov) / 2) * 2
    for i = 0 to array.size(msh.v) - 1
        vertex_position = array.get(msh.v, i)
        cam_to_vertex = vector3.new(vertex_position.x - cam.pos.x, vertex_position.y - cam.pos.y, vertex_position.z - cam.pos.z)
        z = cam_to_vertex.z

        x = cam_to_vertex.x / (z * cam.ar.x * fov_scale)
        y = cam_to_vertex.y / (z * cam.ar.y * fov_scale)

        array.set(transformed_vertices, i, vector2.new(x, y))

    mesh2d.new(transformed_vertices, msh.f, msh.fn)


transform_mesh(mesh_obj, transformation_matrix) =>
    new_vertex_list = array.new<vector4>(array.size(mesh_obj.v))
    for i = 0 to array.size(mesh_obj.v) - 1
        old_vertex = array.get(mesh_obj.v, i)
        new_vertex = apply_transformation_matrix(old_vertex, transformation_matrix)
        array.set(new_vertex_list, i, new_vertex)
    mesh.new(new_vertex_list, mesh_obj.f)
    
calculate_face_normals(mesh msh) =>
    face_normals = array.new<vector3>(array.size(msh.f))
    for i = 0 to array.size(msh.f) - 1
        faces = array.get(msh.f, i)

        v1 = array.get(msh.v, faces.v1)
        v2 = array.get(msh.v, faces.v2)
        v3 = array.get(msh.v, faces.v3)

        edge1 = vector3.new(v2.x - v1.x, v2.y - v1.y, v2.z - v1.z)
        edge2 = vector3.new(v3.x - v1.x, v3.y - v1.y, v3.z - v1.z)

        normal = vector3.new(
         edge1.y * edge2.z - edge1.z * edge2.y,
         edge1.z * edge2.x - edge1.x * edge2.z,
         edge1.x * edge2.y - edge1.y * edge2.x
         )

        normal_length = math.sqrt(normal.x * normal.x + normal.y * normal.y + normal.z * normal.z)
        normalized_normal = vector3.new(normal.x / normal_length, normal.y / normal_length, normal.z / normal_length)

        array.set(face_normals, i, normalized_normal)

    face_normals

is_backface(vector3 face_normal, vector3 camera_position, vector4 vertex_position) =>
    camera_direction = vector3.new(
     camera_position.x - vertex_position.x,
     camera_position.y - vertex_position.y,
     camera_position.z - vertex_position.z
     )

    dot_product = face_normal.x * camera_direction.x + face_normal.y * camera_direction.y + face_normal.z * camera_direction.z

    dot_product > 0
 
culling(msh, cam)=>
    face_normals = calculate_face_normals(msh)
    culled_faces = array.new<face>()
    culled_face_normals = array.new<vector3>()
    
    for i = 0 to array.size(msh.f) - 1
        face_normal = array.get(face_normals, i)
        faces = array.get(msh.f, i)
        vertex_position = array.get(msh.v, faces.v1)

        if not is_backface(face_normal, cam.pos, vertex_position)
            array.push(culled_faces, faces)
            array.push(culled_face_normals, face_normal)
 
    mesh.new(msh.v, culled_faces, face_normals)

process_object(obj, cam) =>
    transformation_matrix = create_transformation_matrix(obj.l.position, obj.l.theta, obj.l.scale)
    transformed_mesh = transform_mesh(obj.m, transformation_matrix)
    cull_mesh = culling(transformed_mesh, cam)
    // paint = sort_faces_by_depth(cull_mesh, cam)
    perspective_transform(cull_mesh, cam)


size(scene)=>
    size = 0
    for i = 0 to array.size(scene) - 1
        obj = array.get(scene, i)
        size += array.size(obj.f)
    size

make_poly(array<mesh2d> scene, int poly_count)=>
    var poly_list = array.new<polyg>(poly_count)
    array.clear(poly_list)
    for i = 0 to array.size(scene) - 1
        poly = array.new<polyg>(array.size(array.get(scene, i).f))
        obj = array.get(scene, i)
        obj_v = obj.v
        obj_fn = obj.fn
        for j = 0 to array.size(obj.f) - 1
            v1 = array.get(obj.f, j).v1
            v2 = array.get(obj.f, j).v2
            v3 = array.get(obj.f, j).v3
            array.set(poly, j, polyg.new(
             poly4.new(
             array.get(obj_v, v1).x, 
             array.get(obj_v, v2).x, 
             array.get(obj_v, v1).y, 
             array.get(obj_v, v2).y), 
             poly4.new(
             array.get(obj_v, v2).x, 
             array.get(obj_v, v3).x, 
             array.get(obj_v, v2).y, 
             array.get(obj_v, v3).y), 
             poly4.new(
             array.get(obj_v, v3).x, 
             array.get(obj_v, v1).x, 
             array.get(obj_v, v3).y, 
             array.get(obj_v, v1).y),
             array.get(obj_fn, j)))
        for k = 0 to array.size(poly) - 1
            array.push(poly_list, array.get(poly, k))
    poly_list

process_scene(scn, cam)=>
    new_scn = array.new<mesh2d>(array.size(scn))
    for i = 0 to array.size(scn) - 1
        new_object = process_object(array.get(scn, i), cam)
        array.set(new_scn, i, new_object)
    poly_count = size(new_scn)
    make_poly(new_scn, poly_count)

render(scene_list, Camera, scale_factor, colour)=>
    lines = array.new<line>(500)
    fills = array.new<linefill>(500)

    if barstate.islast 
        scene_lines = process_scene(scene_list, Camera)

        time_quanta = (time[1] - last_bar_time)
        left = chart.left_visible_bar_time
        right = chart.right_visible_bar_time

        center = (right + left)/2

        wire_color = colour

        for i = 0 to array.size(scene_lines) - 1
            poly = array.get(scene_lines, i)
            array.push(lines, line.new(int(center + time_quanta * poly.l1.x1 * scale_factor), poly.l1.y1, int(center + time_quanta * poly.l1.x2 * scale_factor), poly.l1.y2, xloc.bar_time, color = wire_color))
            array.push(lines, line.new(int(center + time_quanta * poly.l2.x1 * scale_factor), poly.l2.y1, int(center + time_quanta * poly.l2.x2 * scale_factor), poly.l2.y2, xloc.bar_time, color = wire_color))
            array.push(lines, line.new(int(center + time_quanta * poly.l3.x1 * scale_factor), poly.l3.y1, int(center + time_quanta * poly.l3.x2 * scale_factor), poly.l3.y2, xloc.bar_time, color = wire_color))

    if barstate.isconfirmed 
        for i = 0 to array.size(lines) - 1
            line.delete(array.get(lines, i))

pin_vertex_list = array.from(
 vector4.new(0, 0.5, 0, 1),              //0 a

 vector4.new( 0.0802,  0.3417,  0.0000, 1),  //1 b 
 vector4.new( 0.0567,  0.3417, -0.0567, 1),  //2 c 
 vector4.new( 0.0000,  0.3417, -0.0802, 1),  //3 d 
 vector4.new(-0.0567,  0.3417, -0.0567, 1), //4 e 
 vector4.new(-0.0802,  0.3417,  0.0000, 1),  //5 f 
 vector4.new(-0.0567,  0.3417,  0.0567, 1),  //6 g 
 vector4.new( 0.0000,  0.3417,  0.0802, 1),  //7 h 
 vector4.new( 0.0567,  0.3417,  0.0567, 1),  //8 i 

 vector4.new( 0.0599,  0.1667,  0.0000, 1),  //9 j
 vector4.new( 0.0424,  0.1667, -0.0424, 1),  //10 k 
 vector4.new( 0.0000,  0.1667, -0.0599, 1),  //11 l
 vector4.new(-0.0424,  0.1667, -0.0424, 1),  //12 m 
 vector4.new(-0.0599,  0.1667,  0.0000, 1),  //13 n
 vector4.new(-0.0424,  0.1667,  0.0424, 1),  //14 o 
 vector4.new( 0.0000,  0.1667,  0.0599, 1),  //15 p
 vector4.new( 0.0424,  0.1667,  0.0424, 1),  //16 q

 vector4.new( 0.1589, -0.2000,  0.0000, 1), //17 r
 vector4.new( 0.1124, -0.2000, -0.1124, 1), //18 s 
 vector4.new( 0.0000, -0.2000, -0.1589, 1), //19 t
 vector4.new(-0.1124, -0.2000, -0.1124, 1), //20 u 
 vector4.new(-0.1589, -0.2000,  0.0000, 1), //21 v
 vector4.new(-0.1124, -0.2000,  0.1124, 1), //22 w
 vector4.new( 0.0000, -0.2000,  0.1589, 1), //23 z
 vector4.new( 0.1124, -0.2000,  0.1124, 1), //24 a1

 vector4.new( 0.0677, -0.5000,  0.0000, 1), //25 b1
 vector4.new( 0.0479, -0.5000, -0.0479, 1), //26 c1
 vector4.new( 0.0000, -0.5000, -0.0677, 1), //27 d1
 vector4.new(-0.0479, -0.5000, -0.0479, 1), //28 e1
 vector4.new(-0.0677, -0.5000,  0.0000, 1), //29 f1
 vector4.new(-0.0479, -0.5000,  0.0479, 1), //30 g1
 vector4.new( 0.0000, -0.5000,  0.0677, 1), //31 h1
 vector4.new( 0.0479, -0.5000,  0.0479, 1), //32 i1
 
 vector4.new(0, -0.5, 0, 1)                 //33 h1
 )

pin_face_list = array.from(
 face.new(0, 1, 2), //0
 face.new(0, 2, 3), //1
 face.new(0, 3, 4), //2
 face.new(0, 4, 5), //3
 face.new(0, 5, 6), //4
 face.new(0, 6, 7), //5
 face.new(0, 7, 8), //6
 face.new(0, 1, 8), //7
 face.new(1, 2, 9), //8
 face.new(2, 9, 10), //9
 face.new(2, 10, 11), //10
 face.new(2, 3, 11), //11
 face.new(3, 4, 11), //12
 face.new(4, 11, 12), //13
 face.new(4, 12, 13), //14
 face.new(4, 5, 13), //15
 face.new(5, 6, 13), //16
 face.new(6, 13, 14), //17
 face.new(6, 14, 15), //18
 face.new(6, 7, 15), //19
 face.new(7, 8, 15), //20
 face.new(8, 15, 16), //21
 face.new(8, 9, 16), //22
 face.new(1, 8, 9), //23
 face.new(9, 17, 18), //24
 face.new(9, 10, 18), //25
 face.new(10, 11, 18), //26
 face.new(11, 18, 19), //27
 face.new(11, 19, 20), //28
 face.new(11, 12, 20), //29
 face.new(12, 13, 20), //30
 face.new(13, 20, 21), //31
 face.new(13, 21, 22), //32
 face.new(13, 14, 22), //33
 face.new(14, 15, 22), //34
 face.new(15, 22, 23), //35
 face.new(15, 23, 24), //36
 face.new(15, 16, 24), //37
 face.new(9, 16, 24), //38
 face.new(9, 17, 24), //39
 face.new(17, 18, 25), //40
 face.new(17, 24, 25), //41 
 face.new(18, 25, 26), //42
 face.new(18, 26, 27), //43
 face.new(18, 19, 27), //44
 face.new(19, 20, 27), //45
 face.new(20, 27, 28), //46
 face.new(20, 28, 29), //47
 face.new(20, 21, 29), //48
 face.new(21, 22, 29), //49
 face.new(22, 29, 30), //50
 face.new(22, 30, 31), //51
 face.new(22, 23, 31), //52
 face.new(23, 24, 31), //53
 face.new(24, 31, 32), //54
 face.new(24, 25, 32), //55
 face.new(25, 26, 33), //56
 face.new(26, 27, 33), //57
 face.new(27, 28, 33), //58
 face.new(28, 29, 33), //59
 face.new(29, 30, 33), //60
 face.new(30, 31, 33), //61
 face.new(31, 32, 33), //62
 face.new(25, 32, 33)  //63
 )

ball_vertex_list = array.from(
 vector4.new(0.0, -0.5, 0.0, 1),
 vector4.new(0.0, 0.5, 0.0, 1),
 vector4.new(0.17026233930306509, 0.3535533905932738, 0.3535533905932738, 1),
 vector4.new(0.24078730940376433, 3.061616997868383e-17, 0.5, 1),
 vector4.new(0.1702623393030651, -0.35355339059327373, 0.3535533905932738, 1),
 vector4.new(0.3825760036952101, 0.3535533905932738, 0.08732047630169361, 1),
 vector4.new(0.5410441730642656, 3.061616997868383e-17, 0.12348980185873357, 1),
 vector4.new(0.38257600369521017, -0.35355339059327373, 0.08732047630169362, 1),
 vector4.new(0.3068021341766003, 0.3535533905932738, -0.24466653765816737, 1),
 vector4.new(0.4338837391175582, 3.061616997868383e-17, -0.34601073581504793, 1),
 vector4.new(0.3068021341766003, -0.35355339059327373, -0.2446665376581674, 1),
 vector4.new(4.805693554381959e-17, 0.3535533905932738, -0.3924146584735999, 1),
 vector4.new(6.796277001215932e-17, 3.061616997868383e-17, -0.5549581320873712, 1),
 vector4.new(4.8056935543819596e-17, -0.35355339059327373, -0.39241465847359996, 1),
 vector4.new(-0.3068021341766002, 0.3535533905932738, -0.24466653765816745, 1),
 vector4.new(-0.43388373911755806, 3.061616997868383e-17, -0.34601073581504804, 1),
 vector4.new(-0.30680213417660024, -0.35355339059327373, -0.2446665376581675, 1),
 vector4.new(-0.3825760036952101, 0.3535533905932738, 0.08732047630169353, 1),
 vector4.new(-0.5410441730642656, 3.061616997868383e-17, 0.12348980185873344, 1),
 vector4.new(-0.38257600369521017, -0.35355339059327373, 0.08732047630169354, 1),
 vector4.new(-0.17026233930306517, 0.3535533905932738, 0.35355339059327373, 1),
 vector4.new(-0.24078730940376444, 3.061616997868383e-17, 0.49999999999999994, 1),
 vector4.new(-0.1702623393030652, -0.35355339059327373, 0.3535533905932738, 1)
 )

ball_face_list = array.from(
 face.new(2, 5, 1),
 face.new(2, 3, 6),
 face.new(3, 4, 7),
 face.new(7, 4, 0),
 face.new(5, 8, 1),
 face.new(5, 6, 9),
 face.new(6, 7, 10),
 face.new(10, 7, 0),
 face.new(8, 11, 1),
 face.new(8, 9, 12),
 face.new(9, 10, 13),
 face.new(13, 10, 0),
 face.new(11, 14, 1),
 face.new(11, 12, 15),
 face.new(12, 13, 16),
 face.new(16, 13, 0),
 face.new(14, 17, 1),
 face.new(14, 15, 18),
 face.new(15, 16, 19),
 face.new(19, 16, 0),
 face.new(17, 20, 1),
 face.new(17, 18, 21),
 face.new(18, 19, 22),
 face.new(22, 19, 0),
 face.new(20, 2, 1),
 face.new(20, 21, 3),
 face.new(21, 22, 4),
 face.new(4, 22, 0)
 )

center = math.avg(chart.left_visible_bar_time, chart.right_visible_bar_time)

play_speed = input.float(0.5)

lane_position_x = normalize_screen(input.time(0, confirm = true, group = "Input"))
direction_and_power_y1 = input.price(0, "Input Y1", inline = "direction_1", confirm = true, group = "Input")
direction_and_power_x1 = input.time(0, "Input X1", inline = "direction_1", confirm = true, group = "Input") / 10000000000
direction_and_power_y2 = input.price(0, "Input Y2", inline = "direction_2", confirm = true, group = "Input")
direction_and_power_x2 = input.time(0, "Input X2", inline = "direction_2", confirm = true, group = "Input") / 10000000000
curent_time = input.time(0, "Time Advance Set This To Current Time To Play", confirm = true, group = "Input")

ball_color = input.color(color.blue, "Ball Color")
pin_color = input.color(color.red, "Pin Color")

x_pos = input.float(0, "Camera Position X")
y_pos = input.float(1, "Camera Position Y")
z_pos = input.float(-3, "Camera Position Z")

fov = input.float(45, "FOV")

scale_factor = input.float(100, "Screen Scale")

controle = play.new(lane_position_x, curent_time, poly4.new(direction_and_power_x1, direction_and_power_x2, direction_and_power_y1, direction_and_power_y2))

[ball_location, pin1_location, pin2_location, pin3_location] = process_play(controle, play_speed)

Camera = camera.new(vector3.new(x_pos, y_pos, z_pos), vector3.new(0, 0, 0), fov, vector2.new(1, 1), vector2.new(0.1, 8))

pin_mesh = mesh.new(pin_vertex_list, pin_face_list)
ball_mesh = mesh.new(ball_vertex_list, ball_face_list)

ball = object.new(ball_mesh, ball_location)
pin1 = object.new(pin_mesh, pin1_location)
pin2 = object.new(pin_mesh, pin2_location) 
pin3 = object.new(pin_mesh, pin3_location)

debug_1 = array.from(ball)
debug_2 = array.from(pin1)
debug_3 = array.from(pin2)
debug_4 = array.from(pin3)

 
render(debug_2, Camera, scale_factor, pin_color)
render(debug_3, Camera, scale_factor, pin_color)
render(debug_4, Camera, scale_factor, pin_color)
render(debug_1, Camera, scale_factor, ball_color)

hline(-1)
hline(1)


//python program to convert .obj files into 3D files for the engine
// def parse_obj(file_path):
//     vertices = []
//     faces = []

//     with open(file_path, 'r') as file:
//         for line in file:
//             if line.startswith('v '):
//                 coords = list(map(float, line[2:].split()))
//                 vertices.append(coords)
//             elif line.startswith('f '):
//                 indices = [int(s.split('/')[0]) - 1 for s in line[2:].split()]
//                 faces.append(indices)

//     return vertices, faces

// def convert_to_custom_format(vertices, faces, vertex_var_name, face_var_name):
//     vertex_lines = [f"vector4.new({v[0]}, {v[1]}, {v[2]}, 1)," for v in vertices]
//     vertex_data = f"{vertex_var_name} = array.from(\n " + "\n ".join(vertex_lines) + "\n)"

//     face_lines = [f"face.new({f[0]}, {f[1]}, {f[2]})," for f in faces]
//     face_data = f"{face_var_name} = array.from(\n " + "\n ".join(face_lines) + "\n)"

//     return vertex_data + "\n\n" + face_data

// def main():
//     input_obj_file = "C:/object.obj"
//     output_custom_file = "C:/object.txt"
//     vertex_var_name = "object_vertex_list"
//     face_var_name = "object_face_list"

//     vertices, faces = parse_obj(input_obj_file)
//     custom_data = convert_to_custom_format(vertices, faces, vertex_var_name, face_var_name)

//     with open(output_custom_file, 'w') as output_file:
//         output_file.write(custom_data)

// if __name__ == "__main__":
//     main()
