// File: tomfunkhouser[P]gaps/pkgs/R3Shapes/R3Quaternion.cpp
// Function: gaps::R3Quaternion::R3Quaternion(gaps::R4Matrix const&, int)
R3Quaternion::
R3Quaternion(const R4Matrix& m, int /* dummy */)
{
#if 1
    // From http://www.cg.info.hiroshima-cu.ac.jp/~miyazaki/knowledge/teche52.html
    v[0] = ( m[0][0] + m[1][1] + m[2][2] + 1.0) / 4.0;
    v[1] = ( m[0][0] - m[1][1] - m[2][2] + 1.0) / 4.0;
    v[2] = (-m[0][0] + m[1][1] - m[2][2] + 1.0) / 4.0;
    v[3] = (-m[0][0] - m[1][1] + m[2][2] + 1.0) / 4.0;
    if (v[0] < 0.0) v[0] = 0.0;
    if (v[1] < 0.0) v[1] = 0.0;
    if (v[2] < 0.0) v[2] = 0.0;
    if (v[3] < 0.0) v[3] = 0.0;
    v[0] = sqrt(v[0]);
    v[1] = sqrt(v[1]);
    v[2] = sqrt(v[2]);
    v[3] = sqrt(v[3]);
    if ((v[0] >= v[1]) && (v[0] >= v[2]) && (v[0] >= v[3])) {
        v[1] *= RNSign(m[2][1] - m[1][2]);
        v[2] *= RNSign(m[0][2] - m[2][0]);
        v[3] *= RNSign(m[1][0] - m[0][1]);
    } 
    else if ((v[1] >= v[0]) && (v[1] >= v[2]) && (v[1] >= v[3])) {
        v[0] *= RNSign(m[2][1] - m[1][2]);
        v[2] *= RNSign(m[1][0] + m[0][1]);
        v[3] *= RNSign(m[0][2] + m[2][0]);
    } 
    else if ((v[2] >= v[0]) && (v[2] >= v[1]) && (v[2] >= v[3])) {
        v[0] *= RNSign(m[0][2] - m[2][0]);
        v[1] *= RNSign(m[1][0] + m[0][1]);
        v[3] *= RNSign(m[2][1] + m[1][2]);
    } 
    else if ((v[3] >= v[0]) && (v[3] >= v[1]) && (v[3] >= v[2])) {
        v[0] *= RNSign(m[1][0] - m[0][1]);
        v[1] *= RNSign(m[2][0] + m[0][2]);
        v[2] *= RNSign(m[2][1] + m[1][2]);
    } 
    else {
        v[0] = 0;
        v[1] = 0;
        v[2] = 0;
        v[3] = 0;
    }
#elif 0
    // Also probably works
    // From http://vamos.sourceforge.net/matrixfaq.htm#Q48
    RNScalar T = m[0][0] + m[1][1] + m[2][2] + 1.0;
    if (T > 0.0) {
        RNScalar S = 0.5 / sqrt(T);
        v[0] = 0.25 / S;
        v[1] = ( m[2][1] - m[1][2] ) * S;
        v[2] = ( m[0][2] - m[2][0] ) * S;
        v[3] = ( m[1][0] - m[0][1] ) * S;
    }
    else {
        if ((m[0][0] >= m[1][1]) && (m[0][0] >= m[2][2])) {
            RNScalar S  = sqrt( 1.0 + m[0][0] - m[1][1] - m[2][2] ) * 2.0;
            v[1] = 0.5 / S;
            v[2] = (m[0][1] + m[1][0] ) / S;
            v[3] = (m[0][2] + m[2][0] ) / S;
            v[0] = (m[1][2] + m[2][1] ) / S;
        }
        else if ((m[1][1] >= m[0][0]) && (m[1][1] >= m[2][2])) {
            RNScalar S  = sqrt( 1.0 + m[1][1] - m[0][0] - m[2][2] ) * 2;
            v[1] = (m[0][1] + m[1][0] ) / S;
            v[2] = 0.5 / S;
            v[3] = (m[1][2] + m[2][1] ) / S;
            v[0] = (m[0][2] + m[2][0] ) / S;
        }
        else if ((m[2][2] >= m[0][0]) && (m[2][2] >= m[1][1])) {
            RNScalar S  = sqrt( 1.0 + m[2][2] - m[0][0] - m[1][1] ) * 2;
            v[1] = (m[0][2] + m[2][0] ) / S;
            v[2] = (m[1][2] + m[2][1] ) / S;
            v[3] = 0.5 / S;
            v[0] = (m[0][1] + m[1][0] ) / S;
        }
    }
#else
    RNAbort("Not implemented");
#endif

    // Normalize
    Normalize();
}

