// File: /workspace/github_cpp_makefile_star2_O2/cloudinary[P]fuif/transform/2dmatch.h
// Function: fwd_match(Image&, std::vector<int, std::allocator<int>>&)
bool fwd_match(Image &input, std::vector<int> &parameters) {
    std::vector<int> adj_params = parameters; // use a copy so empty (default) parameters remain empty
    meta_match(input, adj_params);
    int c0 = input.nb_meta_channels + adj_params[0];
    int cn = input.nb_meta_channels + adj_params[1];
    if (c0 >= input.channel.size() || cn >= input.channel.size()) {
        e_printf("Error: match transform with incorrect parameters.\n");
        return false;
    }
    int maxdist = 10000, erodes = 1;
    if (adj_params.size() > 3) maxdist = adj_params[3];
    if (adj_params[0] == 0 && adj_params[1] == input.nb_channels-1 && adj_params[2] == 0) parameters.clear(); // we can use default parameters
    if (parameters.size() > 3) parameters.pop_back();
    bool softmatch = adj_params[2];
    Channel &m = input.channel[0];
    int w = input.channel[c0].w;
    int h = input.channel[c0].h;

    if (maxdist > 0) {
      v_printf(5,"Running heuristic to find matches (channels %i-%i)\n",c0,cn);
      offsets ot(maxdist + 1);
      make_offsets_table(ot);
      for (int y=0; y<h; y++) {
        if (y%10 == 0) v_printf(7,"Finding matches at row %i\n",y);
        for (int x=0; x<w; x++) {
            if (m.value(y,x)) continue;
            pixel_type z = find_good_match(input,c0,cn,x,y,ot);
            if (!z) continue;
            int count=0;
            for (int yy=0; y+yy<h; yy++) {
                int xl=0;
                for (; x+xl>=0; xl--) {
                    if (matches(input,c0,cn,x+xl,y+yy,z,ot,false)) {
                        if (m.value(y+yy,x+xl) == 0 || m.value(y+yy,x+xl) > z)
                        { m.value(y+yy,x+xl) = z; count++; }
                    }
                    else break;
                }
                xl++;
                int xr=1;
                for (; x+xr<w; xr++) {
                    if (matches(input,c0,cn,x+xr,y+yy,z,ot,false)) {
                        if (m.value(y+yy,x+xr) == 0 || m.value(y+yy,x+xr) > z)
                        { m.value(y+yy,x+xr) = z; count++; }
                    }
                    else break;
                }
                xr--;
                if (!xl && !xr) break;
            }
            v_printf(8,"Matched %i pixels from seed position (%i,%i)\n",count,x,y);
        }
      }
      for (int y=h-1; y>=0; y--) {
        for (int x=w-1; x>=0; x--) {
            if (m.value(y,x)) do_match(input,c0,cn,x,y,m.value(y,x),ot);
        }
      }
    } else {
      if (input.nb_frames < 2) {
        e_printf("This transform is meant for animations only.\n");
        return false;
      }
      v_printf(5,"Running simple heuristic to find matches from previous frames (channels %i-%i)\n",c0,cn);
      int fh = h / input.nb_frames;
      int offsetcode = 2*fh*fh + (fh&1); // this simple formula corresponds to the code to go exactly one frame up
      m.q = offsetcode;
      int minmatchcount = CLAMP(w/50,5,40); // arbitrary threshold

      for (int n=1; n <= -maxdist; n++)
      for (int y=n*fh; y<h; y++) {
        int matchcount=0;  // to reduce entropy in the match channel, only consider it a match if it matches enough pixels in a row
        bool firstmatch=true;
        for (int x=0; x<w; x++) {
            if (m.value(y,x)) continue;
            bool nomatch = false;
            for (int c=c0; c<=cn; c++)
                if (input.channel[c].value(y,x) != input.channel[c].value(y-n*fh,x)) nomatch=true;
            if (nomatch) { matchcount=0; firstmatch=true; continue; }
            matchcount++;
            if (matchcount >= minmatchcount) {
                if (firstmatch) {
                    for (int prev_x = x-matchcount+1; prev_x < x; prev_x++) {
                        m.value(y,prev_x) = n;
                    }
                }
                firstmatch=false;
                m.value(y,x) = n; // quantization multiplies this by offsetcode;
            }
        }
      }

      // vertical-only erode
/*
      for (int y=fh; y<=h; y++) {
        if (y<h) for (int x=0; x<w; x++) {
            if (m.value(y,x) > 0) {
                if (m.value(y-1,x) == 0
                    && (y+1<h && m.value(y+1,x) == 0)
                ) m.value(y,x) = -m.value(y,x); // if top and bottom are zero, flag this one
            }
        }
        for (int x=0; x<w; x++) {
            if (m.value(y-1,x) < 0) m.value(y-1,x) = 0;
        }
      }
*/

     // simple erode, reduces entropy and helps to avoid lossy artifacts accumulating at the edges

    for (int it=0; it<3; it++)
      for (int y=fh; y<=h; y++) {
        if (y<h) for (int x=0; x<w; x++) {
            if (m.value(y,x) > 0) {
                if (m.value(y-1,x) == 0
                    || (x>0 && m.value(y,x-1) == 0)
                    || (y+1<h && m.value(y+1,x) <= 0)
                    || (x+1<w && m.value(y,x+1) <= 0)
                ) m.value(y,x) = -m.value(y,x); // if any neighbor is zero, flag this one
            }
        }
//        for (int x=0; x<w; x++) {
//            if (m.value(y-1,x) < 0) m.value(y-1,x) = 0;
//        }
      }


      for (int y=fh; y<h; y++) {
        for (int x=0; x<w; x++) {
            if (m.value(y,x) > 0)
                for (int c=c0; c<=cn; c++)
                    input.channel[c].value(y,x) = 0;
            else if (m.value(y,x) < 0) m.value(y,x) *= -1;
        }
      }

    }
    return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xa8, %rsp
movq %rsi, %r15
movq %rdi, %r13
leaq 0x90(%rsp), %rbx
movq %rbx, %rdi
callq 0x5326
movq %r13, %rdi
movq %rbx, %rsi
callq 0x8b45
movl 0x6c(%r13), %r9d
movq 0x90(%rsp), %rax
movl (%rax), %ecx
leal (%rcx,%r9), %edx
movl %edx, 0x10(%rsp)
movslq %edx, %r12
movq (%r13), %rdi
movq 0x8(%r13), %rsi
subq %rdi, %rsi
sarq $0x6, %rsi
cmpq %r12, %rsi
jbe 0x943e
movl 0x4(%rax), %edx
addl %edx, %r9d
movslq %r9d, %r8
movq %r8, 0x20(%rsp)
cmpq %r8, %rsi
jbe 0x943e
movq %r9, 0x40(%rsp)
movq %rdi, (%rsp)
movq 0x98(%rsp), %rsi
subq %rax, %rsi
movl $0x2710, %r14d          # imm = 0x2710
cmpq $0xd, %rsi
jb 0x90d0
movl 0xc(%rax), %r14d
testl %ecx, %ecx
jne 0x90f1
movl 0x64(%r13), %ecx
decl %ecx
cmpl %ecx, %edx
jne 0x90f1
cmpl $0x0, 0x8(%rax)
jne 0x90f1
movq (%r15), %rax
cmpq %rax, 0x8(%r15)
je 0x90f1
movq %rax, 0x8(%r15)
movq 0x8(%r15), %rax
movq %rax, %rcx
subq (%r15), %rcx
cmpq $0xd, %rcx
jb 0x9109
addq $-0x4, %rax
movq %rax, 0x8(%r15)
movq %r12, %rdx
shlq $0x6, %rdx
movq (%rsp), %rax
movl 0x18(%rax,%rdx), %ecx
movl %ecx, 0x1c(%rsp)
movl 0x1c(%rax,%rdx), %r15d
testl %r14d, %r14d
movq %r13, 0x48(%rsp)
movl %r15d, 0x18(%rsp)
jle 0x946f
leaq 0x14d02(%rip), %rsi     # 0x1de3d
pushq $0x5
popq %rdi
movl 0x10(%rsp), %edx
movq 0x40(%rsp), %r12
movl %r12d, %ecx
xorl %eax, %eax
callq 0x16c30
incl %r14d
leaq 0x78(%rsp), %rbx
leaq 0x5f(%rsp), %rdx
movq %rbx, %rdi
movq %r14, %rsi
callq 0xa9bc
movq %rbx, %rdi
callq 0x862d
movl 0x1c(%rsp), %eax
testl %eax, %eax
movl $0x0, %ecx
cmovgl %eax, %ecx
movl %ecx, 0x68(%rsp)
testl %r15d, %r15d
movl $0x0, %eax
cmovgl %r15d, %eax
movl %eax, 0x58(%rsp)
movl $0x0, 0x28(%rsp)
xorl %ebp, %ebp
movq (%rsp), %r14
cmpl %ebp, %r15d
movl %ebp, %eax
cmovgl %r15d, %eax
movl %eax, 0xc(%rsp)
cmpl 0x58(%rsp), %ebp
je 0x942b
movl %ebp, %eax
xorl %edx, %edx
pushq $0xa
popq %rcx
divl %ecx
testl %edx, %edx
jne 0x91d8
pushq $0x7
popq %rdi
leaq 0x14ca2(%rip), %rsi     # 0x1de71
movl %ebp, %edx
xorl %eax, %eax
callq 0x16c30
movl 0xc(%rsp), %eax
addl 0x28(%rsp), %eax
movl %eax, 0xc(%rsp)
xorl %r13d, %r13d
movq %rbp, 0x60(%rsp)
cmpl 0x68(%rsp), %r13d
je 0x93c2
movq %r14, %rdi
movl %ebp, %esi
movl %r13d, %edx
callq 0xa44a
cmpw $0x0, (%rax)
jne 0x93ba
movq 0x48(%rsp), %rdi
movl 0x10(%rsp), %esi
movl %r12d, %edx
movq %r13, 0x20(%rsp)
movl %r13d, %ecx
movl %ebp, %r8d
movq %rbx, %r9
callq 0x8dac
testw %ax, %ax
movq 0x20(%rsp), %r13
je 0x93ba
movswl %ax, %ecx
movl %ecx, 0x2c(%rsp)
movl $0x0, 0x30(%rsp)
xorl %ecx, %ecx
cmpl 0xc(%rsp), %ecx
je 0x9395
movl %eax, %ebp
movq 0x60(%rsp), %rax
movq %rcx, 0x38(%rsp)
leal (%rcx,%rax), %r14d
xorl %r15d, %r15d
movq 0x20(%rsp), %rax
movl %eax, %ebx
addl %r15d, %ebx
js 0x92e3
movq 0x48(%rsp), %rdi
movl 0x10(%rsp), %esi
movl %r12d, %edx
movl %ebx, %ecx
movl %r14d, %r8d
movl 0x2c(%rsp), %r9d
pushq $0x0
leaq 0x80(%rsp), %rax
pushq %rax
callq 0x8c27
popq %rcx
popq %rdx
testb %al, %al
je 0x92e3
movq (%rsp), %r13
movq %r13, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
cmpw $0x0, (%rax)
je 0x92ca
movq %r13, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
cmpw %bp, (%rax)
jle 0x92de
movq %r13, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
movw %bp, (%rax)
incl 0x30(%rsp)
decl %r15d
jmp 0x9269
pushq $0x1
popq %rax
movl %eax, %r13d
movq 0x20(%rsp), %rax
leal (%rax,%r13), %ebx
cmpl 0x1c(%rsp), %ebx
jge 0x936e
movq 0x48(%rsp), %rdi
movl 0x10(%rsp), %esi
movl %r12d, %edx
movl %ebx, %ecx
movl %r14d, %r8d
movl 0x2c(%rsp), %r9d
pushq $0x0
leaq 0x80(%rsp), %rax
pushq %rax
callq 0x8c27
popq %rcx
popq %rdx
testb %al, %al
je 0x936e
movq (%rsp), %r12
movq %r12, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
cmpw $0x0, (%rax)
je 0x934d
movq %r12, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
cmpw %bp, (%rax)
jle 0x9361
movq %r12, %rdi
movl %r14d, %esi
movl %ebx, %edx
callq 0xa44a
movw %bp, (%rax)
incl 0x30(%rsp)
incl %r13d
movq 0x40(%rsp), %r12
jmp 0x92e9
notl %r15d
xorl $0x1, %r13d
movq 0x38(%rsp), %rcx
incl %ecx
orl %r15d, %r13d
movq (%rsp), %r14
movl 0x18(%rsp), %r15d
leaq 0x78(%rsp), %rbx
movl %ebp, %eax
jne 0x924c
pushq $0x8
popq %rdi
leaq 0x14aed(%rip), %rsi     # 0x1de8c
movl 0x30(%rsp), %edx
movq 0x20(%rsp), %r13
movl %r13d, %ecx
movq 0x60(%rsp), %rbp
movl %ebp, %r8d
xorl %eax, %eax
callq 0x16c30
incl %r13d
jmp 0x91ec
incl %ebp
decl 0x28(%rsp)
movq 0x48(%rsp), %r13
jmp 0x91a1
decl %r15d
movl 0x1c(%rsp), %ebx
movl %ebx, %eax
leal -0x1(%rax), %ebx
testl %eax, %eax
jle 0x942b
movq %r14, %rdi
movl %r15d, %esi
movl %ebx, %edx
callq 0xa44a
cmpw $0x0, (%rax)
je 0x93d9
movq %r14, %rdi
movl %r15d, %esi
movl %ebx, %edx
callq 0xa44a
movswl (%rax), %r9d
subq $0x8, %rsp
movq %r13, %rdi
movl 0x18(%rsp), %esi
movl %r12d, %edx
movl %ebx, %ecx
movl %r15d, %r8d
leaq 0x80(%rsp), %rax
pushq %rax
callq 0x8d0d
popq %rax
popq %rcx
jmp 0x93d9
testl %r15d, %r15d
jg 0x93d2
leaq 0x78(%rsp), %rdi
callq 0xc00e
movb $0x1, %bl
jmp 0x944e
xorl %ebx, %ebx
leaq 0x14930(%rip), %rdi     # 0x1dd77
xorl %eax, %eax
callq 0x16b80
leaq 0x90(%rsp), %rdi
callq 0x5374
movl %ebx, %eax
addq $0xa8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rdx, 0x68(%rsp)
cmpl $0x1, 0x38(%r13)
jg 0x948d
xorl %ebx, %ebx
leaq 0x14a36(%rip), %rdi     # 0x1deba
xorl %eax, %eax
callq 0x16b80
jmp 0x944e
leaq 0x14a54(%rip), %rsi     # 0x1dee8
xorl %ebp, %ebp
pushq $0x5
popq %rbx
movl %ebx, %edi
movl 0x10(%rsp), %edx
movq 0x40(%rsp), %rcx
xorl %eax, %eax
callq 0x16c30
pushq $0x1
popq %rdi
movl %r15d, %eax
cltd
idivl 0x38(%r13)
movl %eax, %edx
imull %edx, %edx
movl %eax, 0x54(%rsp)
movl %eax, %ecx
andl $0x1, %ecx
leal (%rcx,%rdx,2), %eax
movq (%rsp), %rcx
movl %eax, 0x28(%rcx)
pushq $0x32
popq %rcx
movl 0x1c(%rsp), %esi
movl %esi, %eax
cltd
idivl %ecx
cmpl $0x802, %esi            # imm = 0x802
pushq $0x28
popq %rcx
cmovll %eax, %ecx
cmpl $0xfa, %esi
cmovll %ebx, %ecx
movl %ecx, 0x28(%rsp)
testl %esi, %esi
cmovgl %esi, %ebp
movl %edi, %eax
subl %r14d, %eax
movl %eax, 0x74(%rsp)
movq %r12, 0x60(%rsp)
movl %ebp, %ebx
movl %ebp, 0x38(%rsp)
cmpl 0x74(%rsp), %edi
je 0x9681
movl %edi, 0x40(%rsp)
movl %edi, %ebp
imull 0x54(%rsp), %ebp
movl %ebp, 0x58(%rsp)
movq (%rsp), %r14
cmpl %r15d, %ebp
jge 0x9676
movl %ebp, %eax
subl 0x58(%rsp), %eax
movl %eax, 0x2c(%rsp)
movb $0x1, %al
movl %eax, 0xc(%rsp)
movq $0x0, 0x30(%rsp)
xorl %r15d, %r15d
movl %ebp, 0x10(%rsp)
cmpl %ebx, %r15d
je 0x966a
movq %r14, %rdi
movl %ebp, %esi
movl %r15d, %edx
callq 0xa44a
cmpw $0x0, (%rax)
je 0x957b
movq 0x30(%rsp), %rax
movl %eax, %r13d
jmp 0x9655
xorl %r13d, %r13d
movq 0x68(%rsp), %rbx
cmpq 0x20(%rsp), %r12
jg 0x95cc
movq 0x48(%rsp), %rbp
movq (%rbp), %rdi
addq %rbx, %rdi
movl 0x10(%rsp), %esi
movl %r15d, %edx
callq 0xa44a
movzwl (%rax), %r14d
movq (%rbp), %rdi
addq %rbx, %rdi
movl 0x2c(%rsp), %esi
movl %r15d, %edx
callq 0xa44a
cmpw (%rax), %r14w
setne %al
orb %al, %r13b
incq %r12
addq $0x40, %rbx
jmp 0x9583
testb $0x1, %r13b
je 0x95ee
movb $0x1, %al
movl %eax, 0xc(%rsp)
xorl %r13d, %r13d
movq (%rsp), %r14
movq 0x60(%rsp), %r12
movl 0x38(%rsp), %ebx
movl 0x10(%rsp), %ebp
jmp 0x9655
movq 0x30(%rsp), %rax
leal 0x1(%rax), %r13d
cmpl 0x28(%rsp), %r13d
movq (%rsp), %r14
movq 0x60(%rsp), %r12
movl 0x10(%rsp), %ebp
jl 0x9651
testb $0x1, 0xc(%rsp)
je 0x9635
movl %r15d, %ebx
subl 0x30(%rsp), %ebx
cmpl %r15d, %ebx
jge 0x9635
movq %r14, %rdi
movl %ebp, %esi
movl %ebx, %edx
callq 0xa44a
movl 0x40(%rsp), %ecx
movw %cx, (%rax)
incl %ebx
jmp 0x9619
movq %r14, %rdi
movl %ebp, %esi
movl %r15d, %edx
callq 0xa44a
movl 0x40(%rsp), %ecx
movw %cx, (%rax)
movl $0x0, 0xc(%rsp)
movl 0x38(%rsp), %ebx
incl %r15d
movl %r13d, %eax
movq %rax, 0x30(%rsp)
movq 0x48(%rsp), %r13
jmp 0x9552
incl %ebp
movl 0x18(%rsp), %r15d
jmp 0x9529
movl 0x40(%rsp), %edi
incl %edi
jmp 0x950c
xorl %ecx, %ecx
movl 0x54(%rsp), %eax
movl %eax, %r14d
cmpl $0x3, %ecx
movl %ecx, 0x10(%rsp)
jne 0x978b
jmp 0x979b
jge 0x9775
leal -0x1(%r14), %ebp
leal 0x1(%r14), %r15d
xorl %r13d, %r13d
cmpl %r13d, %ebx
je 0x977a
movq (%rsp), %rdi
movl %r14d, %esi
movl %r13d, %edx
callq 0xa44a
cmpw $0x0, (%rax)
jle 0x976d
movq (%rsp), %rdi
movl %ebp, %esi
movl %r13d, %edx
callq 0xa44a
cmpw $0x0, (%rax)
je 0x9736
testl %r13d, %r13d
je 0x96fe
leal -0x1(%r13), %edx
movq (%rsp), %rdi
movl %r14d, %esi
callq 0xa44a
cmpw $0x0, (%rax)
je 0x9736
cmpl 0x18(%rsp), %r15d
jge 0x971a
movq (%rsp), %rdi
movl %r15d, %esi
movl %r13d, %edx
callq 0xa44a
cmpw $0x0, (%rax)
jle 0x9736
leal 0x1(%r13), %edx
cmpl 0x1c(%rsp), %edx
jge 0x976d
movq (%rsp), %rdi
movl %r14d, %esi
callq 0xa44a
cmpw $0x0, (%rax)
jg 0x976d
movq (%rsp), %rbx
movq %rbx, %rdi
movl %r14d, %esi
movl %r13d, %edx
callq 0xa44a
movzwl (%rax), %eax
xorl %r12d, %r12d
subw %ax, %r12w
movq %rbx, %rdi
movl 0x38(%rsp), %ebx
movl %r14d, %esi
movl %r13d, %edx
callq 0xa44a
movw %r12w, (%rax)
movq 0x60(%rsp), %r12
incl %r13d
jmp 0x96ad
incl %r14d
jmp 0x978b
movl %r15d, %r14d
movq 0x48(%rsp), %r13
movl 0x18(%rsp), %r15d
movl 0x10(%rsp), %ecx
cmpl %r15d, %r14d
jle 0x969c
incl %ecx
jmp 0x9683
movq %r12, %rax
shlq $0x6, %rax
movq %rax, 0x10(%rsp)
movq (%rsp), %r14
movl 0x54(%rsp), %eax
cmpl %r15d, %eax
jge 0x943a
movl %eax, %ebx
xorl %ebp, %ebp
cmpl 0x38(%rsp), %ebp
je 0x9833
movq %r14, %rdi
movl %ebx, %r15d
movl %ebx, %esi
movl %ebp, %edx
callq 0xa44a
cmpw $0x0, (%rax)
jle 0x9803
movq 0x10(%rsp), %r14
movq %r12, %r15
cmpq 0x20(%rsp), %r15
jg 0x9826
movq (%r13), %rdi
addq %r14, %rdi
movl %ebx, %esi
movl %ebp, %edx
callq 0xa44a
andw $0x0, (%rax)
incq %r15
addq $0x40, %r14
jmp 0x97df
movq %r14, %rdi
movl %r15d, %esi
movl %ebp, %edx
callq 0xa44a
cmpw $0x0, (%rax)
jns 0x9826
movq (%rsp), %rdi
movl %ebx, %esi
movl %ebp, %edx
callq 0xa44a
negw (%rax)
incl %ebp
movq (%rsp), %r14
movl 0x18(%rsp), %r15d
jmp 0x97bc
movl %ebx, %eax
incl %eax
jmp 0x97af
jmp 0x9842
jmp 0x9842
jmp 0x9842
movq %rax, %rbx
jmp 0x9858
jmp 0x984b
jmp 0x984b
movq %rax, %rbx
leaq 0x78(%rsp), %rdi
callq 0xc00e
leaq 0x90(%rsp), %rdi
callq 0x5374
movq %rbx, %rdi
callq 0x35d0