// File: /workspace/github_cpp_makefile_star2_O2/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, %r13
leaq 0x2092779(%rip), %r8    # 0x209d780
movslq %edi, %rdi
imulq $0x810, %rdi, %r9       # imm = 0x810
movl %edi, %ecx
andb $0x7, %cl
pushq $0x1
popq %r10
movl %r10d, %eax
shll %cl, %eax
movl %edi, %ecx
sarl $0x3, %ecx
movq (%rsi), %rdx
movzbl (%rdx,%rcx), %esi
andl $0x7, %edi
addq (%r8), %r9
btl %edi, %esi
jb 0xb043
orb %sil, %al
movb %al, (%rdx,%rcx)
movq 0x8(%r13), %rax
incl 0x3c(%rax)
movq 0x1000(%rbx), %rax
leaq -0x1550(%rbp), %rcx
movq %rax, 0x1000(%rcx)
movq %r9, 0x1008(%rcx)
andq $0x0, 0x1010(%rcx)
orl $-0x1, 0x14d0(%rcx)
andq $0x0, 0x14d8(%rcx)
leaq 0x10(%r9), %r8
leaq 0x6cdf(%rip), %rax      # 0x11d60
movsd (%rax), %xmm0
movaps %xmm0, -0x70(%rbp)
movss 0x8(%rax), %xmm0
movss %xmm0, -0x2c(%rbp)
xorl %r14d, %r14d
leaq 0x209270f(%rip), %rdi   # 0x209d7ac
movq %r9, -0x50(%rbp)
cmpl (%r9), %r14d
jae 0xb381
movq (%r8), %r15
movl 0x10(%r15), %esi
movl %esi, %eax
sarl $0x3, %eax
movl %esi, %ecx
andb $0x7, %cl
movl %r10d, %edx
shll %cl, %edx
movq -0x550(%rbp), %rcx
movzbl (%rcx,%rax), %ecx
andl $0x7, %esi
btl %esi, %ecx
jae 0xb375
movzbl (%rbx,%rax), %eax
testl %eax, %edx
je 0xb375
xorl %eax, %eax
cmpl $0x2, 0x20(%r15)
setne %al
movq 0x28(%r15,%rax,8), %rcx
movl (%rdi), %eax
xorl %edx, %edx
cmpl %edx, %eax
je 0xb10f
movq (%rcx,%rdx,8), %rsi
andq (%rbx,%rdx,8), %rsi
movq %rsi, -0x1550(%rbp,%rdx,8)
incq %rdx
jmp 0xb0f6
movq (%r13), %rdx
xorl %ecx, %ecx
cmpl %ecx, %eax
je 0xb375
movq (%rdx,%rcx,8), %rsi
notq %rsi
testq %rsi, -0x1550(%rbp,%rcx,8)
jne 0xb133
incq %rcx
jmp 0xb115
cmpl %ecx, %eax
je 0xb375
movq %r8, -0x58(%rbp)
movq %r15, -0x88(%rbp)
movsd (%r15), %xmm0
movaps -0x70(%rbp), %xmm1
subps %xmm0, %xmm1
movlps %xmm1, -0x40(%rbp)
movss -0x2c(%rbp), %xmm0
subss 0x8(%r15), %xmm0
movss %xmm0, -0x38(%rbp)
movss 0xc(%r15), %xmm0
xorps 0x809d(%rip), %xmm0     # 0x13210
movss %xmm0, -0x34(%rbp)
movq 0x14c8(%rbx), %rdi
leaq -0x40(%rbp), %rsi
callq 0xcca4
testb %al, %al
jne 0xb362
movq %r15, -0x540(%rbp)
movw $0x101, -0x90(%rbp)     # imm = 0x101
movb $0x1, -0x8e(%rbp)
movq 0x18(%r15), %rdi
movq 0x14d8(%r13), %rdx
leaq -0x1550(%rbp), %rsi
callq 0xcce1
movq %rax, -0x530(%rbp)
testq %rax, %rax
je 0xb362
movq 0x1018(%rbx), %rdi
leaq -0x1550(%rbp), %rsi
leaq -0x40(%rbp), %rdx
callq 0xcce1
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xb362
cmpq $0x0, 0x1020(%rbx)
je 0xb34f
movq -0x530(%rbp), %rdi
movq 0x14c8(%rbx), %rdx
leaq -0x1550(%rbp), %rsi
callq 0xcce1
movq %rax, -0x530(%rbp)
testq %rax, %rax
je 0xb362
movl -0x80(%rbp), %ecx
cmpl $-0x1, %ecx
jne 0xb295
andl $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), %r12
movq %r12, %r8
callq 0xc858
movq 0x1018(%rbx), %rsi
movq 0x1020(%rbx), %rdi
xorl %edx, %edx
pushq $0x1
popq %rcx
movq %r12, %r8
callq 0xc858
movl -0x80(%rbp), %ecx
testl %ecx, %ecx
jle 0xb2e8
movq %r13, -0x48(%rbp)
movq -0x530(%rbp), %rax
xorl %r13d, %r13d
xorl %r12d, %r12d
movl %ecx, %ecx
cmpq %rcx, %r12
jae 0xb2df
testq %rax, %rax
je 0xb2df
movq -0x78(%rbp), %rdx
addq %r13, %rdx
movq %rax, %rdi
leaq -0x1550(%rbp), %rsi
callq 0xcce1
movq %rax, -0x530(%rbp)
incq %r12
movl -0x80(%rbp), %ecx
addq $0x10, %r13
jmp 0xb2aa
testq %rax, %rax
movq -0x48(%rbp), %r13
je 0xb362
leaq 0x20924c2(%rip), %rax   # 0x209d7b1
cmpb $0x1, (%rax)
jne 0xb34f
movq -0x538(%rbp), %rdx
movq -0x530(%rbp), %rdi
movq 0x1020(%rbx), %rsi
xorl %ecx, %ecx
leaq -0x1550(%rbp), %r8
callq 0xc858
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xb362
movq 0x1020(%rbx), %rdi
movq -0x530(%rbp), %rsi
movq %rax, %rdx
pushq $0x1
popq %rcx
leaq -0x1550(%rbp), %r8
callq 0xc858
movq %rax, -0x538(%rbp)
testq %rax, %rax
je 0xb362
movl 0x10(%r15), %edi
movq %r13, %rsi
leaq -0x1550(%rbp), %rdx
callq 0xafe6
movq -0x50(%rbp), %r9
pushq $0x1
popq %r10
leaq 0x209243b(%rip), %rdi   # 0x209d7ac
movq -0x58(%rbp), %r8
incl %r14d
addq $0x8, %r8
jmp 0xb0a1
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq