// File: IsaacLaw12[P]RayTracer/./src/RenderImage.cpp
// Function: RenderImage::calculate_color(Ray&, double, SceneObject*, Eigen::Matrix<double, 3, 1, 0, 3, 1>&, Eigen::Matrix<double, 3, 1, 0, 3, 1>&, Eigen::Matrix<double, 3, 1, 0, 3, 1>&, int)
void RenderImage::calculate_color(Ray& ray, double t_value, SceneObject* hit_obj, Eigen::Vector3d &hit_normal, Eigen::Vector3d &accum, Eigen::Vector3d &ampl, int level){
    Eigen::Vector3d vector_to_light, intersect_pos, dif_refl, color;
    Eigen::Vector3d obj_intsct_vector, light_reflect_point;
    if (t_value == MISSED_T_VALUE){
        accum << 0,0,0;
        return;
    }
    color = hit_obj->get_ambient_color() * scene->get_ambient();
    double light_concentration, proximity_reflection;
    intersect_pos = ray.get_ray_loc(t_value);

    for(Light light:scene->get_lights()){
        if (light.get_lighting_group() != hit_obj->get_lighting_group()){
            continue;
        }
        if (!lightReachesObject(light, intersect_pos)){
            continue;
        }
        // Diffuse reflection
        vector_to_light = (light.get_pos() - intersect_pos).normalized();
        light_concentration = hit_normal.dot(vector_to_light);
        if (light_concentration < 0){
                continue;
        }

        dif_refl =  hit_obj->get_diffuse_color() * light.get_color() * light_concentration;
        color += dif_refl;
        // Specular reflection

        // The vector from the intersect point to the camera
        obj_intsct_vector = (ray.get_point() - intersect_pos).normalized();
        // The point opposite the light flipped on the normal
        light_reflect_point = (2 * hit_normal.dot(vector_to_light) *  hit_normal) - vector_to_light;
        proximity_reflection = obj_intsct_vector.dot(light_reflect_point);
        if (proximity_reflection > 0.0){
            color += hit_obj->get_specular_color() * light.get_color() * std::pow(proximity_reflection, hit_obj->get_phong());
        }

    }
    accum = accum + ampl.cwiseProduct(color);

    Eigen::Vector3d kr_ampl = hit_obj->get_kr() * ampl;
    Eigen::Matrix3d ko = hit_obj->get_ko();
    double opacity = (ko * Eigen::Vector3d(1,1,1)).dot(Eigen::Vector3d(1,1,1));
    double dummy_t = 0;
    // Reflections
    if (level > 0){
        Eigen::Vector3d reflect_accum = Eigen::Vector3d::Zero();
        Eigen::Vector3d w = -1 * ray.get_dir();
        Eigen::Vector3d ray_dir = (2 * hit_normal.dot(w) * hit_normal - w).normalized();
        Ray reflect_ray = Ray(intersect_pos, ray_dir);
        ray_trace(reflect_ray, reflect_accum, kr_ampl, --level, dummy_t);
        Eigen::Vector3d reflect_ampl = ko * ampl;
        accum = accum + reflect_ampl.cwiseProduct(reflect_accum);
    }
    // Calculate refraction
    if (level > 0 && opacity < 3.0){
        Eigen::Vector3d refract_accum = Eigen::Vector3d::Zero();
        Ray refract_ray = hit_obj->get_refracted_ray(ray, intersect_pos, hit_normal);
        ray_trace(refract_ray, refract_accum, kr_ampl, --level, dummy_t);
        Eigen::Vector3d refract_ampl = (Eigen::Matrix3d::Identity() - ko) * ampl;
        accum = accum + refract_ampl.cwiseProduct(refract_accum);
    }
    return;
}

