// File: /workspace/github_cpp_makefile_star2_O1/drummyfish[P]flowchart/src/lodepng.cpp
// Function: filter(unsigned char*, unsigned char const*, unsigned int, unsigned int, LodePNGColorMode const*, LodePNGEncoderSettings const*)
static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
                       const LodePNGColorMode* info, const LodePNGEncoderSettings* settings)
{
  /*
  For PNG filter method 0
  out must be a buffer with as size: h + (w * h * bpp + 7) / 8, because there are
  the scanlines with 1 extra byte per scanline
  */

  unsigned bpp = lodepng_get_bpp(info);
  /*the width of a scanline in bytes, not including the filter type*/
  size_t linebytes = (w * bpp + 7) / 8;
  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7) / 8;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  /*
  There is a heuristic called the minimum sum of absolute differences heuristic, suggested by the PNG standard:
   *  If the image type is Palette, or the bit depth is smaller than 8, then do not filter the image (i.e.
      use fixed filtering, with the filter None).
   * (The other case) If the image type is Grayscale or RGB (with or without Alpha), and the bit depth is
     not smaller than 8, then use adaptive filtering heuristic as follows: independently for each row, apply
     all five filters and select the filter that produces the smallest sum of absolute values per row.
   This heuristic is used if filter strategy is LFS_HEURISTIC. Parts of it are used for filter strategies
   LFS_MINSUM and LFS_ZERO.
  */
  int heuristic_zero = info->colortype == LCT_PALETTE || info->bitdepth < 8;

  if(bpp == 0) return 31; /*error: invalid color type*/

  if((!heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
      settings->filter_strategy == LFS_MINSUM)
  {
    /*adaptive filtering*/
    size_t sum[5];
    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned type, bestType = 0;

    for(type = 0; type < 5; type++) ucvector_init(&attempt[type]);

    for(type = 0; type < 5; type++)
    {
      if(!ucvector_resize(&attempt[type], linebytes)) ERROR_BREAK(83 /*alloc fail*/);
    }

    if(!error)
    {
      for(y = 0; y < h; y++)
      {
        /*try the 5 filter types*/
        for(type = 0; type < 5; type++)
        {
          filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);

          /*calculate the sum of the result*/
          sum[type] = 0;
          /*note that not all pixels are checked to speed this up while still having probably the best choice*/
          for(x = 0; x < attempt[type].size; x+=3)
          {
            /*For differences, each byte should be treated as signed, values above 127 are negative
            (converted to signed char). Filtertype 0 isn't a difference though, so use unsigned there.
            This means filtertype 0 is almost never chosen, but that is justified.*/
            if(type == 0) sum[type] += (unsigned char)(attempt[type].data[x]);
            else
            {
              signed char s = (signed char)(attempt[type].data[x]);
              sum[type] += s < 0 ? -s : s;
            }
          }

          /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
          if(type == 0 || sum[type] < smallest)
          {
            bestType = type;
            smallest = sum[type];
          }
        }

        prevline = &in[y * linebytes];

        /*now fill the out values*/
        out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
        for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
      }
    }

    for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
  }
  else if((heuristic_zero && settings->filter_strategy == LFS_HEURISTIC)||
      settings->filter_strategy == LFS_ZERO)
  {
    for(y = 0; y < h; y++)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      const unsigned TYPE = 0;
      out[outindex] = TYPE; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, TYPE);
      prevline = &in[inindex];
    }
  }
  else if(settings->filter_strategy == LFS_PREDEFINED)
  {
    for(y = 0; y < h; y++)
    {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      unsigned type = settings->predefined_filters[y];
      out[outindex] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  }
  else /*LFS_BRUTE_FORCE*/
  {
    /*brute force filter chooser.
    deflate the scanline after every filter attempt to see which one deflates best.
    This is very slow and gives only slightly smaller, sometimes even larger, result*/
    size_t size[5];
    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned type = 0, bestType = 0;
    unsigned char* dummy;
    LodePNGCompressSettings zlibsettings = settings->zlibsettings;
    /*use fixed tree on the attempts so that the tree is not adapted to the filtertype on purpose,
    to simulate the true case where the tree is the same for the whole image. Sometimes it gives
    better result with dynamic tree anyway. Using the fixed tree sometimes gives worse, but in rare
    cases better compression. It does make this a bit less slow, so it's worth doing this.*/
    zlibsettings.btype = 1;
    /*a custom encoder likely doesn't read the btype setting and is optimized for complete PNG
    images only, so disable it*/
    zlibsettings.custom_zlib = 0;
    zlibsettings.custom_deflate = 0;
    for(type = 0; type < 5; type++)
    {
      ucvector_init(&attempt[type]);
      ucvector_resize(&attempt[type], linebytes); /*todo: give error if resize failed*/
    }
    for(y = 0; y < h; y++) /*try the 5 filter types*/
    {
      for(type = 0; type < 5; type++)
      {
        unsigned testsize = attempt[type].size;
        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/

        filterScanline(attempt[type].data, &in[y * linebytes], prevline, linebytes, bytewidth, type);
        size[type] = 0;
        dummy = 0;
        zlib_compress(&dummy, &size[type], attempt[type].data, testsize, &zlibsettings);
        myfree(dummy);
        /*check if this is smallest size (or if type == 0 it's the first case so always store the values)*/
        if(type == 0 || size[type] < smallest)
        {
          bestType = type;
          smallest = size[type];
        }
      }
      prevline = &in[y * linebytes];
      out[y * (linebytes + 1)] = bestType; /*the first byte of a scanline will be the filter type*/
      for(x = 0; x < linebytes; x++) out[y * (linebytes + 1) + 1 + x] = attempt[bestType].data[x];
    }
    for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
  }

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x148, %rsp            # imm = 0x148
movq %r9, %rbx
movl %ecx, %r13d
movq %rdi, %rbp
movl (%r8), %eax
movl 0x4(%r8), %ecx
xorl %r15d, %r15d
cmpq $0x6, %rax
ja 0xd7f5
leaq 0x4dbb(%rip), %rdi      # 0x125ac
movl (%rdi,%rax,4), %r15d
imull %ecx, %r15d
cmpl $0x3, %eax
sete %al
cmpl $0x8, %ecx
setb %cl
testl %r15d, %r15d
je 0xd8e0
imull %r15d, %edx
addl $0x7, %edx
movl %edx, 0xc(%rsp)
movl %edx, %r10d
shrl $0x3, %r10d
addl $0x7, %r15d
shrl $0x3, %r15d
orb %cl, %al
movq %rbp, 0x60(%rsp)
movq %rsi, 0x18(%rsp)
movq %r10, (%rsp)
jne 0xd840
cmpl $0x0, 0x2c(%rbx)
je 0xd84c
movl 0x2c(%rbx), %ecx
cmpl $0x2, %ecx
jne 0xd8ea
movq %r15, 0x30(%rsp)
xorps %xmm0, %xmm0
leaq 0xd0(%rsp), %rdi
movaps %xmm0, 0x60(%rdi)
movaps %xmm0, 0x50(%rdi)
movaps %xmm0, 0x40(%rdi)
movaps %xmm0, 0x30(%rdi)
movaps %xmm0, 0x20(%rdi)
movaps %xmm0, 0x10(%rdi)
movaps %xmm0, (%rdi)
movq $0x0, 0x70(%rdi)
movq %r10, %rsi
callq 0xbdfa
testl %eax, %eax
je 0xd9a8
leaq 0xe8(%rsp), %rbx
xorl %r15d, %r15d
xorl %ecx, %ecx
movq %rcx, %r14
cmpq $0x4, %rcx
movq (%rsp), %r8
je 0xd8ca
movq %rbx, %rdi
movq %r8, %rsi
callq 0xbdfa
addq $0x18, %rbx
leaq 0x1(%r14), %rcx
testl %eax, %eax
jne 0xd89c
movl $0x53, %r15d
movq (%rsp), %r8
movq %r15, 0x38(%rsp)
cmpq $0x4, %r14
setae %al
movq 0x18(%rsp), %rdx
jmp 0xd9bd
movl $0x1f, %eax
jmp 0xdd84
testl %ecx, %ecx
sete %dl
testb %dl, %al
jne 0xd959
cmpl $0x1, %ecx
je 0xd959
cmpl $0x4, %ecx
jne 0xdb61
testl %r13d, %r13d
je 0xdd82
leaq 0x1(%r10), %rax
movq %rax, 0x30(%rsp)
movl %r13d, %r12d
incq %rbp
xorl %r13d, %r13d
xorl %edx, %edx
movq %rsi, %r14
movq 0x30(%rbx), %rax
movzbl (%rax,%r13), %r9d
movb %r9b, -0x1(%rbp)
movq %rbp, %rdi
movq %r10, %rcx
movq %r15, %r8
callq 0xdd96
movq (%rsp), %r10
incq %r13
addq 0x30(%rsp), %rbp
leaq (%r14,%r10), %rsi
movq %r14, %rdx
cmpq %r13, %r12
jne 0xd91e
jmp 0xdd82
testl %r13d, %r13d
je 0xdd82
leaq 0x1(%r10), %rax
movl %r13d, %ecx
leaq 0x1(%rbp), %rdx
xorl %r9d, %r9d
movq %rax, %rdi
imulq %r9, %rdi
movb $0x0, (%rbp,%rdi)
cmpl $0x8, 0xc(%rsp)
jb 0xd995
xorl %edi, %edi
movb (%rsi,%rdi), %r8b
movb %r8b, (%rdx,%rdi)
incq %rdi
cmpq %rdi, %r10
jne 0xd985
incq %r9
addq %rax, %rdx
addq %r10, %rsi
cmpq %rcx, %r9
jne 0xd970
jmp 0xdd82
movl $0x53, %eax
movq %rax, 0x38(%rsp)
xorl %eax, %eax
movq 0x18(%rsp), %rdx
movq (%rsp), %r8
testl %r13d, %r13d
sete %cl
xorb $0x1, %al
orb %cl, %al
jne 0xdb27
leaq 0x1(%r8), %rsi
cmpl $0x2, %r8d
movl $0x1, %edi
cmovael %r8d, %edi
movl %r13d, %eax
movq %rax, 0x40(%rsp)
leaq 0x1(%rbp), %r9
xorl %r10d, %r10d
xorl %r13d, %r13d
xorl %r15d, %r15d
movl $0x0, 0x10(%rsp)
movq %rsi, 0x50(%rsp)
movq %rdi, 0x48(%rsp)
movq %r9, 0x28(%rsp)
movq %r13, %rbx
movq %r10, 0x20(%rsp)
movq %r10, %r13
imulq %r8, %r13
addq %rdx, %r13
xorl %r12d, %r12d
leaq (%r12,%r12,2), %r14
movq 0xd0(%rsp,%r14,8), %rbp
movzbl %r12b, %r9d
movq %rbp, %rdi
movq %r13, %rsi
movq %rbx, %rdx
movq %r8, %rcx
movq 0x30(%rsp), %r8
callq 0xdd96
movq $0x0, 0x70(%rsp,%r12,8)
movq 0xd8(%rsp,%r14,8), %rax
testq %rax, %rax
je 0xda9b
movq 0x70(%rsp,%r12,8), %rcx
movl $0x3, %edx
xorl %esi, %esi
movzbl (%rbp,%rsi), %esi
movl %esi, %edi
sarb $0x7, %dil
movl %esi, %r8d
xorb %dil, %r8b
subb %dil, %r8b
testq %r12, %r12
movzbl %r8b, %edi
cmovel %esi, %edi
movzbl %dil, %esi
addq %rsi, %rcx
movl %edx, %esi
addl $0x3, %edx
cmpq %rsi, %rax
ja 0xda67
movq %rcx, 0x70(%rsp,%r12,8)
testq %r12, %r12
je 0xdaa7
cmpq %r15, 0x70(%rsp,%r12,8)
jae 0xdab1
movq 0x70(%rsp,%r12,8), %r15
movl %r12d, 0x10(%rsp)
incq %r12
cmpq $0x5, %r12
movq (%rsp), %r8
jne 0xda1f
movq 0x50(%rsp), %rsi
movq %rsi, %rax
movq 0x20(%rsp), %r10
imulq %r10, %rax
movq 0x60(%rsp), %rcx
movl 0x10(%rsp), %edx
movb %dl, (%rcx,%rax)
cmpl $0x8, 0xc(%rsp)
movq 0x48(%rsp), %rdi
movq 0x28(%rsp), %r9
jb 0xdb11
movl 0x10(%rsp), %eax
leaq (%rax,%rax,2), %rax
movq 0xd0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%r9,%rcx)
incq %rcx
cmpq %rcx, %rdi
jne 0xdb02
incq %r10
addq %rsi, %r9
cmpq 0x40(%rsp), %r10
movq 0x18(%rsp), %rdx
jne 0xda05
xorl %ebx, %ebx
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp,%rbx)
movq 0xd0(%rsp,%rbx), %rdi
callq 0x2220
movq $0x0, 0xd0(%rsp,%rbx)
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xdb29
movq 0x38(%rsp), %rax
jmp 0xdd84
movq %r15, 0x30(%rsp)
movups (%rbx), %xmm0
movups 0x10(%rbx), %xmm1
movaps %xmm0, 0xa0(%rsp)
movaps %xmm1, 0xb0(%rsp)
movq 0x20(%rbx), %rax
movq %rax, 0xc0(%rsp)
movl $0x1, 0xa0(%rsp)
xorps %xmm0, %xmm0
movaps %xmm0, 0xb0(%rsp)
xorl %ebx, %ebx
leaq (%rsp,%rbx), %rdi
addq $0xd0, %rdi
xorps %xmm0, %xmm0
movups %xmm0, (%rdi)
movq $0x0, 0x10(%rdi)
movq %r10, %rsi
callq 0xbdfa
movq (%rsp), %r10
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xdba1
testl %r13d, %r13d
movq 0x18(%rsp), %rax
je 0xdd52
cmpl $0x2, %r10d
movl $0x1, %esi
cmovael %r10d, %esi
leaq 0x1(%r10), %rdi
movl %r13d, %ecx
movq %rcx, 0x68(%rsp)
leaq 0x1(%rbp), %r8
xorl %r9d, %r9d
movl $0x0, 0x20(%rsp)
movq $0x0, 0x10(%rsp)
movq $0x0, 0x28(%rsp)
movq %rsi, 0x40(%rsp)
movq %rdi, 0x38(%rsp)
movq %r8, 0x50(%rsp)
movq 0x28(%rsp), %rbx
movq %r9, 0x48(%rsp)
imulq %r10, %r9
addq %rax, %r9
movq %r9, 0x28(%rsp)
leaq 0x70(%rsp), %rbp
leaq 0xd8(%rsp), %r12
xorl %r15d, %r15d
movl (%r12), %r14d
movq -0x8(%r12), %r13
movzbl %r15b, %r9d
movq %r13, %rdi
movq 0x28(%rsp), %rsi
movq %rbx, %rdx
movq %r10, %rcx
movq 0x30(%rsp), %r8
callq 0xdd96
xorl %eax, %eax
movq %rax, 0x70(%rsp,%r15,8)
movq %rax, 0x58(%rsp)
movq 0xb0(%rsp), %rax
leaq 0x58(%rsp), %rdi
movq %rbp, %rsi
movq %r13, %rdx
movq %r14, %rcx
leaq 0xa0(%rsp), %r8
testq %rax, %rax
je 0xdca5
callq *%rax
jmp 0xdcaa
callq 0x5296
movq 0x58(%rsp), %rdi
callq 0x2220
testq %r15, %r15
je 0xdcc5
movq 0x10(%rsp), %rax
cmpq %rax, 0x70(%rsp,%r15,8)
jae 0xdcd4
movq 0x70(%rsp,%r15,8), %rax
movq %rax, 0x10(%rsp)
movl %r15d, 0x20(%rsp)
incq %r15
addq $0x18, %r12
addq $0x8, %rbp
cmpq $0x5, %r15
movq (%rsp), %r10
jne 0xdc4d
movq 0x38(%rsp), %rdi
movq %rdi, %rax
movq 0x48(%rsp), %r9
imulq %r9, %rax
movq 0x60(%rsp), %rcx
movl 0x20(%rsp), %edx
movb %dl, (%rcx,%rax)
cmpl $0x8, 0xc(%rsp)
movq 0x40(%rsp), %rsi
movq 0x50(%rsp), %r8
jb 0xdd3c
movl 0x20(%rsp), %eax
leaq (%rax,%rax,2), %rax
movq 0xd0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%r8,%rcx)
incq %rcx
cmpq %rcx, %rsi
jne 0xdd2d
incq %r9
addq %rdi, %r8
cmpq 0x68(%rsp), %r9
movq 0x18(%rsp), %rax
jne 0xdc22
xorl %ebx, %ebx
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp,%rbx)
movq 0xd0(%rsp,%rbx), %rdi
callq 0x2220
movq $0x0, 0xd0(%rsp,%rbx)
addq $0x18, %rbx
cmpq $0x78, %rbx
jne 0xdd54
xorl %eax, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq