// File: /workspace/github_cpp_makefile_star2_O1/YiweiMao[P]tessDX/src/tessellator.cpp
// Function: CHWTessellator::StitchTransition(int, int, int, CHWTessellator::TESSELLATOR_PARITY, int, int, CHWTessellator::TESSELLATOR_PARITY)
void CHWTessellator::StitchTransition(int baseIndexOffset,
                                    int insideEdgePointBaseOffset, int insideNumHalfTessFactorPoints, 
                                    TESSELLATOR_PARITY insideEdgeTessFactorParity,
                                    int outsideEdgePointBaseOffset, int outsideNumHalfTessFactorPoints,
                                    TESSELLATOR_PARITY outsideTessFactorParity
)
{

#ifdef ALLOW_XBOX_360_COMPARISON
    // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
    // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
    //
    // The contents of the finalPointPositionTable are where vertex i [0..32] ends up on the half-edge
    // at the max tessellation amount given ruler-function split order.  
    // Recall the other half of an edge is mirrored, so we only need to deal with one half.
    // This table is used to decide when to advance a point on the interior or exterior.
    // It supports odd TessFactor up to 65 and even TessFactor up to 64.
    static const int _finalPointPositionTable[33] = 
            { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
              1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };
    // The loopStart and loopEnd tables below just provide optimal loop bounds for the
    // stitching algorithm further below, for any given halfTssFactor.  
    // There is probably a better way to encode this...

    // loopStart[halfTessFactor] encodes the FIRST entry other that [0] in finalPointPositionTable[] above which is
    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
    static const int _loopStart[33] = 
            {1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
    // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
    static const int _loopEnd[33] = 
            {0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
    const int* finalPointPositionTable;
    const int* loopStart;
    const int* loopEnd;
    if( m_bXBox360Mode )
    {
        // The XBox360 vertex introduction order is always from the center of the edge.
        // So the final positions of points on the half-edge are this trivial table.
        static const int XBOXfinalPointPositionTable[33] = 
                { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
                  18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32 };
        // loopStart and loopEnd (meaning described above) also become trivial for XBox360 splitting.
        static const int XBOXloopStart[33] = 
                {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};
        static const int XBOXloopEnd[33] = 
                {0,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31};

        finalPointPositionTable = XBOXfinalPointPositionTable;
        loopStart = XBOXloopStart;
        loopEnd = XBOXloopEnd;
    }
    else
    {
        finalPointPositionTable = _finalPointPositionTable;
        loopStart = _loopStart;
        loopEnd =_loopEnd;
    }
#else
    // Tables to assist in the stitching of 2 rows of points having arbitrary TessFactors.
    // The stitching order is governed by Ruler Function vertex split ordering (see external documentation).
    //
    // The contents of the finalPointPositionTable are where vertex i [0..33] ends up on the half-edge
    // at the max tessellation amount given ruler-function split order.  
    // Recall the other half of an edge is mirrored, so we only need to deal with one half.
    // This table is used to decide when to advance a point on the interior or exterior.
    // It supports odd TessFactor up to 65 and even TessFactor up to 64.
    static const int finalPointPositionTable[33] = 
            { 0, 32, 16, 8, 17, 4, 18, 9, 19, 2, 20, 10, 21, 5, 22, 11, 23,
              1, 24, 12, 25, 6, 26, 13, 27, 3, 28, 14, 29, 7, 30, 15, 31 };

    // The loopStart and loopEnd tables below just provide optimal loop bounds for the
    // stitching algorithm further below, for any given halfTssFactor.  
    // There is probably a better way to encode this...

    // loopStart[halfTessFactor] encodes the FIRST entry in finalPointPositionTable[] above which is
    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
    static const int loopStart[33] = 
            {1,1,17,9,9,5,5,5,5,3,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
    // loopStart[halfTessFactor] encodes the LAST entry in finalPointPositionTable[] above which is
    // less than halfTessFactor.  Exceptions are entry 0 and 1, which are set up to skip the loop.
    static const int loopEnd[33] = 
            {0,0,17,17,25,25,25,25,29,29,29,29,29,29,29,29,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32};
#endif
    if( TESSELLATOR_PARITY_ODD == insideEdgeTessFactorParity )
    {
        insideNumHalfTessFactorPoints -= 1;
    }
    if( TESSELLATOR_PARITY_ODD == outsideTessFactorParity )
    {
        outsideNumHalfTessFactorPoints -= 1;
    }
    // Walk first half
    int outsidePoint = outsideEdgePointBaseOffset; 
    int insidePoint = insideEdgePointBaseOffset; 

    // iStart,iEnd are a small optimization so the loop below doesn't have to go from 0 up to 31
    int iStart = min(loopStart[insideNumHalfTessFactorPoints],loopStart[outsideNumHalfTessFactorPoints]);
    int iEnd = max(loopEnd[insideNumHalfTessFactorPoints],loopEnd[outsideNumHalfTessFactorPoints]);

    if( finalPointPositionTable[0] < outsideNumHalfTessFactorPoints ) // since we dont' start the loop at 0 below, we need a special case.
    {
        // Advance outside
        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
        baseIndexOffset += 3; outsidePoint++;
    }

    for(int i = iStart; i <= iEnd; i++)
    {
        if( /*(i>0) && <-- not needed since iStart is never 0*/(finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
        {
            // Advance inside
            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
            baseIndexOffset += 3; insidePoint++;
        }
        if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
        {
            // Advance outside
            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
            baseIndexOffset += 3; outsidePoint++;
        }
    }

    if( (insideEdgeTessFactorParity != outsideTessFactorParity) || (insideEdgeTessFactorParity == TESSELLATOR_PARITY_ODD))
    {
        if( insideEdgeTessFactorParity == outsideTessFactorParity )
        {
            // Quad in the middle
            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
            baseIndexOffset += 3;
            DefineClockwiseTriangle(insidePoint+1,outsidePoint,outsidePoint+1,baseIndexOffset);
            baseIndexOffset += 3;
            insidePoint++;
            outsidePoint++;
        }
        else if( TESSELLATOR_PARITY_EVEN == insideEdgeTessFactorParity )
        {
            // Triangle pointing inside
            DefineClockwiseTriangle(insidePoint,outsidePoint,outsidePoint+1,baseIndexOffset);
            baseIndexOffset += 3;
            outsidePoint++;
        }
        else
        {
            // Triangle pointing outside
            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
            baseIndexOffset += 3;
            insidePoint++;
        }
    }

    // Walk second half.  
    for(int i = iEnd; i >= iStart; i--)
    {
        if((finalPointPositionTable[i] < outsideNumHalfTessFactorPoints))
        {
            // Advance outside
            DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
            baseIndexOffset += 3; outsidePoint++;
        }
        if( /*(i>0) && <-- not needed since iStart is never 0*/ (finalPointPositionTable[i] < insideNumHalfTessFactorPoints))
        {
            // Advance inside
            DefineClockwiseTriangle(insidePoint,outsidePoint,insidePoint+1,baseIndexOffset);
            baseIndexOffset += 3; insidePoint++;
        }
    }
    // Below case is not needed if we didn't optimize loop above and made it run from 31 down to 0.
    if((finalPointPositionTable[0] < outsideNumHalfTessFactorPoints))
    {
        DefineClockwiseTriangle(outsidePoint,outsidePoint+1,insidePoint,baseIndexOffset);
        baseIndexOffset += 3; outsidePoint++;
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movl %r9d, %r14d
movl %edx, %r15d
movl %esi, %r12d
movl 0x98(%rsp), %r11d
movl 0x90(%rsp), %esi
leaq 0xc310b(%rip), %rax     # 0x4c6380
leaq 0xc2f54(%rip), %r9      # 0x4c61d0
cmpb $0x0, 0x30(%rdi)
cmovneq %rax, %r9
leaq 0xc3185(%rip), %rax     # 0x4c6410
leaq 0xc2fce(%rip), %r10     # 0x4c6260
cmovneq %rax, %r10
leaq 0xc3203(%rip), %rax     # 0x4c64a0
leaq 0xc304c(%rip), %rdx     # 0x4c62f0
cmovneq %rax, %rdx
xorl %eax, %eax
movl %r8d, 0x38(%rsp)
cmpl $0x1, %r8d
sete %al
subl %eax, %ecx
xorl %eax, %eax
movl %r11d, 0x34(%rsp)
cmpl $0x1, %r11d
sete %al
subl %eax, %esi
movl %ecx, 0x1c(%rsp)
movslq %ecx, %rax
movl (%r10,%rax,4), %ebx
movl %esi, 0x18(%rsp)
movslq %esi, %rsi
movl (%r10,%rsi,4), %ebp
cmpl %ebp, %ebx
movl %ebp, %ecx
cmovll %ebx, %ecx
movl %ecx, 0x14(%rsp)
movl (%rdx,%rax,4), %eax
movl (%rdx,%rsi,4), %ecx
cmpl %ecx, %eax
movl %ecx, 0x2c(%rsp)
movl %eax, 0x30(%rsp)
cmovgl %eax, %ecx
movq %rcx, 0x40(%rsp)
movq %r9, 0x48(%rsp)
movl (%r9), %eax
movl %eax, 0x3c(%rsp)
cmpl %esi, %eax
movq %rdi, 0x8(%rsp)
jge 0x403332
leal 0x1(%r14), %r13d
movl %r14d, %esi
movl %r13d, %edx
movl %r15d, %ecx
movl %r12d, %r8d
callq 0x40266a
addl $0x3, %r12d
movl %r13d, %r14d
movl 0x14(%rsp), %edx
movq 0x40(%rsp), %rax
cmpl %eax, %edx
jg 0x4033cb
cmpl %ebx, %ebp
cmovll %ebp, %ebx
movq %rax, %rsi
movslq %ebx, %rax
movq 0x48(%rsp), %rcx
leaq (%rcx,%rax,4), %rcx
movq %rcx, 0x20(%rsp)
leal (%rax,%rsi), %ecx
subl %edx, %ecx
subl %eax, %ecx
incl %ecx
movq %rcx, 0x50(%rsp)
xorl %ebp, %ebp
movq 0x20(%rsp), %rax
movl (%rax,%rbp,4), %ebx
cmpl 0x1c(%rsp), %ebx
jge 0x40339b
leal 0x1(%r15), %r13d
movq 0x8(%rsp), %rdi
movl %r15d, %esi
movl %r14d, %edx
movl %r13d, %ecx
movl %r12d, %r8d
callq 0x40266a
addl $0x3, %r12d
movl %r13d, %r15d
cmpl 0x18(%rsp), %ebx
jge 0x4033c2
leal 0x1(%r14), %r13d
movq 0x8(%rsp), %rdi
movl %r14d, %esi
movl %r13d, %edx
movl %r15d, %ecx
movl %r12d, %r8d
callq 0x40266a
addl $0x3, %r12d
movl %r13d, %r14d
incq %rbp
cmpl %ebp, 0x50(%rsp)
jne 0x40336c
movl 0x38(%rsp), %edx
cmpl $0x1, %edx
sete %al
movl 0x34(%rsp), %esi
cmpl %esi, %edx
setne %cl
orb %al, %cl
je 0x403430
cmpl %esi, %edx
movl 0x14(%rsp), %ebp
jne 0x403439
leal 0x1(%r15), %r13d
movq 0x8(%rsp), %rbx
movq %rbx, %rdi
movl %r15d, %esi
movl %r14d, %edx
movl %r13d, %ecx
movl %r12d, %r8d
callq 0x40266a
leal 0x3(%r12), %r8d
leal 0x1(%r14), %r15d
movq %rbx, %rdi
movl %r13d, %esi
movl %r14d, %edx
movl %r15d, %ecx
callq 0x40266a
addl $0x6, %r12d
movl %r15d, %r14d
movl %r13d, %r15d
movl %r12d, %r13d
jmp 0x40347c
movl %r12d, %r13d
movl 0x14(%rsp), %ebp
jmp 0x40347c
leal 0x3(%r12), %r13d
testl %edx, %edx
je 0x403460
leal 0x1(%r15), %ebx
movq 0x8(%rsp), %rdi
movl %r15d, %esi
movl %r14d, %edx
movl %ebx, %ecx
movl %r12d, %r8d
callq 0x40266a
movl %ebx, %r15d
jmp 0x40347c
leal 0x1(%r14), %ebx
movq 0x8(%rsp), %rdi
movl %r15d, %esi
movl %r14d, %edx
movl %ebx, %ecx
movl %r12d, %r8d
callq 0x40266a
movl %ebx, %r14d
cmpl %ebp, 0x40(%rsp)
jl 0x4034fe
movl 0x30(%rsp), %eax
movl 0x2c(%rsp), %ecx
cmpl %eax, %ecx
cmovgl %ecx, %eax
movslq %eax, %rbx
movslq %ebp, %rax
movq %rax, 0x20(%rsp)
incq %rbx
movq 0x48(%rsp), %rax
movl -0x4(%rax,%rbx,4), %ebp
cmpl 0x18(%rsp), %ebp
jge 0x4034cd
leal 0x1(%r14), %r12d
movq 0x8(%rsp), %rdi
movl %r14d, %esi
movl %r12d, %edx
movl %r15d, %ecx
movl %r13d, %r8d
callq 0x40266a
addl $0x3, %r13d
movl %r12d, %r14d
cmpl 0x1c(%rsp), %ebp
jge 0x4034f4
leal 0x1(%r15), %r12d
movq 0x8(%rsp), %rdi
movl %r15d, %esi
movl %r14d, %edx
movl %r12d, %ecx
movl %r13d, %r8d
callq 0x40266a
addl $0x3, %r13d
movl %r12d, %r15d
decq %rbx
cmpq 0x20(%rsp), %rbx
jg 0x40349d
movl 0x3c(%rsp), %eax
cmpl 0x18(%rsp), %eax
jge 0x40352d
leal 0x1(%r14), %edx
movq 0x8(%rsp), %rdi
movl %r14d, %esi
movl %r15d, %ecx
movl %r13d, %r8d
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x40266a
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq