// File: kryffin[P]software-rasterizer/./geometry.cpp
// Function: lookAt(Vec3f, Vec3f, Vec3f)
Mat4f lookAt (Vec3f eye, Vec3f target, Vec3f upDir) {
    // compute the forward vector from target to eye
    Vec3f forward = (eye - target).normalize();

    // compute the left vector
    Vec3f left = (upDir.cross(forward)).normalize(); // cross product

    // recompute the orthonormal up vector
    Vec3f up = forward.cross(left);    // cross product

    // init 4x4 matrix
    Mat4f M = Mat4f(1.f);

    // set rotation part, inverse rotation matrix: M^-1 = M^T for Euclidean transform
    M.m[0][0] = left.x;
    M.m[1][0] = left.y;
    M.m[2][0] = left.z;
    M.m[0][1] = up.x;
    M.m[1][1] = up.y;
    M.m[2][1] = up.z;
    M.m[0][2] = forward.x;
    M.m[1][2] = forward.y;
    M.m[2][2] = forward.z;

    // set translation part
    M.m[3][0] = -left.x * eye.x - left.y * eye.y - left.z * eye.z;
    M.m[3][1] = -up.x * eye.x - up.y * eye.y - up.z * eye.z;
    M.m[3][2] = -forward.x * eye.x - forward.y * eye.y - forward.z * eye.z;

    return M;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x168(%rbp)
movq %rdi, -0x160(%rbp)
movlpd %xmm0, -0x20(%rbp)
movss %xmm1, -0x18(%rbp)
movl -0x18(%rbp), %eax
movl %eax, -0x8(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x10(%rbp)
movlpd %xmm2, -0x40(%rbp)
movss %xmm3, -0x38(%rbp)
movl -0x38(%rbp), %eax
movl %eax, -0x28(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x30(%rbp)
movlpd %xmm4, -0x60(%rbp)
movss %xmm5, -0x58(%rbp)
movl -0x58(%rbp), %eax
movl %eax, -0x48(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x50(%rbp)
movl -0x28(%rbp), %eax
movl %eax, -0x88(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0x90(%rbp)
movl -0x88(%rbp), %eax
movl %eax, -0x98(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0xa0(%rbp)
movsd -0xa0(%rbp), %xmm0
movss -0x98(%rbp), %xmm1
leaq -0x10(%rbp), %rdi
callq 0x5260
movss %xmm1, -0xa8(%rbp)
movlpd %xmm0, -0xb0(%rbp)
movl -0xa8(%rbp), %eax
movl %eax, -0x78(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0x80(%rbp)
leaq -0x80(%rbp), %rdi
callq 0x52e0
movss %xmm1, -0xb8(%rbp)
movlpd %xmm0, -0xc0(%rbp)
movl -0xb8(%rbp), %eax
movl %eax, -0x68(%rbp)
movq -0xc0(%rbp), %rax
movq %rax, -0x70(%rbp)
movl -0x68(%rbp), %eax
movl %eax, -0xe8(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0xf0(%rbp)
movl -0xe8(%rbp), %eax
movl %eax, -0xf8(%rbp)
movq -0xf0(%rbp), %rax
movq %rax, -0x100(%rbp)
movsd -0x100(%rbp), %xmm0
movss -0xf8(%rbp), %xmm1
leaq -0x50(%rbp), %rdi
callq 0x5350
movss %xmm1, -0x108(%rbp)
movlpd %xmm0, -0x110(%rbp)
movl -0x108(%rbp), %eax
movl %eax, -0xd8(%rbp)
movq -0x110(%rbp), %rax
movq %rax, -0xe0(%rbp)
leaq -0xe0(%rbp), %rdi
callq 0x52e0
movss %xmm1, -0x118(%rbp)
movlpd %xmm0, -0x120(%rbp)
movl -0x118(%rbp), %eax
movl %eax, -0xc8(%rbp)
movq -0x120(%rbp), %rax
movq %rax, -0xd0(%rbp)
movl -0xc8(%rbp), %eax
movl %eax, -0x130(%rbp)
movq -0xd0(%rbp), %rax
movq %rax, -0x138(%rbp)
movl -0x130(%rbp), %eax
movl %eax, -0x140(%rbp)
movq -0x138(%rbp), %rax
movq %rax, -0x148(%rbp)
movsd -0x148(%rbp), %xmm0
movss -0x140(%rbp), %xmm1
leaq -0x70(%rbp), %rdi
callq 0x5350
movq -0x168(%rbp), %rdi
movss %xmm1, -0x150(%rbp)
movlpd %xmm0, -0x158(%rbp)
movq -0x158(%rbp), %rax
movq %rax, -0x12c(%rbp)
movl -0x150(%rbp), %eax
movl %eax, -0x124(%rbp)
movss 0x8742(%rip), %xmm0     # 0xb008
callq 0x53f0
movq -0x168(%rbp), %rdi
movq -0x160(%rbp), %rax
movss -0xd0(%rbp), %xmm0
movss %xmm0, (%rdi)
movss -0xcc(%rbp), %xmm0
movss %xmm0, 0x10(%rdi)
movss -0xc8(%rbp), %xmm0
movss %xmm0, 0x20(%rdi)
movss -0x12c(%rbp), %xmm0
movss %xmm0, 0x4(%rdi)
movss -0x128(%rbp), %xmm0
movss %xmm0, 0x14(%rdi)
movss -0x124(%rbp), %xmm0
movss %xmm0, 0x24(%rdi)
movss -0x70(%rbp), %xmm0
movss %xmm0, 0x8(%rdi)
movss -0x6c(%rbp), %xmm0
movss %xmm0, 0x18(%rdi)
movss -0x68(%rbp), %xmm0
movss %xmm0, 0x28(%rdi)
movss -0xd0(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm1
movss -0x10(%rbp), %xmm2
movss -0xcc(%rbp), %xmm0
mulss -0xc(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm1
addss %xmm0, %xmm1
movss -0xc8(%rbp), %xmm0
movss -0x8(%rbp), %xmm2
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
movss %xmm0, 0x30(%rdi)
movss -0x12c(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm1
movss -0x10(%rbp), %xmm2
movss -0x128(%rbp), %xmm0
mulss -0xc(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm1
addss %xmm0, %xmm1
movss -0x124(%rbp), %xmm0
movss -0x8(%rbp), %xmm2
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
movss %xmm0, 0x34(%rdi)
movss -0x70(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm1
movss -0x10(%rbp), %xmm2
movss -0x6c(%rbp), %xmm0
mulss -0xc(%rbp), %xmm0
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm1
addss %xmm0, %xmm1
movss -0x68(%rbp), %xmm0
movss -0x8(%rbp), %xmm2
movd %xmm0, %ecx
xorl $0x80000000, %ecx       # imm = 0x80000000
movd %ecx, %xmm0
mulss %xmm2, %xmm0
addss %xmm1, %xmm0
movss %xmm0, 0x38(%rdi)
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
nopw %cs:(%rax,%rax)