// File: /workspace/github_cpp_makefile_star2_O1/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
movq %r9, %r15
movl %ecx, %ebp
movq %rsi, 0x10(%rsp)
movq %rdi, %r13
movl (%r8), %ecx
movl 0x4(%r8), %eax
xorl %edi, %edi
movl $0x0, %r8d
cmpq $0x6, %rcx
ja 0x71e70
leaq 0x18010(%rip), %rsi     # 0x89e7c
movl (%rsi,%rcx,4), %r8d
imull %eax, %r8d
movl 0x38(%r15), %esi
cmpl $0x8, %eax
movl %esi, %eax
cmovbl %edi, %eax
cmpl $0x3, %ecx
cmovel %edi, %eax
cmpl %edi, 0x34(%r15)
cmovel %esi, %eax
testl %r8d, %r8d
je 0x71f05
imull %r8d, %edx
addl $0x7, %edx
movl %edx, 0x18(%rsp)
movl %edx, %r12d
shrl $0x3, %r12d
addl $0x7, %r8d
shrl $0x3, %r8d
cmpl $0x4, %eax
movq %r8, (%rsp)
ja 0x71f0f
testl %ebp, %ebp
movq 0x10(%rsp), %rcx
je 0x72593
movq %r13, %rbx
leaq 0x1(%r12), %r13
movl %ebp, %r15d
incq %rbx
xorl %edx, %edx
movzbl %al, %ebp
movq %rcx, %r14
movb %bpl, -0x1(%rbx)
movq %rbx, %rdi
movq %rcx, %rsi
movq %r12, %rcx
movl %ebp, %r9d
callq 0x725a7
movq (%rsp), %r8
addq %r13, %rbx
leaq (%r14,%r12), %rcx
movq %r14, %rdx
decq %r15
jne 0x71ed5
jmp 0x72593
movl $0x1f, %eax
jmp 0x72595
addl $-0x5, %eax
cmpl $0x3, %eax
ja 0x720a1
leaq 0x17646(%rip), %rcx     # 0x89568
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0xc0(%rsp)
testq %rax, %rax
je 0x72097
movl $0x1, %ecx
movq %rcx, %r14
cmpq $0x5, %rcx
je 0x7221f
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0xc0(%rsp,%r14,8)
leaq 0x1(%r14), %rcx
testq %rax, %rax
jne 0x71f49
jmp 0x72588
movups (%r15), %xmm0
movups 0x10(%r15), %xmm1
movups 0x20(%r15), %xmm2
movaps %xmm0, 0xc0(%rsp)
movaps %xmm2, 0xe0(%rsp)
movaps %xmm1, 0xd0(%rsp)
movl $0x1, 0xc0(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0xd8(%rsp)
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0x90(%rsp)
testq %rax, %rax
je 0x72097
movl $0x1, %ecx
movq %rcx, %r14
cmpq $0x5, %rcx
je 0x720ab
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0x90(%rsp,%r14,8)
leaq 0x1(%r14), %rcx
testq %rax, %rax
jne 0x71fce
jmp 0x72588
testl %ebp, %ebp
movq 0x10(%rsp), %rax
je 0x72593
movq %r13, %rbx
leaq 0x1(%r12), %rcx
movq %rcx, 0x18(%rsp)
movl %ebp, %r13d
incq %rbx
xorl %ebp, %ebp
xorl %edx, %edx
movq %rax, %r14
movq 0x40(%r15), %rax
movzbl (%rax,%rbp), %r9d
movb %r9b, -0x1(%rbx)
movq %rbx, %rdi
movq %r14, %rsi
movq %r12, %rcx
callq 0x725a7
movq (%rsp), %r8
incq %rbp
addq 0x18(%rsp), %rbx
leaq (%r14,%r12), %rax
movq %r14, %rdx
cmpq %rbp, %r13
jne 0x7201d
jmp 0x72593
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0x60(%rsp)
testq %rax, %rax
je 0x72097
movl $0x1, %ecx
movq %rcx, %r14
cmpq $0x5, %rcx
je 0x7239d
movq %r12, %rdi
callq 0x3a5a0
movq %rax, 0x60(%rsp,%r14,8)
leaq 0x1(%r14), %rcx
testq %rax, %rax
jne 0x7206f
jmp 0x72588
movl $0x53, %eax
jmp 0x72595
movl $0x58, %eax
jmp 0x72595
movq %r14, 0x58(%rsp)
movq %r13, 0x20(%rsp)
testl %ebp, %ebp
movq (%rsp), %r8
movq 0x10(%rsp), %rcx
je 0x721fd
leaq 0x1(%r12), %rsi
movl %ebp, %eax
movq %rax, 0x30(%rsp)
movq 0x20(%rsp), %rax
leaq 0x1(%rax), %rdi
xorl %r9d, %r9d
movl $0x0, 0x28(%rsp)
xorl %ebx, %ebx
movq $0x0, 0x8(%rsp)
movq %rsi, 0x38(%rsp)
movq %rdi, 0x48(%rsp)
movq 0x8(%rsp), %r15
movq %r9, 0x40(%rsp)
imulq %r12, %r9
addq %rcx, %r9
movq %r9, 0x8(%rsp)
leaq 0x60(%rsp), %rbp
xorl %r13d, %r13d
movq 0x90(%rsp,%r13,8), %r14
movzbl %r13b, %r9d
movq %r14, %rdi
movq 0x8(%rsp), %rsi
movq %r15, %rdx
movq %r12, %rcx
callq 0x725a7
xorl %eax, %eax
movq %rax, (%rbp)
movq %rax, 0x50(%rsp)
movq 0xd8(%rsp), %rax
leaq 0x50(%rsp), %rdi
movq %rbp, %rsi
movq %r14, %rdx
movq %r12, %rcx
leaq 0xc0(%rsp), %r8
testq %rax, %rax
je 0x7216a
callq *%rax
jmp 0x7216f
callq 0x67c2b
movq 0x50(%rsp), %rdi
callq 0x3a530
testq %r13, %r13
je 0x72184
cmpq %rbx, (%rbp)
jae 0x7218d
movq (%rbp), %rbx
movl %r13d, 0x28(%rsp)
incq %r13
addq $0x8, %rbp
cmpq $0x5, %r13
movq (%rsp), %r8
jne 0x72119
movq 0x38(%rsp), %rsi
movq %rsi, %rax
movq 0x40(%rsp), %r9
imulq %r9, %rax
movq 0x20(%rsp), %rcx
movl 0x28(%rsp), %edx
movb %dl, (%rcx,%rax)
cmpl $0x8, 0x18(%rsp)
movq 0x48(%rsp), %rdi
jb 0x721e7
movl 0x28(%rsp), %eax
movq 0x90(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r12d
jne 0x721d9
incq %r9
addq %rsi, %rdi
cmpq 0x30(%rsp), %r9
movq 0x10(%rsp), %rcx
jne 0x720f6
xorl %ebx, %ebx
movq 0x58(%rsp), %r14
movq 0x90(%rsp,%rbx,8), %rdi
callq 0x3a530
incq %rbx
cmpq $0x5, %rbx
jne 0x72204
jmp 0x72588
movq %r14, 0x30(%rsp)
movq %r13, 0x20(%rsp)
testl %ebp, %ebp
movq (%rsp), %r8
movq 0x10(%rsp), %rcx
je 0x7237b
leaq 0x1(%r12), %rsi
movl %ebp, %eax
movq %rax, 0x38(%rsp)
movq 0x20(%rsp), %rax
leaq 0x1(%rax), %rdi
xorl %r9d, %r9d
movq $0x0, 0x8(%rsp)
xorl %r14d, %r14d
xorl %ebx, %ebx
movq %rsi, 0x40(%rsp)
movq %rdi, 0x28(%rsp)
movq 0x8(%rsp), %r13
movq %r9, 0x48(%rsp)
imulq %r12, %r9
addq %rcx, %r9
movq %r9, 0x8(%rsp)
xorl %r15d, %r15d
movq 0xc0(%rsp,%r15,8), %rbp
movzbl %r15b, %r9d
movq %rbp, %rdi
movq 0x8(%rsp), %rsi
movq %r13, %rdx
movq %r12, %rcx
callq 0x725a7
testq %r15, %r15
je 0x722d5
cmpl $0x8, 0x18(%rsp)
jb 0x722dc
xorl %ecx, %ecx
xorl %eax, %eax
movq (%rsp), %r8
movzbl (%rbp,%rcx), %edx
movl %edx, %esi
xorl $0xff, %esi
testb %dl, %dl
cmovnsl %edx, %esi
addq %rsi, %rax
incq %rcx
cmpl %ecx, %r12d
jne 0x722b6
jmp 0x722fc
cmpl $0x8, 0x18(%rsp)
jae 0x722e4
xorl %eax, %eax
movq (%rsp), %r8
jmp 0x722fc
xorl %ecx, %ecx
xorl %eax, %eax
movq (%rsp), %r8
movzbl (%rbp,%rcx), %edx
addq %rdx, %rax
incq %rcx
cmpl %ecx, %r12d
jne 0x722ec
testq %r15, %r15
sete %cl
cmpq %rbx, %rax
setb %dl
orb %cl, %dl
cmovneq %rax, %rbx
movzbl %r14b, %r14d
cmovnel %r15d, %r14d
incq %r15
cmpq $0x5, %r15
jne 0x72283
movq 0x40(%rsp), %rsi
movq %rsi, %rax
movq 0x48(%rsp), %r9
imulq %r9, %rax
movq 0x20(%rsp), %rcx
movb %r14b, (%rcx,%rax)
cmpl $0x8, 0x18(%rsp)
movq 0x28(%rsp), %rdi
jb 0x72365
movzbl %r14b, %eax
movq 0xc0(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r12d
jne 0x72357
incq %r9
addq %rsi, %rdi
cmpq 0x38(%rsp), %r9
movq 0x10(%rsp), %rcx
jne 0x72265
xorl %ebx, %ebx
movq 0x30(%rsp), %r14
movq 0xc0(%rsp,%rbx,8), %rdi
callq 0x3a530
incq %rbx
cmpq $0x5, %rbx
jne 0x72382
jmp 0x72588
movq %r14, 0x30(%rsp)
testl %ebp, %ebp
movq (%rsp), %r8
movq 0x10(%rsp), %rax
je 0x7256e
leaq 0x1(%r12), %rsi
movl %ebp, %ecx
movq %rcx, 0x38(%rsp)
leaq 0x1(%r13), %rdi
xorl %r9d, %r9d
xorl %ebx, %ebx
xorl %r14d, %r14d
xorl %r15d, %r15d
movq %r13, 0x20(%rsp)
movq %rsi, 0x40(%rsp)
movq %rdi, 0x28(%rsp)
movq %rbx, 0x8(%rsp)
movq %r9, 0x48(%rsp)
movq %r9, %rbx
imulq %r12, %rbx
addq %rax, %rbx
xorl %r13d, %r13d
movq 0x60(%rsp,%r13,8), %rbp
movzbl %r13b, %r9d
movq %rbp, %rdi
movq %rbx, %rsi
movq 0x8(%rsp), %rdx
movq %r12, %rcx
callq 0x725a7
movl $0x400, %edx            # imm = 0x400
leaq 0xc0(%rsp), %rdi
xorl %esi, %esi
callq 0x3a260
cmpl $0x8, 0x18(%rsp)
jb 0x72441
xorl %eax, %eax
movzbl (%rbp,%rax), %ecx
incl 0xc0(%rsp,%rcx,4)
incq %rax
cmpl %eax, %r12d
jne 0x7242d
incl 0xc0(%rsp,%r13,4)
xorl %edx, %edx
xorl %eax, %eax
movq (%rsp), %r8
movl 0xc0(%rsp,%rdx,4), %esi
testq %rsi, %rsi
je 0x724e1
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 0x72498
addq $0x8, %rcx
movq %rdi, %r9
shrq $0x8, %r9
cmpq $0xffff, %rdi           # imm = 0xFFFF
movq %r9, %rdi
ja 0x72481
cmpq $0x10, %rdi
jb 0x724b5
addq $0x4, %rcx
movq %rdi, %r9
shrq $0x4, %r9
cmpq $0xff, %rdi
movq %r9, %rdi
ja 0x7249e
cmpq $0x2, %rdi
jb 0x724cd
incq %rcx
movq %rdi, %r9
shrq %r9
cmpq $0x3, %rdi
movq %r9, %rdi
ja 0x724bb
movl $0x1, %edi
shll %cl, %edi
imulq %rsi, %rcx
subq %rdi, %rsi
leaq (%rcx,%rsi,2), %rcx
jmp 0x724e3
xorl %ecx, %ecx
addq %rcx, %rax
incq %rdx
cmpq $0x100, %rdx            # imm = 0x100
jne 0x72451
testq %r13, %r13
sete %cl
cmpq %r15, %rax
seta %dl
orb %cl, %dl
cmovneq %rax, %r15
cmovnel %r13d, %r14d
incq %r13
cmpq $0x5, %r13
jne 0x723f4
movq 0x40(%rsp), %rsi
movq %rsi, %rax
movq 0x48(%rsp), %r9
imulq %r9, %rax
movq 0x20(%rsp), %r13
movb %r14b, (%r13,%rax)
cmpl $0x8, 0x18(%rsp)
movq 0x28(%rsp), %rdi
jb 0x72558
movl %r14d, %eax
movq 0x60(%rsp,%rax,8), %rax
xorl %ecx, %ecx
movb (%rax,%rcx), %dl
movb %dl, (%rdi,%rcx)
incq %rcx
cmpl %ecx, %r12d
jne 0x7254a
incq %r9
addq %rsi, %rdi
cmpq 0x38(%rsp), %r9
movq 0x10(%rsp), %rax
jne 0x723d8
xorl %ebx, %ebx
movq 0x30(%rsp), %r14
movq 0x60(%rsp,%rbx,8), %rdi
callq 0x3a530
incq %rbx
cmpq $0x5, %rbx
jne 0x72575
movl $0x53, %eax
cmpq $0x5, %r14
jne 0x72595
xorl %eax, %eax
addq $0x4c8, %rsp            # imm = 0x4C8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq