// File: 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
subq $0x1580, %rsp           # imm = 0x1580
movl %edi, -0x4(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
leaq 0x2094b23(%rip), %rax   # 0x20a5780
movq (%rax), %rax
movslq -0x4(%rbp), %rcx
imulq $0x810, %rcx, %rcx      # imm = 0x810
addq %rcx, %rax
movq %rax, -0x1500(%rbp)
movl -0x4(%rbp), %eax
sarl $0x3, %eax
movl %eax, -0x1504(%rbp)
movl -0x4(%rbp), %ecx
andl $0x7, %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, -0x1508(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movl -0x1504(%rbp), %ecx
movzbl (%rax,%rcx), %eax
andl -0x1508(%rbp), %eax
cmpl $0x0, %eax
jne 0x10cdd
movl -0x1508(%rbp), %esi
movq -0x10(%rbp), %rax
movq (%rax), %rax
movl -0x1504(%rbp), %ecx
movzbl (%rax,%rcx), %edx
orl %esi, %edx
movb %dl, (%rax,%rcx)
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movl 0x3c(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x3c(%rax)
movq -0x18(%rbp), %rax
movq 0x1000(%rax), %rax
movq %rax, -0x4f8(%rbp)
movq -0x1500(%rbp), %rax
movq %rax, -0x4f0(%rbp)
movq $0x0, -0x4e8(%rbp)
movl $0xffffffff, -0x28(%rbp) # imm = 0xFFFFFFFF
movq $0x0, -0x20(%rbp)
movq -0x1500(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x1518(%rbp)
movl $0x0, -0x150c(%rbp)
movl -0x150c(%rbp), %eax
movq -0x1500(%rbp), %rcx
cmpl (%rcx), %eax
jae 0x112bd
movq -0x1518(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x1520(%rbp)
movq -0x1520(%rbp), %rax
movl 0x10(%rax), %eax
sarl $0x3, %eax
movl %eax, -0x1524(%rbp)
movq -0x1520(%rbp), %rax
movl 0x10(%rax), %ecx
andl $0x7, %ecx
movl $0x1, %eax
shll %cl, %eax
movl %eax, -0x1528(%rbp)
movq -0x4f8(%rbp), %rax
movl -0x1524(%rbp), %ecx
movzbl (%rax,%rcx), %eax
andl -0x1528(%rbp), %eax
cmpl $0x0, %eax
jne 0x10da7
jmp 0x11297
movq -0x18(%rbp), %rax
movl -0x1524(%rbp), %ecx
movzbl (%rax,%rcx), %eax
andl -0x1528(%rbp), %eax
cmpl $0x0, %eax
jne 0x10dc5
jmp 0x11297
movq -0x1520(%rbp), %rax
cmpl $0x2, 0x20(%rax)
jne 0x10de6
movq -0x1520(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x1530(%rbp)
jmp 0x10df8
movq -0x1520(%rbp), %rax
movq 0x30(%rax), %rax
movq %rax, -0x1530(%rbp)
leaq 0x20949ad(%rip), %rax   # 0x20a57ac
movl (%rax), %eax
movl %eax, -0x1534(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x1540(%rbp)
leaq -0x14f8(%rbp), %rax
movq %rax, -0x1548(%rbp)
movl $0x0, -0x154c(%rbp)
movl -0x154c(%rbp), %eax
cmpl -0x1534(%rbp), %eax
jae 0x10e9d
movq -0x1540(%rbp), %rax
movq (%rax), %rcx
movq -0x1530(%rbp), %rax
andq (%rax), %rcx
movq -0x1548(%rbp), %rax
movq %rcx, (%rax)
movl -0x154c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x154c(%rbp)
movq -0x1530(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1530(%rbp)
movq -0x1548(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1548(%rbp)
movq -0x1540(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1540(%rbp)
jmp 0x10e2a
leaq -0x14f8(%rbp), %rax
movq %rax, -0x1558(%rbp)
movq -0x10(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x1560(%rbp)
movl $0x0, -0x1564(%rbp)
movl -0x1564(%rbp), %eax
cmpl -0x1534(%rbp), %eax
jae 0x10f2b
movq -0x1558(%rbp), %rax
movq (%rax), %rax
movq -0x1560(%rbp), %rcx
movq (%rcx), %rcx
xorq $-0x1, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
je 0x10ef4
jmp 0x10f2b
jmp 0x10ef6
movl -0x1564(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1564(%rbp)
movq -0x1558(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1558(%rbp)
movq -0x1560(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1560(%rbp)
jmp 0x10ec3
movl -0x1564(%rbp), %eax
leaq 0x2094874(%rip), %rcx   # 0x20a57ac
cmpl (%rcx), %eax
jne 0x10f41
jmp 0x11297
movq -0x1520(%rbp), %rax
movq %rax, -0x30(%rbp)
leaq 0x9f2d(%rip), %rax      # 0x1ae80
movss (%rax), %xmm0
movq -0x1520(%rbp), %rax
subss (%rax), %xmm0
movss %xmm0, -0x1574(%rbp)
leaq 0x9f0f(%rip), %rax      # 0x1ae80
movss 0x4(%rax), %xmm0
movq -0x1520(%rbp), %rax
subss 0x4(%rax), %xmm0
movss %xmm0, -0x1570(%rbp)
leaq 0x9eef(%rip), %rax      # 0x1ae80
movss 0x8(%rax), %xmm0
movq -0x1520(%rbp), %rax
subss 0x8(%rax), %xmm0
movss %xmm0, -0x156c(%rbp)
movq -0x1520(%rbp), %rax
movss 0xc(%rax), %xmm0
movd %xmm0, %eax
xorl $0x80000000, %eax       # imm = 0x80000000
movd %eax, %xmm0
movss %xmm0, -0x1568(%rbp)
movq -0x18(%rbp), %rax
movq 0x14c8(%rax), %rdi
leaq -0x1574(%rbp), %rsi
callq 0x14c60
testb $0x1, %al
jne 0x10fe8
jmp 0x10fed
jmp 0x11297
movq -0x1520(%rbp), %rax
movq %rax, -0x4e8(%rbp)
movb $0x1, -0x38(%rbp)
movb $0x1, -0x37(%rbp)
movb $0x1, -0x36(%rbp)
movq -0x1520(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x10(%rbp), %rax
movq 0x14d8(%rax), %rdx
leaq -0x14f8(%rbp), %rsi
callq 0x14ce0
movq %rax, -0x4d8(%rbp)
cmpq $0x0, -0x4d8(%rbp)
jne 0x1103f
jmp 0x11297
movq -0x18(%rbp), %rax
movq 0x1018(%rax), %rdi
leaq -0x14f8(%rbp), %rsi
leaq -0x1574(%rbp), %rdx
callq 0x14ce0
movq %rax, -0x4e0(%rbp)
cmpq $0x0, -0x4e0(%rbp)
jne 0x11073
jmp 0x11297
movq -0x18(%rbp), %rax
cmpq $0x0, 0x1020(%rax)
jne 0x110a0
movq -0x1520(%rbp), %rax
movl 0x10(%rax), %edi
movq -0x10(%rbp), %rsi
leaq -0x14f8(%rbp), %rdx
callq 0x10c40
jmp 0x11297
movq -0x4d8(%rbp), %rdi
movq -0x18(%rbp), %rax
movq 0x14c8(%rax), %rdx
leaq -0x14f8(%rbp), %rsi
callq 0x14ce0
movq %rax, -0x4d8(%rbp)
cmpq $0x0, -0x4d8(%rbp)
jne 0x110d4
jmp 0x11297
cmpl $-0x1, -0x28(%rbp)
jne 0x11167
movl $0x0, -0x28(%rbp)
movq -0x18(%rbp), %rax
movq 0x1018(%rax), %rcx
movq 0x1020(%rax), %rax
movslq 0x4(%rcx), %rcx
movslq 0x4(%rax), %rax
imulq %rax, %rcx
shlq $0x4, %rcx
movq %rsp, %rax
subq %rcx, %rax
movq %rax, %rsp
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
movq 0x1018(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x1020(%rax), %rsi
xorl %eax, %eax
movl %eax, %edx
xorl %ecx, %ecx
leaq -0x14f8(%rbp), %r8
callq 0x14330
movq -0x18(%rbp), %rax
movq 0x1020(%rax), %rdi
movq -0x18(%rbp), %rax
movq 0x1018(%rax), %rsi
xorl %eax, %eax
movl %eax, %edx
movl $0x1, %ecx
leaq -0x14f8(%rbp), %r8
callq 0x14330
cmpl $0x0, -0x28(%rbp)
jle 0x111f8
movl $0x0, -0x1578(%rbp)
movl -0x1578(%rbp), %ecx
xorl %eax, %eax
cmpl -0x28(%rbp), %ecx
movb %al, -0x1579(%rbp)
jae 0x1119f
cmpq $0x0, -0x4d8(%rbp)
setne %al
movb %al, -0x1579(%rbp)
movb -0x1579(%rbp), %al
testb $0x1, %al
jne 0x111ab
jmp 0x111e7
movq -0x4d8(%rbp), %rdi
movq -0x20(%rbp), %rdx
movl -0x1578(%rbp), %eax
shlq $0x4, %rax
addq %rax, %rdx
leaq -0x14f8(%rbp), %rsi
callq 0x14ce0
movq %rax, -0x4d8(%rbp)
movl -0x1578(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1578(%rbp)
jmp 0x1117b
cmpq $0x0, -0x4d8(%rbp)
jne 0x111f6
jmp 0x11297
jmp 0x111f8
leaq 0x20945b2(%rip), %rax   # 0x20a57b1
testb $0x1, (%rax)
je 0x1127d
movq -0x4d8(%rbp), %rdi
movq -0x18(%rbp), %rax
movq 0x1020(%rax), %rsi
movq -0x4e0(%rbp), %rdx
xorl %ecx, %ecx
leaq -0x14f8(%rbp), %r8
callq 0x14330
movq %rax, -0x4e0(%rbp)
cmpq $0x0, -0x4e0(%rbp)
jne 0x1123e
jmp 0x11297
movq -0x18(%rbp), %rax
movq 0x1020(%rax), %rdi
movq -0x4d8(%rbp), %rsi
movq -0x4e0(%rbp), %rdx
movl $0x1, %ecx
leaq -0x14f8(%rbp), %r8
callq 0x14330
movq %rax, -0x4e0(%rbp)
cmpq $0x0, -0x4e0(%rbp)
jne 0x1127b
jmp 0x11297
jmp 0x1127d
movq -0x1520(%rbp), %rax
movl 0x10(%rax), %edi
movq -0x10(%rbp), %rsi
leaq -0x14f8(%rbp), %rdx
callq 0x10c40
movl -0x150c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x150c(%rbp)
movq -0x1518(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1518(%rbp)
jmp 0x10d33
movq %rbp, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)