// File: /workspace/github_cpp_makefile_star2_O2/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, %rbp
movq %r8, %r14
movl %ecx, %ebx
movl %edx, %r13d
movq %rsi, 0x30(%rsp)
movq %rdi, %r12
movq %r8, %rdi
callq 0x45e2
imull %eax, %r13d
addl $0x7, %r13d
shrl $0x3, %r13d
leal 0x7(%rax), %ecx
shrl $0x3, %ecx
movq %rcx, 0x38(%rsp)
cmpl $0x3, (%r14)
pushq $0x1f
popq %r15
movq %r13, 0x10(%rsp)
movq %r12, 0x48(%rsp)
jne 0xa641
movb $0x1, %cl
testl %eax, %eax
jne 0xa65a
jmp 0xaacb
testl %eax, %eax
je 0xaacb
movb $0x1, %cl
cmpl $0x8, 0x4(%r14)
jb 0xa65a
cmpl $0x0, 0x2c(%rbp)
je 0xa662
xorl %ecx, %ecx
movl 0x2c(%rbp), %eax
cmpl $0x2, %eax
jne 0xa6bc
xorl %eax, %eax
xorps %xmm0, %xmm0
cmpq $0x78, %rax
je 0xa684
movups %xmm0, 0xa0(%rsp,%rax)
andq $0x0, 0xb0(%rsp,%rax)
addq $0x18, %rax
jmp 0xa667
movl %ebx, %ebp
xorl %ecx, %ecx
pushq $0x53
popq %r15
leaq 0x18(%rcx), %rbx
cmpq $0x90, %rbx
je 0xa775
leaq (%rsp,%rcx), %rdi
addq $0xa0, %rdi
movq %r13, %rsi
callq 0x925a
movq %rbx, %rcx
testl %eax, %eax
jne 0xa68c
jmp 0xa8b1
movl %ebx, %r14d
testl %eax, %eax
sete %dl
testb %dl, %cl
jne 0xa72f
cmpl $0x1, %eax
je 0xa72f
cmpl $0x4, %eax
jne 0xa8d3
leaq 0x1(%r13), %rax
movq %rax, 0x10(%rsp)
movl %r14d, %r15d
incq %r12
movq %r12, %rbx
xorl %r12d, %r12d
xorl %edx, %edx
movq 0x30(%rsp), %rax
cmpq %r12, %r15
je 0xaac8
movq %rax, %r14
movq 0x30(%rbp), %rax
movzbl (%rax,%r12), %r9d
movb %r9b, -0x1(%rbx)
movq %rbx, %rdi
movq %r14, %rsi
movq %r13, %rcx
movq 0x38(%rsp), %r8
callq 0xaae0
incq %r12
addq 0x10(%rsp), %rbx
leaq (%r14,%r13), %rax
movq %r14, %rdx
jmp 0xa6f2
leaq 0x1(%r13), %rbx
movl %r14d, %r15d
incq %r12
xorl %edx, %edx
movq 0x30(%rsp), %rax
subq $0x1, %r15
jb 0xaac8
movq %rax, %r14
movb $0x0, -0x1(%r12)
movq %r12, %rdi
movq %rax, %rsi
movq %r13, %rcx
movq 0x38(%rsp), %r8
xorl %r9d, %r9d
callq 0xaae0
addq %rbx, %r12
leaq (%r14,%r13), %rax
movq %r14, %rdx
jmp 0xa740
leaq 0x1(%r13), %rax
movq %rax, 0x20(%rsp)
movl %ebp, %eax
movq %rax, 0x40(%rsp)
leaq 0x1(%r12), %rax
movq %rax, 0x18(%rsp)
xorl %eax, %eax
xorl %r15d, %r15d
xorl %ebx, %ebx
xorl %r12d, %r12d
cmpq 0x40(%rsp), %rax
movq %rax, %rcx
movq 0x30(%rsp), %rax
je 0xa8ae
movq %rcx, 0x28(%rsp)
imulq %r13, %rcx
addq %rax, %rcx
movq %rcx, 0x8(%rsp)
xorl %r13d, %r13d
cmpq $0x5, %r13
je 0xa84f
imulq $0x18, %r13, %rbp
movq 0xa0(%rsp,%rbp), %r14
movzbl %r13b, %r9d
movq %r14, %rdi
movq 0x8(%rsp), %rsi
movq %r12, %rdx
movq 0x10(%rsp), %rcx
movq 0x38(%rsp), %r8
callq 0xaae0
movq 0xa8(%rsp,%rbp), %rcx
xorl %eax, %eax
xorl %edx, %edx
movl %edx, %edx
cmpq %rdx, %rcx
jbe 0xa831
movzbl (%r14,%rdx), %esi
movl %esi, %edi
sarb $0x7, %dil
movl %esi, %r8d
xorb %dil, %r8b
subb %dil, %r8b
testq %r13, %r13
movzbl %r8b, %edi
cmovel %esi, %edi
movzbl %dil, %esi
addq %rsi, %rax
addl $0x3, %edx
jmp 0xa800
testq %r13, %r13
sete %cl
cmpq %rbx, %rax
setb %dl
orb %cl, %dl
cmovnel %r13d, %r15d
cmovneq %rax, %rbx
incq %r13
jmp 0xa7c0
movq 0x20(%rsp), %rax
imulq 0x28(%rsp), %rax
movq 0x48(%rsp), %rcx
movb %r15b, (%rcx,%rax)
movl %r15d, %eax
imulq $0x18, %rax, %rax
addq %rsp, %rax
addq $0xa0, %rax
xorl %ecx, %ecx
movq 0x10(%rsp), %r13
movq 0x18(%rsp), %rsi
cmpq %rcx, %r13
je 0xa892
movq (%rax), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rsi,%rcx)
incq %rcx
jmp 0xa87f
movq 0x28(%rsp), %rax
incq %rax
addq 0x20(%rsp), %rsi
movq %rsi, 0x18(%rsp)
movq 0x8(%rsp), %r12
jmp 0xa799
xorl %r15d, %r15d
xorl %ebx, %ebx
cmpq $0x78, %rbx
je 0xaacb
leaq (%rsp,%rbx), %rdi
addq $0xa0, %rdi
callq 0x9fa4
addq $0x18, %rbx
jmp 0xa8b3
movups (%rbp), %xmm0
movups 0x10(%rbp), %xmm1
movaps %xmm0, 0x70(%rsp)
movaps %xmm1, 0x80(%rsp)
movq 0x20(%rbp), %rax
movq %rax, 0x90(%rsp)
movl $0x1, 0x70(%rsp)
xorps %xmm0, %xmm0
movaps %xmm0, 0x80(%rsp)
xorl %ebx, %ebx
cmpq $0x78, %rbx
je 0xa933
leaq (%rsp,%rbx), %rdi
addq $0xa0, %rdi
xorps %xmm0, %xmm0
movups %xmm0, (%rdi)
andq $0x0, 0x10(%rdi)
movq %r13, %rsi
callq 0x925a
addq $0x18, %rbx
jmp 0xa909
leaq 0x1(%r13), %rsi
movl %r14d, %eax
movq %rax, 0x60(%rsp)
leaq 0x1(%r12), %rdi
xorl %r8d, %r8d
movq $0x0, 0x18(%rsp)
movq $0x0, 0x28(%rsp)
movl $0x0, 0x8(%rsp)
movq %rsi, 0x58(%rsp)
cmpq 0x60(%rsp), %r8
movq 0x30(%rsp), %rax
je 0xaaaa
movq %rdi, 0x40(%rsp)
movq %r8, 0x68(%rsp)
imulq %r13, %r8
addq %rax, %r8
movq %r8, 0x20(%rsp)
xorl %r14d, %r14d
leaq 0xa8(%rsp), %r12
pushq $-0x5
popq %rbx
testq %rbx, %rbx
je 0xaa4a
movl (%r12), %r13d
movq -0x8(%r12), %rbp
leal 0x5(%rbx), %r15d
movzbl %r15b, %r9d
movq %rbp, %rdi
movq 0x20(%rsp), %rsi
movq 0x18(%rsp), %rdx
movq 0x10(%rsp), %rcx
movq 0x38(%rsp), %r8
callq 0xaae0
andq $0x0, 0x148(%rsp,%rbx,8)
leaq (%rsp,%r14), %rsi
addq $0x120, %rsi            # imm = 0x120
andq $0x0, 0x50(%rsp)
leaq 0x50(%rsp), %rdi
movq %rbp, %rdx
movq %r13, %rcx
leaq 0x70(%rsp), %r8
callq 0x8cd8
movq 0x50(%rsp), %rdi
callq 0x2200
cmpq $-0x5, %rbx
sete %al
movq 0x148(%rsp,%rbx,8), %rcx
movq 0x28(%rsp), %rsi
cmpq %rsi, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %rsi
movq %rsi, 0x28(%rsp)
movl 0x8(%rsp), %eax
cmovnel %r15d, %eax
movl %eax, 0x8(%rsp)
incq %rbx
addq $0x18, %r12
addq $0x8, %r14
jmp 0xa99a
movq 0x58(%rsp), %rsi
movq %rsi, %rax
movq 0x68(%rsp), %r8
imulq %r8, %rax
movq 0x48(%rsp), %rcx
movl 0x8(%rsp), %edx
movb %dl, (%rcx,%rax)
movl %edx, %eax
imulq $0x18, %rax, %rax
addq %rsp, %rax
addq $0xa0, %rax
xorl %ecx, %ecx
movq 0x10(%rsp), %r13
movq 0x40(%rsp), %rdi
cmpq %rcx, %r13
je 0xaa95
movq (%rax), %rdx
movb (%rdx,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
jmp 0xaa82
incq %r8
addq %rsi, %rdi
movq 0x20(%rsp), %rax
movq %rax, 0x18(%rsp)
jmp 0xa966
xorl %ebx, %ebx
cmpq $0x78, %rbx
je 0xaac8
leaq (%rsp,%rbx), %rdi
addq $0xa0, %rdi
callq 0x9fa4
addq $0x18, %rbx
jmp 0xaaac
xorl %r15d, %r15d
movl %r15d, %eax
addq $0x148, %rsp            # imm = 0x148
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq