// File: /workspace/github_cpp_makefile_star2_O1/FreeSlave[P]vhlt/hlvis/flow.cpp
// Function: RecursiveLeafFlow(int, threaddata_t const*, pstack_s const*)
inline static void     RecursiveLeafFlow(const int leafnum, const threaddata_t* const thread, const pstack_t* const prevstack)
{
    pstack_t        stack;
    leaf_t*         leaf;

    leaf = &g_leafs[leafnum];
#ifdef USE_CHECK_STACK
    CheckStack(leaf, thread);
#endif

    {
        const unsigned offset = leafnum >> 3;
        const unsigned bit = (1 << (leafnum & 7));
    
        // mark the leaf as visible
        if (!(thread->leafvis[offset] & bit))
        {
            thread->leafvis[offset] |= bit;
            thread->base->numcansee++;
        }
    }

#ifdef USE_CHECK_STACK
    prevstack->next = &stack;
    stack.next = NULL;
#endif
    stack.head = prevstack->head;
    stack.leaf = leaf;
    stack.portal = NULL;
#ifdef RVIS_LEVEL_2
    stack.clipPlaneCount = -1;
    stack.clipPlane = NULL;
#endif

    // check all portals for flowing into other leafs       
    unsigned i;
    portal_t** plist = leaf->portals;

    for (i = 0; i < leaf->numportals; i++, plist++)
    {
        portal_t* p = *plist;

#if ZHLT_ZONES
        portal_t * head_p = stack.head->portal;
        if (g_Zones->check(head_p->zone, p->zone))
        {
            continue;
        }
#endif

        {
            const unsigned offset = p->leaf >> 3;
            const unsigned bit = 1 << (p->leaf & 7);

            if (!(stack.head->mightsee[offset] & bit))
            {
                continue;                                      // can't possibly see it
            }
            if (!(prevstack->mightsee[offset] & bit))
            {
                continue;                                      // can't possibly see it
            }
        }

        // if the portal can't see anything we haven't allready seen, skip it
        {
            long* test;

            if (p->status == stat_done)
            {
                test = (long*)p->visbits;
            }
            else
            {
                test = (long*)p->mightsee;
            }
    
            {
                const int bitlongs = g_bitlongs;

                {
                    long* prevmight = (long*)prevstack->mightsee;
                    long* might = (long*)stack.mightsee;
                
                    unsigned j;
                    for (j = 0; j < bitlongs; j++, test++, might++, prevmight++)
                    {
                        (*might) = (*prevmight) & (*test);
                    }
                }
        
                {
                    long* might = (long*)stack.mightsee;
                    long* vis = (long*)thread->leafvis;
                    unsigned j;
                    for (j = 0; j < bitlongs; j++, might++, vis++)
                    {
                        if ((*might) & ~(*vis))
                        {
                            break;
                        }
                    }
            
                    if (j == g_bitlongs)
                    {                                                  // can't see anything new
                        continue;
                    }
                }
            }
        }

        // get plane of portal, point normal into the neighbor leaf
        stack.portalplane = &p->plane;
        plane_t             backplane;
        VectorSubtract(vec3_origin, p->plane.normal, backplane.normal);
        backplane.dist = -p->plane.dist;

        if (VectorCompare(prevstack->portalplane->normal, backplane.normal))
        {
            continue;                                      // can't go out a coplanar face
        }

        stack.portal = p;
#ifdef USE_CHECK_STACK
        stack.next = NULL;
#endif
        stack.freewindings[0] = 1;
        stack.freewindings[1] = 1;
        stack.freewindings[2] = 1;

        stack.pass = ChopWinding(p->winding, &stack, thread->pstack_head.portalplane);
        if (!stack.pass)
        {
            continue;
        }

        stack.source = ChopWinding(prevstack->source, &stack, &backplane);
        if (!stack.source)
        {
            continue;
        }

        if (!prevstack->pass)
        {                                                  // the second leaf can only be blocked if coplanar
            RecursiveLeafFlow(p->leaf, thread, &stack);
            continue;
        }

        stack.pass = ChopWinding(stack.pass, &stack, prevstack->portalplane);
        if (!stack.pass)
        {
            continue;
        }

#ifdef RVIS_LEVEL_2
        if (stack.clipPlaneCount == -1)
        {
            stack.clipPlaneCount = 0;
            stack.clipPlane = (plane_t*)alloca(sizeof(plane_t) * prevstack->source->numpoints * prevstack->pass->numpoints);

            ClipToSeperators(prevstack->source, prevstack->pass, NULL, false, &stack);
            ClipToSeperators(prevstack->pass, prevstack->source, NULL, true, &stack);
        }

        if (stack.clipPlaneCount > 0)
        {
            unsigned j;
            for (j = 0; j < stack.clipPlaneCount && stack.pass != NULL; j++)
            {
                stack.pass = ChopWinding(stack.pass, &stack, &(stack.clipPlane[j]));
            }

            if (stack.pass == NULL)
            continue;
        }
#else

        stack.pass = ClipToSeperators(stack.source, prevstack->pass, stack.pass, false, &stack);
        if (!stack.pass)
        {
            continue;
        }

        stack.pass = ClipToSeperators(prevstack->pass, stack.source, stack.pass, true, &stack);
        if (!stack.pass)
        {
            continue;
        }
#endif

        if (g_fullvis)
        {
            stack.source = ClipToSeperators(stack.pass, prevstack->pass, stack.source, false, &stack);
            if (!stack.source)
            {
                continue;
            }

            stack.source = ClipToSeperators(prevstack->pass, stack.pass, stack.source, true, &stack);
            if (!stack.source)
            {
                continue;
            }
        }

        // flow through it for real
        RecursiveLeafFlow(p->leaf, thread, &stack);
    }

#ifdef RVIS_LEVEL_2
#if 0
    if (stack.clipPlane != NULL)
    {
        free(stack.clipPlane);
    }
#endif
#endif
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1528, %rsp           # imm = 0x1528
movq %rdx, %rbx
movq %rsi, %r14
leaq 0x2092d0c(%rip), %r8    # 0x209f780
movslq %edi, %rdi
imulq $0x810, %rdi, %r13      # imm = 0x810
movl %edi, %ecx
andb $0x7, %cl
movl $0x1, %eax
shll %cl, %eax
movl %edi, %ecx
sarl $0x3, %ecx
movq (%rsi), %rdx
movzbl (%rdx,%rcx), %esi
andl $0x7, %edi
addq (%r8), %r13
btl %edi, %esi
jb 0xcaae
orb %sil, %al
movb %al, (%rdx,%rcx)
movq 0x8(%r14), %rax
incl 0x3c(%rax)
movq 0x1000(%rbx), %rax
movq %rax, -0x550(%rbp)
movq %r13, -0x548(%rbp)
xorl %r12d, %r12d
movq %r12, -0x540(%rbp)
movl $0xffffffff, -0x80(%rbp) # imm = 0xFFFFFFFF
movq %r12, -0x78(%rbp)
cmpl $0x0, (%r13)
je 0xce6e
leaq 0x10(%r13), %r15
leaq 0x7312(%rip), %rax      # 0x13e00
movsd (%rax), %xmm0
movaps %xmm0, -0x70(%rbp)
movss 0x8(%rax), %xmm0
movss %xmm0, -0x34(%rbp)
leaq 0x2092ca5(%rip), %rdi   # 0x209f7ac
movaps 0x87c2(%rip), %xmm2     # 0x152d0
movsd 0x896a(%rip), %xmm3     # 0x15480
movq (%r15), %r8
movl 0x10(%r8), %esi
movl %esi, %eax
sarl $0x3, %eax
movl %esi, %ecx
andb $0x7, %cl
movl $0x1, %edx
shll %cl, %edx
movq -0x550(%rbp), %rcx
movzbl (%rcx,%rax), %ecx
andl $0x7, %esi
btl %esi, %ecx
jae 0xce5d
movzbl (%rbx,%rax), %eax
testl %eax, %edx
je 0xce5d
movl (%rdi), %eax
xorl %ecx, %ecx
testq %rax, %rax
je 0xcb9f
cmpl $0x2, 0x20(%r8)
setne %cl
movq 0x28(%r8,%rcx,8), %rcx
xorl %edx, %edx
movq (%rcx,%rdx,8), %rsi
andq (%rbx,%rdx,8), %rsi
movq %rsi, -0x1550(%rbp,%rdx,8)
incq %rdx
cmpl %edx, %eax
jne 0xcb69
movq (%r14), %rdx
xorl %ecx, %ecx
movq (%rdx,%rcx,8), %rsi
notq %rsi
testq %rsi, -0x1550(%rbp,%rcx,8)
jne 0xcb9f
incq %rcx
cmpl %ecx, %eax
jne 0xcb85
movl %eax, %ecx
cmpl %eax, %ecx
je 0xce5d
movq %r8, -0x88(%rbp)
movsd (%r8), %xmm0
movaps -0x70(%rbp), %xmm1
subps %xmm0, %xmm1
movlps %xmm1, -0x48(%rbp)
movss -0x34(%rbp), %xmm0
subss 0x8(%r8), %xmm0
movss %xmm0, -0x40(%rbp)
movss 0xc(%r8), %xmm0
xorps 0x54b5(%rip), %xmm0     # 0x12090
movss %xmm0, -0x3c(%rbp)
movq 0x14c8(%rbx), %rax
movss (%rax), %xmm0
subss -0x48(%rbp), %xmm0
andps %xmm2, %xmm0
cvtss2sd %xmm0, %xmm0
ucomisd %xmm3, %xmm0
ja 0xcc3e
xorl %edx, %edx
movaps 0x86ca(%rip), %xmm1     # 0x152d0
movsd 0x8872(%rip), %xmm2     # 0x15480
movq %rdx, %rcx
cmpq $0x2, %rdx
je 0xcc34
movss 0x4(%rax,%rcx,4), %xmm0
subss -0x44(%rbp,%rcx,4), %xmm0
andps %xmm1, %xmm0
cvtss2sd %xmm0, %xmm0
leaq 0x1(%rcx), %rdx
ucomisd %xmm2, %xmm0
jbe 0xcc0e
cmpq $0x1, %rcx
ja 0xce47
movq %r8, -0x540(%rbp)
movw $0x101, -0x90(%rbp)     # imm = 0x101
movb $0x1, -0x8e(%rbp)
movq 0x18(%r8), %rdi
movq 0x14d8(%r14), %rdx
leaq -0x1550(%rbp), %rsi
movq %r8, -0x30(%rbp)
callq 0xefdc
movq %rax, -0x530(%rbp)
testq %rax, %rax
je 0xce47
movq 0x1018(%rbx), %rdi
leaq -0x1550(%rbp), %rsi
leaq -0x48(%rbp), %rdx
callq 0xefdc
movq -0x30(%rbp), %rcx
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xce47
cmpq $0x0, 0x1020(%rbx)
je 0xce35
movq -0x530(%rbp), %rdi
movq 0x14c8(%rbx), %rdx
leaq -0x1550(%rbp), %rsi
callq 0xefdc
movq -0x30(%rbp), %rcx
movq %rax, -0x530(%rbp)
testq %rax, %rax
je 0xce47
cmpl $-0x1, -0x80(%rbp)
jne 0xcd54
movl $0x0, -0x80(%rbp)
movq 0x1018(%rbx), %rdi
movq 0x1020(%rbx), %rsi
movslq 0x4(%rdi), %rax
movslq 0x4(%rsi), %rcx
imulq %rax, %rcx
shlq $0x4, %rcx
movq %rsp, %rax
subq %rcx, %rax
movq %rax, %rsp
movq %rax, -0x78(%rbp)
xorl %edx, %edx
xorl %ecx, %ecx
leaq -0x1550(%rbp), %r8
callq 0xea74
movq 0x1018(%rbx), %rsi
movq 0x1020(%rbx), %rdi
xorl %edx, %edx
movl $0x1, %ecx
leaq -0x1550(%rbp), %r8
callq 0xea74
movq -0x30(%rbp), %rcx
cmpl $0x0, -0x80(%rbp)
jle 0xcdc8
movq %r13, -0x50(%rbp)
movq %r14, -0x58(%rbp)
cmpl $0x0, -0x80(%rbp)
setne %cl
movq -0x530(%rbp), %rax
testq %rax, %rax
setne %dl
andb %cl, %dl
cmpb $0x1, %dl
jne 0xcdb7
movl $0x1, %r13d
xorl %r14d, %r14d
movq -0x78(%rbp), %rdx
addq %r14, %rdx
movq %rax, %rdi
leaq -0x1550(%rbp), %rsi
callq 0xefdc
movq %rax, -0x530(%rbp)
movl -0x80(%rbp), %ecx
cmpq %rcx, %r13
jae 0xcdb7
addq $0x10, %r14
incq %r13
testq %rax, %rax
jne 0xcd86
testq %rax, %rax
movq -0x58(%rbp), %r14
movq -0x50(%rbp), %r13
movq -0x30(%rbp), %rcx
je 0xce47
leaq 0x20929e2(%rip), %rax   # 0x209f7b1
cmpb $0x1, (%rax)
jne 0xce35
movq -0x538(%rbp), %rdx
movq -0x530(%rbp), %rdi
movq 0x1020(%rbx), %rsi
xorl %ecx, %ecx
leaq -0x1550(%rbp), %r8
callq 0xea74
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xce47
movq 0x1020(%rbx), %rdi
movq -0x530(%rbp), %rsi
movq %rax, %rdx
movl $0x1, %ecx
leaq -0x1550(%rbp), %r8
callq 0xea74
movq -0x30(%rbp), %rcx
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xce47
movl 0x10(%rcx), %edi
movq %r14, %rsi
leaq -0x1550(%rbp), %rdx
callq 0xca53
leaq 0x209295e(%rip), %rdi   # 0x209f7ac
movaps 0x847b(%rip), %xmm2     # 0x152d0
movsd 0x8623(%rip), %xmm3     # 0x15480
incl %r12d
addq $0x8, %r15
cmpl (%r13), %r12d
jb 0xcb16
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq