// File: IsaacLaw12[P]RayTracer/./src/Model.cpp
// Function: Model::intersect_ray(Ray&, Eigen::Matrix<double, 3, 1, 0, 3, 1>&)
double Model::intersect_ray(Ray& ray, Eigen::Vector3d &hit_normal){
    double smallest_t = MISSED_T_VALUE;
    const Eigen::Vector3d& ray_dir = ray.get_dir();
    Eigen::Vector3d a_vertex, b_vertex, c_vertex,  a_b, a_c, a_l, solution;
    Eigen::Matrix3d M = Eigen::Matrix3d();
    Eigen::Matrix3d MMs1, MMs2, MMs3;
    double beta, gamma, t_value;
    std::set<int> intersected_faces = bounding_box->intersected_faces(ray);

    //std::cout << "Intersected_faces: "<<intersected_faces.size() << "\n";
    //std::cout << "returned intersected faces: \n ";
    //    for (auto i = intersected_faces.begin(); i != intersected_faces.end(); ++i)
    //        std::cout << *i << ' ';
    //std::cout << "\n";
    for (auto face_num: intersected_faces){
    //for (int face_num=0; face_num<Faces.cols(); face_num++){
        a_vertex = get_vertex( Faces(0, face_num) - 1 );
        b_vertex = get_vertex( Faces(1, face_num) - 1 );
        c_vertex = get_vertex( Faces(2, face_num) - 1 );

        a_b = a_vertex - b_vertex;
        a_c = a_vertex - c_vertex;
        a_l = a_vertex - ray.get_point();

        M << a_b(0), a_c(0), ray_dir(0),
             a_b(1), a_c(1), ray_dir(1),
             a_b(2), a_c(2), ray_dir(2);
        MMs1 = Eigen::Matrix3d(M);
        MMs2 = Eigen::Matrix3d(M);
        MMs3 = Eigen::Matrix3d(M);
        for (int i=0; i<3; i++){
            MMs1(i,0) = a_l(i);
            MMs2(i,1) = a_l(i);
            MMs3(i,2) = a_l(i);
        }
        beta = MMs1.determinant() / M.determinant();
        if (beta < 0 || beta > 1){
            continue;
        }
        gamma = MMs2.determinant() / M.determinant();
        if (gamma < 0 || beta+gamma > 1){
            continue;
        }

        t_value = MMs3.determinant() / M.determinant();
        if ((t_value < smallest_t) && (t_value > 0.00001)){
            smallest_t = t_value;
            if (smoothing){
                hit_normal = get_smooth_face_normal(face_num, beta, gamma);
            } else{
                hit_normal = get_face_normal(face_num);
            }

            if (hit_normal.dot(ray_dir) > 0)
                hit_normal = -1 * hit_normal;
        }
    }

    return smallest_t;
}

// Assembly:
subq $0x588, %rsp            # imm = 0x588
movq %rdi, 0x580(%rsp)
movq %rsi, 0x578(%rsp)
movq %rdx, 0x570(%rsp)
movq 0x580(%rsp), %rax
movq %rax, 0x128(%rsp)
movsd 0x188(%rax), %xmm0
movsd %xmm0, 0x568(%rsp)
movq 0x578(%rsp), %rdi
callq 0x5cba0
movq %rax, 0x560(%rsp)
leaq 0x548(%rsp), %rdi
callq 0x11e20
leaq 0x530(%rsp), %rdi
callq 0x11e20
leaq 0x518(%rsp), %rdi
callq 0x11e20
leaq 0x500(%rsp), %rdi
callq 0x11e20
leaq 0x4e8(%rsp), %rdi
callq 0x11e20
leaq 0x4d0(%rsp), %rdi
callq 0x11e20
leaq 0x4b8(%rsp), %rdi
callq 0x11e20
leaq 0x470(%rsp), %rdi
callq 0x1e7c0
leaq 0x428(%rsp), %rdi
callq 0x1e7c0
leaq 0x3e0(%rsp), %rdi
callq 0x1e7c0
leaq 0x398(%rsp), %rdi
callq 0x1e7c0
movq 0x128(%rsp), %rdi
addq $0x190, %rdi            # imm = 0x190
callq 0x1e7e0
movq %rax, %rsi
movq 0x578(%rsp), %rdx
leaq 0x350(%rsp), %rdi
callq 0x587d0
leaq 0x350(%rsp), %rax
movq %rax, 0x348(%rsp)
movq 0x348(%rsp), %rdi
callq 0x1e7f0
movq %rax, 0x340(%rsp)
movq 0x348(%rsp), %rdi
callq 0x1e820
movq %rax, 0x338(%rsp)
leaq 0x340(%rsp), %rdi
leaq 0x338(%rsp), %rsi
callq 0x1e850
testb $0x1, %al
jne 0x1c128
jmp 0x1c9bb
leaq 0x340(%rsp), %rdi
callq 0x1e870
movq 0x128(%rsp), %rdi
movl (%rax), %eax
movl %eax, 0x334(%rsp)
addq $0x1b0, %rdi            # imm = 0x1B0
movslq 0x334(%rsp), %rdx
xorl %eax, %eax
movl %eax, %esi
callq 0x1da60
movq %rax, 0x120(%rsp)
jmp 0x1c168
movq 0x128(%rsp), %rsi
movq 0x120(%rsp), %rax
movl (%rax), %edx
decl %edx
leaq 0x318(%rsp), %rdi
callq 0x1b8f0
jmp 0x1c18b
leaq 0x548(%rsp), %rdi
leaq 0x318(%rsp), %rsi
callq 0x9d10
movq 0x128(%rsp), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
movslq 0x334(%rsp), %rdx
movl $0x1, %esi
callq 0x1da60
movq %rax, 0x118(%rsp)
jmp 0x1c1cb
movq 0x128(%rsp), %rsi
movq 0x118(%rsp), %rax
movl (%rax), %edx
decl %edx
leaq 0x2f0(%rsp), %rdi
callq 0x1b8f0
jmp 0x1c1ee
leaq 0x530(%rsp), %rdi
leaq 0x2f0(%rsp), %rsi
callq 0x9d10
movq 0x128(%rsp), %rdi
addq $0x1b0, %rdi            # imm = 0x1B0
movslq 0x334(%rsp), %rdx
movl $0x2, %esi
callq 0x1da60
movq %rax, 0x110(%rsp)
jmp 0x1c22e
movq 0x128(%rsp), %rsi
movq 0x110(%rsp), %rax
movl (%rax), %edx
decl %edx
leaq 0x2d8(%rsp), %rdi
callq 0x1b8f0
jmp 0x1c251
leaq 0x518(%rsp), %rdi
leaq 0x2d8(%rsp), %rsi
callq 0x9d10
leaq 0x2c0(%rsp), %rdi
leaq 0x548(%rsp), %rsi
leaq 0x530(%rsp), %rdx
callq 0x9e80
jmp 0x1c285
leaq 0x500(%rsp), %rdi
leaq 0x2c0(%rsp), %rsi
callq 0x1e190
jmp 0x1c29c
leaq 0x2a8(%rsp), %rdi
leaq 0x548(%rsp), %rsi
leaq 0x518(%rsp), %rdx
callq 0x9e80
jmp 0x1c2bb
leaq 0x4e8(%rsp), %rdi
leaq 0x2a8(%rsp), %rsi
callq 0x1e190
jmp 0x1c2d2
movq 0x578(%rsp), %rdi
callq 0x5cb90
movq %rax, 0x108(%rsp)
jmp 0x1c2e9
movq 0x108(%rsp), %rdx
leaq 0x290(%rsp), %rdi
leaq 0x548(%rsp), %rsi
callq 0x9e80
jmp 0x1c308
leaq 0x4d0(%rsp), %rdi
leaq 0x290(%rsp), %rsi
callq 0x1e190
jmp 0x1c31f
xorl %eax, %eax
movl %eax, %esi
leaq 0x500(%rsp), %rdi
callq 0x6130
movq %rax, 0x100(%rsp)
jmp 0x1c33a
movq 0x100(%rsp), %rdx
leaq 0x270(%rsp), %rdi
leaq 0x470(%rsp), %rsi
callq 0x1e8a0
jmp 0x1c359
xorl %eax, %eax
movl %eax, %esi
leaq 0x4e8(%rsp), %rdi
callq 0x6130
movq %rax, 0xf8(%rsp)
jmp 0x1c374
movq 0xf8(%rsp), %rsi
leaq 0x270(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xf0(%rsp)
jmp 0x1c393
movq 0x560(%rsp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x16a90
movq %rax, 0xe8(%rsp)
jmp 0x1c3ae
movq 0xe8(%rsp), %rsi
movq 0xf0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xe0(%rsp)
jmp 0x1c3cd
leaq 0x500(%rsp), %rdi
movl $0x1, %esi
callq 0x6130
movq %rax, 0xd8(%rsp)
jmp 0x1c3e9
movq 0xd8(%rsp), %rsi
movq 0xe0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xd0(%rsp)
jmp 0x1c408
leaq 0x4e8(%rsp), %rdi
movl $0x1, %esi
callq 0x6130
movq %rax, 0xc8(%rsp)
jmp 0x1c424
movq 0xc8(%rsp), %rsi
movq 0xd0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xc0(%rsp)
jmp 0x1c443
movq 0x560(%rsp), %rdi
movl $0x1, %esi
callq 0x16a90
movq %rax, 0xb8(%rsp)
jmp 0x1c45f
movq 0xb8(%rsp), %rsi
movq 0xc0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xb0(%rsp)
jmp 0x1c47e
leaq 0x500(%rsp), %rdi
movl $0x2, %esi
callq 0x6130
movq %rax, 0xa8(%rsp)
jmp 0x1c49a
movq 0xa8(%rsp), %rsi
movq 0xb0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0xa0(%rsp)
jmp 0x1c4b9
leaq 0x4e8(%rsp), %rdi
movl $0x2, %esi
callq 0x6130
movq %rax, 0x98(%rsp)
jmp 0x1c4d5
movq 0x98(%rsp), %rsi
movq 0xa0(%rsp), %rdi
callq 0x1e8e0
movq %rax, 0x90(%rsp)
jmp 0x1c4f4
movq 0x560(%rsp), %rdi
movl $0x2, %esi
callq 0x16a90
movq %rax, 0x88(%rsp)
jmp 0x1c510
movq 0x88(%rsp), %rsi
movq 0x90(%rsp), %rdi
callq 0x1e8e0
jmp 0x1c527
leaq 0x270(%rsp), %rdi
callq 0x1ea60
leaq 0x228(%rsp), %rdi
leaq 0x470(%rsp), %rsi
callq 0x1ea80
jmp 0x1c54b
leaq 0x428(%rsp), %rdi
leaq 0x228(%rsp), %rsi
callq 0x1eab0
leaq 0x1e0(%rsp), %rdi
leaq 0x470(%rsp), %rsi
callq 0x1ea80
jmp 0x1c577
leaq 0x3e0(%rsp), %rdi
leaq 0x1e0(%rsp), %rsi
callq 0x1eab0
leaq 0x198(%rsp), %rdi
leaq 0x470(%rsp), %rsi
callq 0x1ea80
jmp 0x1c5a3
leaq 0x398(%rsp), %rdi
leaq 0x198(%rsp), %rsi
callq 0x1eab0
movl $0x0, 0x194(%rsp)
cmpl $0x3, 0x194(%rsp)
jge 0x1c73c
movslq 0x194(%rsp), %rsi
leaq 0x4d0(%rsp), %rdi
callq 0x6130
movq %rax, 0x80(%rsp)
jmp 0x1c5f0
movq 0x80(%rsp), %rax
movsd (%rax), %xmm0
movsd %xmm0, 0x70(%rsp)
movslq 0x194(%rsp), %rsi
xorl %eax, %eax
movl %eax, %edx
leaq 0x428(%rsp), %rdi
callq 0x1eaf0
movq %rax, 0x78(%rsp)
jmp 0x1c622
movq 0x78(%rsp), %rax
movsd 0x70(%rsp), %xmm0
movsd %xmm0, (%rax)
movslq 0x194(%rsp), %rsi
leaq 0x4d0(%rsp), %rdi
callq 0x6130
movq %rax, 0x68(%rsp)
jmp 0x1c64d
movq 0x68(%rsp), %rax
movsd (%rax), %xmm0
movsd %xmm0, 0x58(%rsp)
movslq 0x194(%rsp), %rsi
leaq 0x3e0(%rsp), %rdi
movl $0x1, %edx
callq 0x1eaf0
movq %rax, 0x60(%rsp)
jmp 0x1c67d
movq 0x60(%rsp), %rax
movsd 0x58(%rsp), %xmm0
movsd %xmm0, (%rax)
movslq 0x194(%rsp), %rsi
leaq 0x4d0(%rsp), %rdi
callq 0x6130
movq %rax, 0x50(%rsp)
jmp 0x1c6a8
movq 0x50(%rsp), %rax
movsd (%rax), %xmm0
movsd %xmm0, 0x40(%rsp)
movslq 0x194(%rsp), %rsi
leaq 0x398(%rsp), %rdi
movl $0x2, %edx
callq 0x1eaf0
movq %rax, 0x48(%rsp)
jmp 0x1c6d8
movq 0x48(%rsp), %rax
movsd 0x40(%rsp), %xmm0
movsd %xmm0, (%rax)
movl 0x194(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x194(%rsp)
jmp 0x1c5c3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x310(%rsp)
movl %eax, 0x30c(%rsp)
jmp 0x1c9e3
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x310(%rsp)
movl %eax, 0x30c(%rsp)
leaq 0x270(%rsp), %rdi
callq 0x1ea60
jmp 0x1c9e3
leaq 0x428(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x38(%rsp)
jmp 0x1c751
leaq 0x470(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x30(%rsp)
jmp 0x1c766
movsd 0x30(%rsp), %xmm1
movsd 0x38(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x390(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x390(%rsp), %xmm0
ja 0x1c7a4
movsd 0x390(%rsp), %xmm0
movsd 0x4086a(%rip), %xmm1    # 0x5d008
ucomisd %xmm1, %xmm0
jbe 0x1c7a9
jmp 0x1c9a9
leaq 0x3e0(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x28(%rsp)
jmp 0x1c7be
leaq 0x470(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x20(%rsp)
jmp 0x1c7d3
movsd 0x20(%rsp), %xmm1
movsd 0x28(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x388(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x388(%rsp), %xmm0
ja 0x1c81a
movsd 0x390(%rsp), %xmm0
addsd 0x388(%rsp), %xmm0
movsd 0x407f4(%rip), %xmm1    # 0x5d008
ucomisd %xmm1, %xmm0
jbe 0x1c81f
jmp 0x1c9a9
leaq 0x398(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x18(%rsp)
jmp 0x1c834
leaq 0x470(%rsp), %rdi
callq 0x1ebc0
movsd %xmm0, 0x10(%rsp)
jmp 0x1c849
movsd 0x10(%rsp), %xmm1
movsd 0x18(%rsp), %xmm0
divsd %xmm1, %xmm0
movsd %xmm0, 0x380(%rsp)
movsd 0x380(%rsp), %xmm1
movsd 0x568(%rsp), %xmm0
ucomisd %xmm1, %xmm0
jbe 0x1c9a7
movsd 0x380(%rsp), %xmm0
movsd 0x45869(%rip), %xmm1    # 0x620f8
ucomisd %xmm1, %xmm0
jbe 0x1c9a7
movq 0x128(%rsp), %rax
movsd 0x380(%rsp), %xmm0
movsd %xmm0, 0x568(%rsp)
testb $0x1, 0x251(%rax)
je 0x1c903
movq 0x128(%rsp), %rsi
movl 0x334(%rsp), %edx
movsd 0x390(%rsp), %xmm0
movsd 0x388(%rsp), %xmm1
leaq 0x178(%rsp), %rdi
callq 0x1bbc0
jmp 0x1c8ec
movq 0x570(%rsp), %rdi
leaq 0x178(%rsp), %rsi
callq 0x9d10
jmp 0x1c936
movq 0x128(%rsp), %rsi
movl 0x334(%rsp), %edx
leaq 0x160(%rsp), %rdi
callq 0x1b990
jmp 0x1c921
movq 0x570(%rsp), %rdi
leaq 0x160(%rsp), %rsi
callq 0x9d10
movq 0x570(%rsp), %rdi
movq 0x560(%rsp), %rsi
callq 0x1e440
movsd %xmm0, 0x8(%rsp)
jmp 0x1c953
movsd 0x8(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x1c9a5
movl $0xffffffff, 0x134(%rsp) # imm = 0xFFFFFFFF
movq 0x570(%rsp), %rdx
leaq 0x138(%rsp), %rdi
leaq 0x134(%rsp), %rsi
callq 0x12100
jmp 0x1c98c
movq 0x570(%rsp), %rdi
leaq 0x138(%rsp), %rsi
callq 0x121c0
jmp 0x1c9a3
jmp 0x1c9a5
jmp 0x1c9a7
jmp 0x1c9a9
leaq 0x340(%rsp), %rdi
callq 0x1ec30
jmp 0x1c10a
movsd 0x568(%rsp), %xmm0
movsd %xmm0, (%rsp)
leaq 0x350(%rsp), %rdi
callq 0x1ec60
movsd (%rsp), %xmm0
addq $0x588, %rsp            # imm = 0x588
retq
leaq 0x350(%rsp), %rdi
callq 0x1ec60
movq 0x310(%rsp), %rdi
callq 0x45e0
nopl (%rax)