// Assembly:
subq $0xc8, %rsp
movq %rdi, 0xc0(%rsp)
movq %rsi, 0xb8(%rsp)
movl %edx, 0xb4(%rsp)
movq 0xc0(%rsp), %rax
movq %rax, 0xa8(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x68(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x68(%rsp), %xmm0
addsd 0x8(%rax), %xmm0
movsd %xmm0, 0x70(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x70(%rsp), %xmm0
movq %rax, %rcx
movq 0xa8(%rsp), %rax
addsd 0x10(%rcx), %xmm0
movsd 0xe2fbe(%rip), %xmm1    # 0x133008
addsd %xmm1, %xmm0
movsd 0xe319a(%rip), %xmm1    # 0x1331f0
divsd %xmm1, %xmm0
movsd %xmm0, (%rax)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x78(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x78(%rsp), %xmm0
subsd 0x8(%rax), %xmm0
movsd %xmm0, 0x80(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x80(%rsp), %xmm0
movq %rax, %rcx
movq 0xa8(%rsp), %rax
subsd 0x10(%rcx), %xmm0
movsd 0xe2f38(%rip), %xmm1    # 0x133008
addsd %xmm1, %xmm0
movsd 0xe3114(%rip), %xmm1    # 0x1331f0
divsd %xmm1, %xmm0
movsd %xmm0, 0x8(%rax)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd (%rax), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, 0x88(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x88(%rsp), %xmm0
addsd 0x8(%rax), %xmm0
movsd %xmm0, 0x90(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x90(%rsp), %xmm0
movq %rax, %rcx
movq 0xa8(%rsp), %rax
subsd 0x10(%rcx), %xmm0
movsd 0xe2e94(%rip), %xmm1    # 0x133008
addsd %xmm1, %xmm0
movsd 0xe3070(%rip), %xmm1    # 0x1331f0
divsd %xmm1, %xmm0
movsd %xmm0, 0x10(%rax)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd (%rax), %xmm0
movq %xmm0, %rax
movabsq $-0x8000000000000000, %rcx # imm = 0x8000000000000000
xorq %rcx, %rax
movq %rax, %xmm0
movsd %xmm0, 0x98(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x98(%rsp), %xmm0
subsd 0x8(%rax), %xmm0
movsd %xmm0, 0xa0(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0xa0(%rsp), %xmm0
movq %rax, %rcx
movq 0xa8(%rsp), %rax
addsd 0x10(%rcx), %xmm0
movsd 0xe2df0(%rip), %xmm1    # 0x133008
addsd %xmm1, %xmm0
movsd 0xe2fcc(%rip), %xmm1    # 0x1331f0
divsd %xmm1, %xmm0
movsd %xmm0, 0x18(%rax)
xorps %xmm0, %xmm0
ucomisd (%rax), %xmm0
jbe 0x50245
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, (%rax)
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
ucomisd 0x8(%rax), %xmm0
jbe 0x50267
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x8(%rax)
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
ucomisd 0x10(%rax), %xmm0
jbe 0x50289
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x10(%rax)
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
ucomisd 0x18(%rax), %xmm0
jbe 0x502ab
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rax)
movq 0xa8(%rsp), %rax
movsd (%rax), %xmm0
callq 0xf390
movq 0xa8(%rsp), %rax
movsd %xmm0, (%rax)
movsd 0x8(%rax), %xmm0
callq 0xf390
movq 0xa8(%rsp), %rax
movsd %xmm0, 0x8(%rax)
movsd 0x10(%rax), %xmm0
callq 0xf390
movq 0xa8(%rsp), %rax
movsd %xmm0, 0x10(%rax)
movsd 0x18(%rax), %xmm0
callq 0xf390
movq 0xa8(%rsp), %rax
movsd %xmm0, 0x18(%rax)
movsd (%rax), %xmm0
ucomisd 0x8(%rax), %xmm0
jb 0x5043a
movq 0xa8(%rsp), %rax
movsd (%rax), %xmm0
ucomisd 0x10(%rax), %xmm0
jb 0x5043a
movq 0xa8(%rsp), %rax
movsd (%rax), %xmm0
ucomisd 0x18(%rax), %xmm0
jb 0x5043a
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x50(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x50(%rsp), %xmm0
subsd 0x10(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x8(%rax), %xmm0
movsd %xmm0, 0x8(%rax)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x10(%rax), %xmm0
movsd %xmm0, 0x58(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x58(%rsp), %xmm0
subsd (%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x10(%rax), %xmm0
movsd %xmm0, 0x10(%rax)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x60(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x60(%rsp), %xmm0
subsd 0x8(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x18(%rax), %xmm0
movsd %xmm0, 0x18(%rax)
jmp 0x50803
movq 0xa8(%rsp), %rax
movsd 0x8(%rax), %xmm0
ucomisd (%rax), %xmm0
jb 0x5056f
movq 0xa8(%rsp), %rax
movsd 0x8(%rax), %xmm0
ucomisd 0x10(%rax), %xmm0
jb 0x5056f
movq 0xa8(%rsp), %rax
movsd 0x8(%rax), %xmm0
ucomisd 0x18(%rax), %xmm0
jb 0x5056f
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x38(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x38(%rsp), %xmm0
subsd 0x10(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd (%rax), %xmm0
movsd %xmm0, (%rax)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x40(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x40(%rsp), %xmm0
addsd 0x8(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x10(%rax), %xmm0
movsd %xmm0, 0x10(%rax)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x10(%rax), %xmm0
movsd %xmm0, 0x48(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x48(%rsp), %xmm0
addsd (%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x18(%rax), %xmm0
movsd %xmm0, 0x18(%rax)
jmp 0x50801
movq 0xa8(%rsp), %rax
movsd 0x10(%rax), %xmm0
ucomisd (%rax), %xmm0
jb 0x506a4
movq 0xa8(%rsp), %rax
movsd 0x10(%rax), %xmm0
ucomisd 0x8(%rax), %xmm0
jb 0x506a4
movq 0xa8(%rsp), %rax
movsd 0x10(%rax), %xmm0
ucomisd 0x18(%rax), %xmm0
jb 0x506a4
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x10(%rax), %xmm0
movsd %xmm0, 0x20(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x20(%rsp), %xmm0
subsd (%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd (%rax), %xmm0
movsd %xmm0, (%rax)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x28(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x28(%rsp), %xmm0
addsd 0x8(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x8(%rax), %xmm0
movsd %xmm0, 0x8(%rax)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x30(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x30(%rsp), %xmm0
addsd 0x10(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x18(%rax), %xmm0
movsd %xmm0, 0x18(%rax)
jmp 0x507ff
movq 0xa8(%rsp), %rax
movsd 0x18(%rax), %xmm0
ucomisd (%rax), %xmm0
jb 0x507d6
movq 0xa8(%rsp), %rax
movsd 0x18(%rax), %xmm0
ucomisd 0x8(%rax), %xmm0
jb 0x507d6
movq 0xa8(%rsp), %rax
movsd 0x18(%rax), %xmm0
ucomisd 0x10(%rax), %xmm0
jb 0x507d6
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x8(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x8(%rsp), %xmm0
subsd 0x8(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd (%rax), %xmm0
movsd %xmm0, (%rax)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd (%rax), %xmm0
movsd %xmm0, 0x10(%rsp)
movq 0xb8(%rsp), %rdi
xorl %esi, %esi
callq 0x4e280
movsd 0x10(%rsp), %xmm0
addsd 0x10(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x8(%rax), %xmm0
movsd %xmm0, 0x8(%rax)
movq 0xb8(%rsp), %rdi
movl $0x2, %esi
callq 0x4e280
movsd 0x8(%rax), %xmm0
movsd %xmm0, 0x18(%rsp)
movq 0xb8(%rsp), %rdi
movl $0x1, %esi
callq 0x4e280
movsd 0x18(%rsp), %xmm0
addsd 0x10(%rax), %xmm0
callq 0x51a80
movq 0xa8(%rsp), %rax
mulsd 0x10(%rax), %xmm0
movsd %xmm0, 0x10(%rax)
jmp 0x507fd
movq 0xa8(%rsp), %rax
xorps %xmm0, %xmm0
movsd %xmm0, (%rax)
xorps %xmm0, %xmm0
movsd %xmm0, 0x8(%rax)
xorps %xmm0, %xmm0
movsd %xmm0, 0x10(%rax)
xorps %xmm0, %xmm0
movsd %xmm0, 0x18(%rax)
jmp 0x507ff
jmp 0x50801
jmp 0x50803
movq 0xa8(%rsp), %rdi
callq 0x4f6e0
addq $0xc8, %rsp
retq
nopl (%rax,%rax)