// Assembly:
subq $0x8a8, %rsp            # imm = 0x8A8
movl 0x8b0(%rsp), %eax
movq %rdi, 0x8a0(%rsp)
movq %rsi, 0x898(%rsp)
movsd %xmm0, 0x890(%rsp)
movq %rdx, 0x888(%rsp)
movq %rcx, 0x880(%rsp)
movq %r8, 0x878(%rsp)
movq %r9, 0x870(%rsp)
movq 0x8a0(%rsp), %rax
movq %rax, 0x40(%rsp)
leaq 0x858(%rsp), %rdi
callq 0x11e20
leaq 0x840(%rsp), %rdi
callq 0x11e20
leaq 0x828(%rsp), %rdi
callq 0x11e20
leaq 0x810(%rsp), %rdi
callq 0x11e20
leaq 0x7f8(%rsp), %rdi
callq 0x11e20
leaq 0x7e0(%rsp), %rdi
callq 0x11e20
movq 0x40(%rsp), %rax
movsd 0x890(%rsp), %xmm0
ucomisd 0x8(%rax), %xmm0
jne 0x30dcc
jp 0x30dcc
movq 0x878(%rsp), %rsi
movq $0x0, 0x7b8(%rsp)
leaq 0x7c0(%rsp), %rdi
movq %rdi, 0x30(%rsp)
leaq 0x7b8(%rsp), %rdx
callq 0x11f20
movq 0x30(%rsp), %rdi
movq $0x0, 0x7b0(%rsp)
leaq 0x7b0(%rsp), %rsi
callq 0x11f60
movq %rax, 0x38(%rsp)
jmp 0x30d74
movq 0x38(%rsp), %rdi
movq $0x0, 0x798(%rsp)
leaq 0x798(%rsp), %rsi
callq 0x11f60
jmp 0x30d94
leaq 0x7c0(%rsp), %rdi
callq 0x120e0
jmp 0x31742
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0x7a8(%rsp)
movl %eax, 0x7a4(%rsp)
leaq 0x7c0(%rsp), %rdi
callq 0x120e0
jmp 0x3174a
movq 0x888(%rsp), %rsi
leaq 0x740(%rsp), %rdi
callq 0x43120
movq 0x40(%rsp), %rax
movq (%rax), %rdi
callq 0x3f5d0
movq %rax, %rsi
leaq 0x740(%rsp), %rdi
callq 0x31bf0
movq %rax, 0x788(%rsp)
movq %rdx, 0x790(%rsp)
leaq 0x810(%rsp), %rdi
leaq 0x788(%rsp), %rsi
callq 0x31c40
movq 0x898(%rsp), %rsi
movsd 0x890(%rsp), %xmm0
leaq 0x718(%rsp), %rdi
callq 0x5cbb0
leaq 0x840(%rsp), %rdi
leaq 0x718(%rsp), %rsi
callq 0x9d10
movq 0x40(%rsp), %rax
movq (%rax), %rdi
callq 0x3f640
movq %rax, 0x710(%rsp)
movq 0x710(%rsp), %rdi
callq 0x31c70
movq %rax, 0x708(%rsp)
movq 0x710(%rsp), %rdi
callq 0x31ca0
movq %rax, 0x700(%rsp)
leaq 0x708(%rsp), %rdi
leaq 0x700(%rsp), %rsi
callq 0x31cd0
testb $0x1, %al
jne 0x30eb3
jmp 0x3121f
leaq 0x708(%rsp), %rdi
callq 0x31d10
movq %rax, %rsi
leaq 0x6b8(%rsp), %rdi
callq 0x31d20
leaq 0x6b8(%rsp), %rdi
callq 0x11e10
movl %eax, 0x2c(%rsp)
movq 0x888(%rsp), %rdi
callq 0x43210
movl %eax, %ecx
movl 0x2c(%rsp), %eax
cmpl %ecx, %eax
je 0x30efd
jmp 0x3120d
leaq 0x6a0(%rsp), %rdi
leaq 0x840(%rsp), %rsi
callq 0xa4f0
movq 0x40(%rsp), %rdi
leaq 0x6b8(%rsp), %rsi
leaq 0x6a0(%rsp), %rdx
callq 0x31760
testb $0x1, %al
jne 0x30f35
jmp 0x3120d
leaq 0x658(%rsp), %rdi
leaq 0x6b8(%rsp), %rsi
callq 0x11db0
leaq 0x670(%rsp), %rdi
leaq 0x658(%rsp), %rsi
leaq 0x840(%rsp), %rdx
callq 0x9e80
leaq 0x688(%rsp), %rdi
leaq 0x670(%rsp), %rsi
callq 0x9ef0
leaq 0x858(%rsp), %rdi
leaq 0x688(%rsp), %rsi
callq 0x9e50
movq 0x880(%rsp), %rdi
leaq 0x858(%rsp), %rsi
callq 0x1e440
movsd %xmm0, 0x738(%rsp)
xorps %xmm0, %xmm0
ucomisd 0x738(%rsp), %xmm0
jbe 0x30fc2
jmp 0x3120d
movq 0x888(%rsp), %rsi
leaq 0x5d8(%rsp), %rdi
callq 0x430f0
leaq 0x5c0(%rsp), %rdi
leaq 0x6b8(%rsp), %rsi
callq 0x11de0
leaq 0x5d8(%rsp), %rdi
leaq 0x5c0(%rsp), %rsi
callq 0x31bf0
movq %rax, 0x620(%rsp)
movq %rdx, 0x628(%rsp)
leaq 0x630(%rsp), %rdi
leaq 0x620(%rsp), %rsi
leaq 0x738(%rsp), %rdx
callq 0x31d90
leaq 0x828(%rsp), %rdi
leaq 0x630(%rsp), %rsi
callq 0x31e50
leaq 0x810(%rsp), %rdi
leaq 0x828(%rsp), %rsi
callq 0x31e80
movq 0x898(%rsp), %rdi
callq 0x5cb90
movq %rax, %rsi
leaq 0x590(%rsp), %rdi
leaq 0x840(%rsp), %rdx
callq 0x9e80
leaq 0x5a8(%rsp), %rdi
leaq 0x590(%rsp), %rsi
callq 0x9ef0
leaq 0x7f8(%rsp), %rdi
leaq 0x5a8(%rsp), %rsi
callq 0x9e50
movq 0x880(%rsp), %rdi
leaq 0x858(%rsp), %rsi
callq 0x1e440
movaps %xmm0, %xmm1
movsd 0x35b99(%rip), %xmm0    # 0x66c60
mulsd %xmm1, %xmm0
movsd %xmm0, 0x520(%rsp)
movq 0x880(%rsp), %rdx
leaq 0x528(%rsp), %rdi
leaq 0x520(%rsp), %rsi
callq 0xa310
leaq 0x550(%rsp), %rdi
leaq 0x528(%rsp), %rsi
leaq 0x858(%rsp), %rdx
callq 0x31ef0
leaq 0x7e0(%rsp), %rdi
leaq 0x550(%rsp), %rsi
callq 0x31f60
leaq 0x7f8(%rsp), %rdi
leaq 0x7e0(%rsp), %rsi
callq 0x1e440
movsd %xmm0, 0x730(%rsp)
movsd 0x730(%rsp), %xmm0
xorps %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jbe 0x3120b
movq 0x888(%rsp), %rsi
leaq 0x4a0(%rsp), %rdi
callq 0x43150
leaq 0x488(%rsp), %rdi
leaq 0x6b8(%rsp), %rsi
callq 0x11de0
leaq 0x4a0(%rsp), %rdi
leaq 0x488(%rsp), %rsi
callq 0x31bf0
movq %rax, 0x4e8(%rsp)
movq %rdx, 0x4f0(%rsp)
movsd 0x730(%rsp), %xmm0
movsd %xmm0, 0x20(%rsp)
movq 0x888(%rsp), %rdi
callq 0x430b0
movaps %xmm0, %xmm1
movsd 0x20(%rsp), %xmm0
callq 0x45d0
movsd %xmm0, 0x480(%rsp)
leaq 0x4f8(%rsp), %rdi
leaq 0x4e8(%rsp), %rsi
leaq 0x480(%rsp), %rdx
callq 0x31d90
leaq 0x810(%rsp), %rdi
leaq 0x4f8(%rsp), %rsi
callq 0x31f90
jmp 0x3120d
leaq 0x708(%rsp), %rdi
callq 0x32000
jmp 0x30e95
movq 0x878(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x870(%rsp), %rsi
leaq 0x440(%rsp), %rdi
leaq 0x810(%rsp), %rdx
callq 0x32090
movq 0x18(%rsp), %rsi
leaq 0x458(%rsp), %rdi
leaq 0x440(%rsp), %rdx
callq 0x32020
movq 0x878(%rsp), %rdi
leaq 0x458(%rsp), %rsi
callq 0x32100
movq 0x888(%rsp), %rsi
leaq 0x3d0(%rsp), %rdi
callq 0x431b0
movq 0x870(%rsp), %rsi
leaq 0x3d0(%rsp), %rdi
callq 0x31bf0
movq %rax, 0x418(%rsp)
movq %rdx, 0x420(%rsp)
leaq 0x428(%rsp), %rdi
leaq 0x418(%rsp), %rsi
callq 0x32130
movq 0x888(%rsp), %rsi
leaq 0x388(%rsp), %rdi
callq 0x431e0
movsd 0x2bd24(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x350(%rsp)
movsd 0x2bd13(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x348(%rsp)
movsd 0x2bd02(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x340(%rsp)
leaq 0x358(%rsp), %rdi
leaq 0x350(%rsp), %rsi
leaq 0x348(%rsp), %rdx
leaq 0x340(%rsp), %rcx
callq 0x9c70
leaq 0x388(%rsp), %rdi
leaq 0x358(%rsp), %rsi
callq 0x31bf0
movq %rax, 0x370(%rsp)
movq %rdx, 0x378(%rsp)
movsd 0x2bca7(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x320(%rsp)
movsd 0x2bc96(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x318(%rsp)
movsd 0x2bc85(%rip), %xmm0    # 0x5d008
movsd %xmm0, 0x310(%rsp)
leaq 0x328(%rsp), %rdi
leaq 0x320(%rsp), %rsi
leaq 0x318(%rsp), %rdx
leaq 0x310(%rsp), %rcx
callq 0x9c70
leaq 0x370(%rsp), %rdi
leaq 0x328(%rsp), %rsi
callq 0x32170
movsd %xmm0, 0x380(%rsp)
xorps %xmm0, %xmm0
movsd %xmm0, 0x308(%rsp)
cmpl $0x0, 0x8b0(%rsp)
jle 0x315e4
leaq 0x2e0(%rsp), %rdi
callq 0x9c00
leaq 0x2f0(%rsp), %rdi
leaq 0x2e0(%rsp), %rsi
callq 0x9c30
movl $0xffffffff, 0x29c(%rsp) # imm = 0xFFFFFFFF
movq 0x898(%rsp), %rdi
callq 0x5cba0
movq %rax, %rdx
leaq 0x2a0(%rsp), %rdi
leaq 0x29c(%rsp), %rsi
callq 0x12100
leaq 0x2c8(%rsp), %rdi
leaq 0x2a0(%rsp), %rsi
callq 0x1ec70
movq 0x880(%rsp), %rdi
leaq 0x2c8(%rsp), %rsi
callq 0x1e440
movaps %xmm0, %xmm1
movsd 0x357f0(%rip), %xmm0    # 0x66c60
mulsd %xmm1, %xmm0
movsd %xmm0, 0x210(%rsp)
movq 0x880(%rsp), %rdx
leaq 0x218(%rsp), %rdi
leaq 0x210(%rsp), %rsi
callq 0xa310
leaq 0x240(%rsp), %rdi
leaq 0x218(%rsp), %rsi
leaq 0x2c8(%rsp), %rdx
callq 0x31ef0
leaq 0x280(%rsp), %rdi
leaq 0x240(%rsp), %rsi
callq 0x321e0
leaq 0x1c0(%rsp), %rdi
leaq 0x840(%rsp), %rsi
callq 0xa4f0
leaq 0x1a8(%rsp), %rdi
leaq 0x280(%rsp), %rsi
callq 0xa4f0
leaq 0x1d8(%rsp), %rdi
leaq 0x1c0(%rsp), %rsi
leaq 0x1a8(%rsp), %rdx
callq 0x5ca90
movq 0x40(%rsp), %rdi
movl 0x8b0(%rsp), %r8d
addl $-0x1, %r8d
movl %r8d, 0x8b0(%rsp)
leaq 0x1d8(%rsp), %rsi
leaq 0x2f0(%rsp), %rdx
leaq 0x428(%rsp), %rcx
leaq 0x308(%rsp), %r9
callq 0x30a60
movq 0x870(%rsp), %rsi
leaq 0x388(%rsp), %rdi
callq 0x31bf0
movq %rax, 0x180(%rsp)
movq %rdx, 0x188(%rsp)
leaq 0x190(%rsp), %rdi
leaq 0x180(%rsp), %rsi
callq 0x32130
movq 0x878(%rsp), %rax
movq %rax, 0x10(%rsp)
leaq 0x140(%rsp), %rdi
leaq 0x190(%rsp), %rsi
leaq 0x2f0(%rsp), %rdx
callq 0x32090
movq 0x10(%rsp), %rsi
leaq 0x158(%rsp), %rdi
leaq 0x140(%rsp), %rdx
callq 0x32020
movq 0x878(%rsp), %rdi
leaq 0x158(%rsp), %rsi
callq 0x32100
cmpl $0x0, 0x8b0(%rsp)
jle 0x31740
movsd 0x3566e(%rip), %xmm0    # 0x66c68
ucomisd 0x380(%rsp), %xmm0
jbe 0x31740
leaq 0x118(%rsp), %rdi
callq 0x9c00
leaq 0x128(%rsp), %rdi
leaq 0x118(%rsp), %rsi
callq 0x9c30
movq 0x888(%rsp), %rsi
movq 0x898(%rsp), %rdx
movq 0x880(%rsp), %r8
movq (%rsi), %rax
leaq 0xe0(%rsp), %rdi
leaq 0x840(%rsp), %rcx
callq *0x18(%rax)
movq 0x40(%rsp), %rdi
movl 0x8b0(%rsp), %r8d
addl $-0x1, %r8d
movl %r8d, 0x8b0(%rsp)
leaq 0xe0(%rsp), %rsi
leaq 0x128(%rsp), %rdx
leaq 0x428(%rsp), %rcx
leaq 0x308(%rsp), %r9
callq 0x30a60
leaq 0x8d(%rsp), %rdi
callq 0x1ef70
leaq 0x90(%rsp), %rdi
leaq 0x8d(%rsp), %rsi
leaq 0x388(%rsp), %rdx
callq 0x322f0
movq 0x870(%rsp), %rdx
leaq 0xa8(%rsp), %rdi
leaq 0x90(%rsp), %rsi
callq 0x32360
leaq 0xc8(%rsp), %rdi
leaq 0xa8(%rsp), %rsi
callq 0x323c0
movq 0x878(%rsp), %rax
movq %rax, 0x8(%rsp)
leaq 0x48(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
leaq 0x128(%rsp), %rdx
callq 0x32090
movq 0x8(%rsp), %rsi
leaq 0x60(%rsp), %rdi
leaq 0x48(%rsp), %rdx
callq 0x32020
movq 0x878(%rsp), %rdi
leaq 0x60(%rsp), %rsi
callq 0x32100
jmp 0x31742
addq $0x8a8, %rsp            # imm = 0x8A8
retq
movq 0x7a8(%rsp), %rdi
callq 0x45e0
nopw (%rax,%rax)