// File: /workspace/github_cpp_makefile_star2_O3/Lut99[P]RayTracer/src/lib/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 + 7u) / 8u, 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 + 7u) / 8u;
  /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  size_t bytewidth = (bpp + 7u) / 8u;
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned error = 0;
  LodePNGFilterStrategy strategy = settings->filter_strategy;

  /*
  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_MINSUM and filter_palette_zero is true.

  If filter_palette_zero is true and filter_strategy is not LFS_MINSUM, the above heuristic is followed,
  but for "the other case", whatever strategy filter_strategy is set to instead of the minimum sum
  heuristic is used.
  */
  if(settings->filter_palette_zero &&
     (info->colortype == LCT_PALETTE || info->bitdepth < 8)) strategy = LFS_ZERO;

  if(bpp == 0) return 31; /*error: invalid color type*/

  if(strategy >= LFS_ZERO && strategy <= LFS_FOUR) {
    unsigned char type = (unsigned char)strategy;
    for(y = 0; y != h; ++y) {
      size_t outindex = (1 + linebytes) * y; /*the extra filterbyte added to each row*/
      size_t inindex = linebytes * y;
      out[outindex] = type; /*filter type byte*/
      filterScanline(&out[outindex + 1], &in[inindex], prevline, linebytes, bytewidth, type);
      prevline = &in[inindex];
    }
  } else if(strategy == LFS_MINSUM) {
    /*adaptive filtering*/
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest = 0;
    unsigned char type, bestType = 0;

    for(type = 0; type != 5; ++type) {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }

    if(!error) {
      for(y = 0; y != h; ++y) {
        /*try the 5 filter types*/
        for(type = 0; type != 5; ++type) {
          size_t sum = 0;
          filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);

          /*calculate the sum of the result*/
          if(type == 0) {
            for(x = 0; x != linebytes; ++x) sum += (unsigned char)(attempt[type][x]);
          } else {
            for(x = 0; x != linebytes; ++x) {
              /*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.*/
              unsigned char s = attempt[type][x];
              sum += s < 128 ? s : (255U - 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 < smallest) {
            bestType = type;
            smallest = sum;
          }
        }

        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][x];
      }
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  } else if(strategy == LFS_ENTROPY) {
    unsigned char* attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t bestSum = 0;
    unsigned type, bestType = 0;
    unsigned count[256];

    for(type = 0; type != 5; ++type) {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }

    for(y = 0; y != h; ++y) {
      /*try the 5 filter types*/
      for(type = 0; type != 5; ++type) {
        size_t sum = 0;
        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        for(x = 0; x != 256; ++x) count[x] = 0;
        for(x = 0; x != linebytes; ++x) ++count[attempt[type][x]];
        ++count[type]; /*the filter type itself is part of the scanline*/
        for(x = 0; x != 256; ++x) {
          sum += ilog2i(count[x]);
        }
        /*check if this is smallest sum (or if type == 0 it's the first case so always store the values)*/
        if(type == 0 || sum > bestSum) {
          bestType = type;
          bestSum = sum;
        }
      }

      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][x];
    }

    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  } else if(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 char 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 if(strategy == 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];
    unsigned char* 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) {
      attempt[type] = (unsigned char*)lodepng_malloc(linebytes);
      if(!attempt[type]) return 83; /*alloc fail*/
    }
    for(y = 0; y != h; ++y) /*try the 5 filter types*/ {
      for(type = 0; type != 5; ++type) {
        unsigned testsize = (unsigned)linebytes;
        /*if(testsize > 8) testsize /= 8;*/ /*it already works good enough by testing a part of the row*/

        filterScanline(attempt[type], &in[y * linebytes], prevline, linebytes, bytewidth, type);
        size[type] = 0;
        dummy = 0;
        zlib_compress(&dummy, &size[type], attempt[type], testsize, &zlibsettings);
        lodepng_free(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][x];
    }
    for(type = 0; type != 5; ++type) lodepng_free(attempt[type]);
  }
  else return 88; /* unknown filter strategy */

  return error;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x4c8, %rsp            # imm = 0x4C8
movl %ecx, %ebp
movq %rsi, 0x18(%rsp)
movq %rdi, %r12
movq 0x500(%rsp), %rbx
xorl %ecx, %ecx
cmpl $0x6, %r8d
ja 0x713c3
movl %r8d, %eax
leaq 0x17adc(%rip), %rcx     # 0x88e9c
movl (%rcx,%rax,4), %ecx
imull %r9d, %ecx
imull %ecx, %edx
addl $0x7, %edx
movl %edx, 0x10(%rsp)
movl %edx, %r14d
shrl $0x3, %r14d
leal 0x7(%rcx), %eax
shrl $0x3, %eax
movq %rax, 0x40(%rsp)
movl 0x38(%rbx), %eax
cmpl $0x0, 0x34(%rbx)
je 0x71408
cmpl $0x3, %r8d
sete %dl
cmpl $0x8, %r9d
setb %sil
orb %dl, %sil
je 0x71408
xorl %eax, %eax
testl %ecx, %ecx
jne 0x71411
jmp 0x71464
testl %ecx, %ecx
je 0x71464
cmpl $0x4, %eax
ja 0x7147b
testl %ebp, %ebp
je 0x71460
leaq 0x1(%r14), %rcx
movq %rcx, 0x10(%rsp)
movl %ebp, %r15d
incq %r12
movzbl %al, %ebp
xorl %edx, %edx
movq 0x40(%rsp), %rbx
movq 0x18(%rsp), %rax
movq %rax, %r13
movb %bpl, -0x1(%r12)
movq %r12, %rdi
movq %rax, %rsi
movq %r14, %rcx
movq %rbx, %r8
movl %ebp, %r9d
callq 0x71a5f
addq 0x10(%rsp), %r12
leaq (%r14,%r13), %rax
movq %r13, %rdx
decq %r15
jne 0x71433
xorl %eax, %eax
jmp 0x71469
movl $0x1f, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
addl $-0x5, %eax
cmpl $0x3, %eax
ja 0x71a55
leaq 0x170fa(%rip), %rcx     # 0x88588
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
movq %r12, 0x48(%rsp)
jmpq *%rax
xorl %ebx, %ebx
movq %r14, %rdi
callq 0x3a5b0
movq %rax, 0xc0(%rsp,%rbx,8)
testq %rax, %rax
je 0x71a4b
incq %rbx
cmpq $0x5, %rbx
jne 0x7149e
testl %ebp, %ebp
je 0x71609
leaq 0x1(%r14), %rsi
movl %ebp, %eax
movq %rax, 0x20(%rsp)
movq 0x48(%rsp), %rax
leaq 0x1(%rax), %rdi
movq 0x18(%rsp), %rax
xorl %r8d, %r8d
movq $0x0, 0x8(%rsp)
xorl %r15d, %r15d
xorl %r13d, %r13d
movq %rsi, 0x28(%rsp)
movq %rdi, 0x38(%rsp)
movq 0x8(%rsp), %rbp
movq %r8, 0x30(%rsp)
imulq %r14, %r8
addq %rax, %r8
movq %r8, 0x8(%rsp)
xorl %ebx, %ebx
movq 0xc0(%rsp,%rbx,8), %r12
movzbl %bl, %r9d
movq %r12, %rdi
movq 0x8(%rsp), %rsi
movq %rbp, %rdx
movq %r14, %rcx
movq 0x40(%rsp), %r8
callq 0x71a5f
testq %rbx, %rbx
je 0x71568
cmpl $0x8, 0x10(%rsp)
jb 0x7156f
xorl %ecx, %ecx
xorl %eax, %eax
movzbl (%r12,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
incq %rcx
cmpl %ecx, %r14d
jne 0x71549
jmp 0x71587
cmpl $0x8, 0x10(%rsp)
jae 0x71573
xorl %eax, %eax
jmp 0x71587
xorl %ecx, %ecx
xorl %eax, %eax
movzbl (%r12,%rcx), %edx
addq %rdx, %rax
incq %rcx
cmpl %ecx, %r14d
jne 0x71577
testq %rbx, %rbx
sete %cl
cmpq %r13, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %r13
movzbl %bl, %eax
movzbl %r15b, %r15d
cmovnel %eax, %r15d
incq %rbx
cmpq $0x5, %rbx
jne 0x71515
movq 0x28(%rsp), %rsi
movq %rsi, %rax
movq 0x30(%rsp), %r8
imulq %r8, %rax
movq 0x48(%rsp), %rcx
movb %r15b, (%rcx,%rax)
cmpl $0x8, 0x10(%rsp)
movq 0x38(%rsp), %rdi
jb 0x715f3
movzbl %r15b, %eax
movq 0xc0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r14d
jne 0x715e5
incq %r8
addq %rsi, %rdi
cmpq 0x20(%rsp), %r8
movq 0x18(%rsp), %rax
jne 0x714f8
xorl %ebx, %ebx
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x3a540
incq %rbx
cmpq $0x5, %rbx
jne 0x7160b
jmp 0x71460
movups (%rbx), %xmm0
movups 0x10(%rbx), %xmm1
movups 0x20(%rbx), %xmm2
movaps %xmm0, 0xc0(%rsp)
movaps %xmm2, 0xe0(%rsp)
movaps %xmm1, 0xd0(%rsp)
movl $0x1, 0xc0(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp)
xorl %ebx, %ebx
movq %r14, %rdi
callq 0x3a5b0
movq %rax, 0x90(%rsp,%rbx,8)
testq %rax, %rax
je 0x71a4b
incq %rbx
cmpq $0x5, %rbx
jne 0x71661
testl %ebp, %ebp
movq 0x18(%rsp), %rax
je 0x717cb
leaq 0x1(%r14), %rsi
movl %ebp, %ecx
movq %rcx, 0x58(%rsp)
leaq 0x1(%r12), %rdi
xorl %r8d, %r8d
xorl %r15d, %r15d
xorl %ebx, %ebx
movq $0x0, 0x8(%rsp)
movq %rsi, 0x20(%rsp)
movq %rdi, 0x30(%rsp)
movq 0x8(%rsp), %rcx
movq %rcx, 0x38(%rsp)
movq %r8, 0x28(%rsp)
imulq %r14, %r8
addq %rax, %r8
movq %r8, 0x8(%rsp)
xorl %ebp, %ebp
xorl %r13d, %r13d
movq 0x90(%rsp,%r13,8), %r12
movzbl %r13b, %r9d
movq %r12, %rdi
movq 0x8(%rsp), %rsi
movq 0x38(%rsp), %rdx
movq %r14, %rcx
movq 0x40(%rsp), %r8
callq 0x71a5f
leaq (%rsp,%rbp), %rsi
addq $0x60, %rsi
xorl %eax, %eax
movq %rax, 0x60(%rsp,%r13,8)
movq %rax, 0x50(%rsp)
movq 0xd8(%rsp), %rax
leaq 0x50(%rsp), %rdi
movq %r12, %rdx
movq %r14, %rcx
leaq 0xc0(%rsp), %r8
testq %rax, %rax
je 0x71739
callq *%rax
jmp 0x7173e
callq 0x67631
movq 0x50(%rsp), %rdi
callq 0x3a540
testq %r13, %r13
sete %al
movq 0x60(%rsp,%r13,8), %rcx
cmpq %rbx, %rcx
setb %dl
orb %al, %dl
cmovneq %rcx, %rbx
cmovnel %r13d, %r15d
incq %r13
addq $0x8, %rbp
cmpq $0x5, %r13
jne 0x716db
movq 0x20(%rsp), %rsi
movq %rsi, %rax
movq 0x28(%rsp), %r8
imulq %r8, %rax
movq 0x48(%rsp), %rcx
movb %r15b, (%rcx,%rax)
cmpl $0x8, 0x10(%rsp)
movq 0x30(%rsp), %rdi
jb 0x717b5
movl %r15d, %eax
movq 0x90(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r14d
jne 0x717a7
incq %r8
addq %rsi, %rdi
cmpq 0x58(%rsp), %r8
movq 0x18(%rsp), %rax
jne 0x716b6
xorl %ebx, %ebx
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x3a540
incq %rbx
cmpq $0x5, %rbx
jne 0x717cd
jmp 0x71460
testl %ebp, %ebp
movq 0x18(%rsp), %rax
je 0x71460
leaq 0x1(%r14), %rcx
movq %rcx, 0x10(%rsp)
movl %ebp, %ecx
movq %rcx, 0x8(%rsp)
incq %r12
xorl %r15d, %r15d
xorl %edx, %edx
movq 0x40(%rsp), %rbp
movq %rax, %r13
movq 0x40(%rbx), %rax
movzbl (%rax,%r15), %r9d
movb %r9b, -0x1(%r12)
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rcx
movq %rbp, %r8
callq 0x71a5f
incq %r15
addq 0x10(%rsp), %r12
leaq (%r14,%r13), %rax
movq %r13, %rdx
cmpq %r15, 0x8(%rsp)
jne 0x71812
jmp 0x71460
xorl %ebx, %ebx
movq %r14, %rdi
callq 0x3a5b0
movq %rax, 0x60(%rsp,%rbx,8)
testq %rax, %rax
je 0x71a4b
incq %rbx
cmpq $0x5, %rbx
jne 0x71851
testl %ebp, %ebp
movq 0x18(%rsp), %rax
je 0x71a31
leaq 0x1(%r14), %rsi
movl %ebp, %ecx
movq %rcx, 0x20(%rsp)
leaq 0x1(%r12), %rdi
xorl %r8d, %r8d
xorl %ebx, %ebx
xorl %ebp, %ebp
xorl %r15d, %r15d
movq %rsi, 0x28(%rsp)
movq %rdi, 0x38(%rsp)
movq %rbx, 0x8(%rsp)
movq %r8, 0x30(%rsp)
movq %r8, %rbx
imulq %r14, %rbx
addq %rax, %rbx
xorl %r13d, %r13d
movq 0x60(%rsp,%r13,8), %r12
movzbl %r13b, %r9d
movq %r12, %rdi
movq %rbx, %rsi
movq 0x8(%rsp), %rdx
movq %r14, %rcx
movq 0x40(%rsp), %r8
callq 0x71a5f
movl $0x400, %edx            # imm = 0x400
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x3a260
cmpl $0x8, 0x10(%rsp)
jb 0x7190a
xorl %eax, %eax
movzbl (%r12,%rax), %ecx
incl 0xc0(%rsp,%rcx,4)
incq %rax
cmpl %eax, %r14d
jne 0x718f6
incl 0xc0(%rsp,%r13,4)
xorl %edx, %edx
xorl %eax, %eax
movl 0xc0(%rsp,%rdx,4), %esi
testq %rsi, %rsi
je 0x719a6
movl %esi, %edi
shrl $0x10, %edi
xorl %ecx, %ecx
cmpl $0x10000, %esi          # imm = 0x10000
setae %cl
cmovbq %rsi, %rdi
shll $0x4, %ecx
cmpq $0x100, %rdi            # imm = 0x100
jb 0x7195d
addq $0x8, %rcx
movq %rdi, %r8
shrq $0x8, %r8
cmpq $0xffff, %rdi           # imm = 0xFFFF
movq %r8, %rdi
ja 0x71946
cmpq $0x10, %rdi
jb 0x7197a
addq $0x4, %rcx
movq %rdi, %r8
shrq $0x4, %r8
cmpq $0xff, %rdi
movq %r8, %rdi
ja 0x71963
cmpq $0x2, %rdi
jb 0x71992
incq %rcx
movq %rdi, %r8
shrq %r8
cmpq $0x3, %rdi
movq %r8, %rdi
ja 0x71980
movl $0x1, %edi
shll %cl, %edi
imulq %rsi, %rcx
subq %rdi, %rsi
leaq (%rcx,%rsi,2), %rcx
jmp 0x719a8
xorl %ecx, %ecx
addq %rcx, %rax
incq %rdx
cmpq $0x100, %rdx            # imm = 0x100
jne 0x71916
testq %r13, %r13
sete %cl
cmpq %r15, %rax
seta %dl
orb %cl, %dl
cmovneq %rax, %r15
cmovnel %r13d, %ebp
incq %r13
cmpq $0x5, %r13
jne 0x718b8
movq 0x28(%rsp), %rsi
movq %rsi, %rax
movq 0x30(%rsp), %r8
imulq %r8, %rax
movq 0x48(%rsp), %rcx
movb %bpl, (%rcx,%rax)
cmpl $0x8, 0x10(%rsp)
movq 0x38(%rsp), %rdi
jb 0x71a1b
movl %ebp, %eax
movq 0x60(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r14d
jne 0x71a0d
incq %r8
addq %rsi, %rdi
cmpq 0x20(%rsp), %r8
movq 0x18(%rsp), %rax
jne 0x7189c
xorl %ebx, %ebx
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x3a540
incq %rbx
cmpq $0x5, %rbx
jne 0x71a33
jmp 0x71460
movl $0x53, %eax
jmp 0x71469
movl $0x58, %eax
jmp 0x71469