// File: mhe[P]raytracerframework_cpp/lodepng.cpp
// Function: filter(unsigned char*, unsigned char const*, unsigned int, unsigned int, LodePNG_InfoColor const*)
static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h, const LodePNG_InfoColor* info)
{
  /*
  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
  
  There is a nice heuristic described here: http://www.cs.toronto.edu/~cosmin/pngtech/optipng.html. It says:
   *  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.
  
  Here the above method is used mostly. Note though that it appears to be better to use the adaptive filtering on the plasma 8-bit palette example, but that image isn't the best reference for palette images in general.
  */
  
  unsigned bpp = LodePNG_InfoColor_getBpp(info);
  size_t linebytes = (w * bpp + 7) / 8; /*the width of a scanline in bytes, not including the filter type*/
  size_t bytewidth = (bpp + 7) / 8; /*bytewidth is used for filtering, is 1 when bpp < 8, number of bytes per pixel otherwise*/
  const unsigned char* prevline = 0;
  unsigned x, y;
  unsigned heuristic;
  unsigned error = 0;
  
  if(bpp == 0) return 31; /*invalid color type*/
  
  /*choose heuristic as described above*/
  if(info->colorType == 3 || info->bitDepth < 8) heuristic = 0;
  else heuristic = 1;
  
  if(heuristic == 0) /*None filtertype for everything*/
  {
    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(heuristic == 1) /*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 = 9949; break; }
    }
    
    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;
          for(x = 0; x < attempt[type].size; x+=3) sum[type] += attempt[type].data[x]; /*note that not all pixels are checked to speed this up while still having probably the best choice*/
        
          /*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]);
  }
  #if 0 /*deflate the scanline with a fixed tree after every filter attempt to see which one deflates best. This is slow, and _does not work as expected_: the heuristic gives smaller result!*/
  else if(heuristic == 2) /*adaptive filtering by using deflate*/
  {
    size_t size[5];
    ucvector attempt[5]; /*five filtering attempts, one for each filter type*/
    size_t smallest;
    unsigned type = 0, bestType = 0;
    unsigned char* dummy;
    LodeZlib_DeflateSettings deflatesettings = LodeZlib_defaultDeflateSettings;
    deflatesettings.btype = 1; /*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*/
    for(type = 0; type < 5; type++) { ucvector_init(&attempt[type]); ucvector_resize(&attempt[type], linebytes); }
    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);
        size[type] = 0; dummy = 0;
        LodePNG_compress(&dummy, &size[type], attempt[type].data, attempt[type].size, &deflatesettings);
        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].data[x];
    }
    for(type = 0; type < 5; type++) ucvector_cleanup(&attempt[type]);
  }
  #endif
  
  return error;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x130, %rsp            # imm = 0x130
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movl %ecx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x28(%rbp), %rdi
callq 0x26220
movl %eax, -0x2c(%rbp)
movl -0x1c(%rbp), %eax
imull -0x2c(%rbp), %eax
addl $0x7, %eax
shrl $0x3, %eax
movl %eax, %eax
movq %rax, -0x38(%rbp)
movl -0x2c(%rbp), %eax
addl $0x7, %eax
shrl $0x3, %eax
movl %eax, %eax
movq %rax, -0x40(%rbp)
movq $0x0, -0x48(%rbp)
movl $0x0, -0x58(%rbp)
cmpl $0x0, -0x2c(%rbp)
jne 0x30a4c
movl $0x1f, -0x4(%rbp)
jmp 0x30dde
movq -0x28(%rbp), %rax
cmpl $0x3, (%rax)
je 0x30a5f
movq -0x28(%rbp), %rax
cmpl $0x8, 0x4(%rax)
jae 0x30a68
movl $0x0, -0x54(%rbp)
jmp 0x30a6f
movl $0x1, -0x54(%rbp)
cmpl $0x0, -0x54(%rbp)
jne 0x30b04
movl $0x0, -0x50(%rbp)
movl -0x50(%rbp), %eax
cmpl -0x20(%rbp), %eax
jae 0x30aff
movq -0x38(%rbp), %rax
addq $0x1, %rax
movl -0x50(%rbp), %ecx
imulq %rcx, %rax
movq %rax, -0x60(%rbp)
movq -0x38(%rbp), %rax
movl -0x50(%rbp), %ecx
imulq %rcx, %rax
movq %rax, -0x68(%rbp)
movl $0x0, -0x6c(%rbp)
movq -0x10(%rbp), %rax
movq -0x60(%rbp), %rcx
movb $0x0, (%rax,%rcx)
movq -0x10(%rbp), %rdi
movq -0x60(%rbp), %rax
addq $0x1, %rax
addq %rax, %rdi
movq -0x18(%rbp), %rsi
addq -0x68(%rbp), %rsi
movq -0x48(%rbp), %rdx
movq -0x38(%rbp), %rcx
movq -0x40(%rbp), %r8
xorl %r9d, %r9d
callq 0x311c0
movq -0x18(%rbp), %rax
addq -0x68(%rbp), %rax
movq %rax, -0x48(%rbp)
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
jmp 0x30a80
jmp 0x30dd8
cmpl $0x1, -0x54(%rbp)
jne 0x30dd6
movq $0x0, -0x128(%rbp)
movl $0x0, -0x130(%rbp)
movl $0x0, -0x12c(%rbp)
cmpl $0x5, -0x12c(%rbp)
jae 0x30b60
movl -0x12c(%rbp), %eax
leaq -0x120(%rbp), %rdi
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x25960
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x30b2d
movl $0x0, -0x12c(%rbp)
cmpl $0x5, -0x12c(%rbp)
jae 0x30bb1
movl -0x12c(%rbp), %eax
leaq -0x120(%rbp), %rdi
imulq $0x18, %rax, %rax
addq %rax, %rdi
movq -0x38(%rbp), %rsi
callq 0x24470
cmpl $0x0, %eax
jne 0x30b9e
movl $0x26dd, -0x58(%rbp)    # imm = 0x26DD
jmp 0x30bb1
jmp 0x30ba0
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x30b6a
cmpl $0x0, -0x58(%rbp)
jne 0x30d97
movl $0x0, -0x50(%rbp)
movl -0x50(%rbp), %eax
cmpl -0x20(%rbp), %eax
jae 0x30d95
movl $0x0, -0x12c(%rbp)
cmpl $0x5, -0x12c(%rbp)
jae 0x30cfa
movl -0x12c(%rbp), %eax
movl %eax, %ecx
leaq -0x120(%rbp), %rax
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq (%rax), %rdi
movq -0x18(%rbp), %rsi
movl -0x50(%rbp), %eax
imulq -0x38(%rbp), %rax
addq %rax, %rsi
movq -0x48(%rbp), %rdx
movq -0x38(%rbp), %rcx
movq -0x40(%rbp), %r8
movl -0x12c(%rbp), %eax
movzbl %al, %r9d
callq 0x311c0
movl -0x12c(%rbp), %eax
movq $0x0, -0xa0(%rbp,%rax,8)
movl $0x0, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
movl -0x12c(%rbp), %ecx
movl %ecx, %edx
leaq -0x120(%rbp), %rcx
imulq $0x18, %rdx, %rdx
addq %rdx, %rcx
cmpq 0x8(%rcx), %rax
jae 0x30ca3
movl -0x12c(%rbp), %eax
movl %eax, %ecx
leaq -0x120(%rbp), %rax
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq (%rax), %rax
movl -0x4c(%rbp), %ecx
movzbl (%rax,%rcx), %eax
movl %eax, %ecx
movl -0x12c(%rbp), %eax
addq -0xa0(%rbp,%rax,8), %rcx
movq %rcx, -0xa0(%rbp,%rax,8)
movl -0x4c(%rbp), %eax
addl $0x3, %eax
movl %eax, -0x4c(%rbp)
jmp 0x30c41
cmpl $0x0, -0x12c(%rbp)
je 0x30cc3
movl -0x12c(%rbp), %eax
movq -0xa0(%rbp,%rax,8), %rax
cmpq -0x128(%rbp), %rax
jae 0x30ce4
movl -0x12c(%rbp), %eax
movl %eax, -0x130(%rbp)
movl -0x12c(%rbp), %eax
movq -0xa0(%rbp,%rax,8), %rax
movq %rax, -0x128(%rbp)
jmp 0x30ce6
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x30bd8
movq -0x18(%rbp), %rax
movl -0x50(%rbp), %ecx
imulq -0x38(%rbp), %rcx
addq %rcx, %rax
movq %rax, -0x48(%rbp)
movl -0x130(%rbp), %eax
movb %al, %dl
movq -0x10(%rbp), %rax
movl -0x50(%rbp), %ecx
movq -0x38(%rbp), %rsi
addq $0x1, %rsi
imulq %rsi, %rcx
movb %dl, (%rax,%rcx)
movl $0x0, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpq -0x38(%rbp), %rax
jae 0x30d85
movl -0x130(%rbp), %eax
movl %eax, %ecx
leaq -0x120(%rbp), %rax
imulq $0x18, %rcx, %rcx
addq %rcx, %rax
movq (%rax), %rax
movl -0x4c(%rbp), %ecx
movb (%rax,%rcx), %dl
movq -0x10(%rbp), %rax
movl -0x50(%rbp), %ecx
movq -0x38(%rbp), %rsi
addq $0x1, %rsi
imulq %rsi, %rcx
addq $0x1, %rcx
movl -0x4c(%rbp), %esi
addq %rsi, %rcx
movb %dl, (%rax,%rcx)
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x30d32
jmp 0x30d87
movl -0x50(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x50(%rbp)
jmp 0x30bc2
jmp 0x30d97
movl $0x0, -0x12c(%rbp)
cmpl $0x5, -0x12c(%rbp)
jae 0x30dd4
movl -0x12c(%rbp), %eax
leaq -0x120(%rbp), %rdi
imulq $0x18, %rax, %rax
addq %rax, %rdi
callq 0x25990
movl -0x12c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x12c(%rbp)
jmp 0x30da1
jmp 0x30dd6
jmp 0x30dd8
movl -0x58(%rbp), %eax
movl %eax, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x130, %rsp            # imm = 0x130
popq %rbp
retq
nopw (%rax,%rax)