// File: tomfunkhouser[P]gaps/pkgs/R3Graphics/R3Viewer.cpp
// Function: gaps::R3Viewer::WorldRay(double, double) const
const R3Ray R3Viewer::
WorldRay(RNCoord x, RNCoord y) const
{
    // Return ray from camera origin to appropriate point on far plane
#if FALSE
    // This also works
    RNScalar dx = (RNScalar) (2 * (x - viewport.XCenter())) / (RNScalar) viewport.Width();
    RNScalar dy = (RNScalar) (2 * (y - viewport.YCenter())) / (RNScalar) viewport.Height();
    R3Vector v = camera.Towards();
    v.Rotate(camera.Up(), dx * camera.XFOV());
    v.Rotate(camera.Left(), dy * camera.YFOV());
    return R3Ray(camera.Origin(), v);
#else
    RNScalar dx = (RNScalar) (2 * (x - viewport.XCenter())) / (RNScalar) viewport.Width();
    RNScalar dy = (RNScalar) (2 * (y - viewport.YCenter())) / (RNScalar) viewport.Height();
    R3Point far_org = camera.Origin() + camera.Towards() * camera.Far();
    R3Vector far_right = camera.Right() * camera.Far() * tan(camera.XFOV());
    R3Vector far_up = camera.Up() * camera.Far() * tan(camera.YFOV());
    R3Point far_point = far_org + (far_right * dx) + (far_up * dy);
    return R3Ray(camera.Origin(), far_point);
#endif
}

// Assembly:
subq $0x188, %rsp            # imm = 0x188
movq %rdi, 0x40(%rsp)
movq %rdi, %rax
movq %rax, 0x48(%rsp)
movq %rdi, 0x180(%rsp)
movq %rsi, 0x178(%rsp)
movsd %xmm0, 0x170(%rsp)
movsd %xmm1, 0x168(%rsp)
movq 0x178(%rsp), %rdi
movq %rdi, 0x38(%rsp)
movsd 0x170(%rsp), %xmm0
movsd %xmm0, (%rsp)
addq $0x98, %rdi
callq 0x5d3b0
movsd (%rsp), %xmm1
movq 0x38(%rsp), %rdi
cvtsi2sd %eax, %xmm0
subsd %xmm0, %xmm1
movsd 0x132339(%rip), %xmm0   # 0x18e050
mulsd %xmm1, %xmm0
movsd %xmm0, 0x8(%rsp)
addq $0x98, %rdi
callq 0x2be50
movsd 0x8(%rsp), %xmm0
movq 0x38(%rsp), %rdi
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x160(%rsp)
movsd 0x168(%rsp), %xmm0
movsd %xmm0, 0x10(%rsp)
addq $0x98, %rdi
callq 0x5d3e0
movsd 0x10(%rsp), %xmm1
movq 0x38(%rsp), %rdi
cvtsi2sd %eax, %xmm0
subsd %xmm0, %xmm1
movsd 0x1322d1(%rip), %xmm0   # 0x18e050
mulsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rsp)
addq $0x98, %rdi
callq 0x2be60
movsd 0x18(%rsp), %xmm0
movq 0x38(%rsp), %rdi
cvtsi2sd %eax, %xmm1
divsd %xmm1, %xmm0
movsd %xmm0, 0x158(%rsp)
addq $0x8, %rdi
callq 0x2b900
movq 0x38(%rsp), %rsi
movq %rax, 0x20(%rsp)
addq $0x8, %rsi
leaq 0x110(%rsp), %rdi
callq 0x2b770
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x49470
leaq 0x128(%rsp), %rdi
leaq 0x110(%rsp), %rsi
callq 0xce8a0
movq 0x20(%rsp), %rsi
leaq 0x140(%rsp), %rdi
leaq 0x128(%rsp), %rdx
callq 0xcce30
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x2b720
movq 0x38(%rsp), %rdi
movq %rax, 0x28(%rsp)
addq $0x8, %rdi
callq 0x49470
movq 0x28(%rsp), %rsi
leaq 0xe0(%rsp), %rdi
callq 0xce8a0
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x2b940
callq 0x22520
leaq 0xf8(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0xce8a0
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x2b890
movq 0x38(%rsp), %rdi
movq %rax, 0x30(%rsp)
addq $0x8, %rdi
callq 0x49470
movq 0x30(%rsp), %rsi
leaq 0xb0(%rsp), %rdi
callq 0xce8a0
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x2b950
callq 0x22520
leaq 0xc8(%rsp), %rdi
leaq 0xb0(%rsp), %rsi
callq 0xce8a0
movsd 0x160(%rsp), %xmm0
leaq 0x68(%rsp), %rdi
leaq 0xf8(%rsp), %rsi
callq 0xce8a0
leaq 0x80(%rsp), %rdi
leaq 0x140(%rsp), %rsi
leaq 0x68(%rsp), %rdx
callq 0xcce30
movsd 0x158(%rsp), %xmm0
leaq 0x50(%rsp), %rdi
leaq 0xc8(%rsp), %rsi
callq 0xce8a0
leaq 0x98(%rsp), %rdi
leaq 0x80(%rsp), %rsi
leaq 0x50(%rsp), %rdx
callq 0xcce30
movq 0x38(%rsp), %rdi
addq $0x8, %rdi
callq 0x2b900
movq 0x40(%rsp), %rdi
movq %rax, %rsi
leaq 0x98(%rsp), %rdx
callq 0xcc1a0
movq 0x48(%rsp), %rax
addq $0x188, %rsp            # imm = 0x188
retq
nopw %cs:(%rax,%rax)