// File: Lut99[P]RayTracer/src/lib/LodePNG.cpp
// Function: lodepng_convert(unsigned char*, unsigned char const*, LodePNGColorMode const*, LodePNGColorMode const*, unsigned int, unsigned int)
unsigned lodepng_convert(unsigned char* out, const unsigned char* in,
                         const LodePNGColorMode* mode_out, const LodePNGColorMode* mode_in,
                         unsigned w, unsigned h) {
  size_t i;
  ColorTree tree;
  size_t numpixels = (size_t)w * (size_t)h;
  unsigned error = 0;

  if(mode_in->colortype == LCT_PALETTE && !mode_in->palette) {
    return 107; /* error: must provide palette if input mode is palette */
  }

  if(lodepng_color_mode_equal(mode_out, mode_in)) {
    size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
    for(i = 0; i != numbytes; ++i) out[i] = in[i];
    return 0;
  }

  if(mode_out->colortype == LCT_PALETTE) {
    size_t palettesize = mode_out->palettesize;
    const unsigned char* palette = mode_out->palette;
    size_t palsize = (size_t)1u << mode_out->bitdepth;
    /*if the user specified output palette but did not give the values, assume
    they want the values of the input color type (assuming that one is palette).
    Note that we never create a new palette ourselves.*/
    if(palettesize == 0) {
      palettesize = mode_in->palettesize;
      palette = mode_in->palette;
      /*if the input was also palette with same bitdepth, then the color types are also
      equal, so copy literally. This to preserve the exact indices that were in the PNG
      even in case there are duplicate colors in the palette.*/
      if (mode_in->colortype == LCT_PALETTE && mode_in->bitdepth == mode_out->bitdepth) {
        size_t numbytes = lodepng_get_raw_size(w, h, mode_in);
        for(i = 0; i != numbytes; ++i) out[i] = in[i];
        return 0;
      }
    }
    if(palettesize < palsize) palsize = palettesize;
    color_tree_init(&tree);
    for(i = 0; i != palsize; ++i) {
      const unsigned char* p = &palette[i * 4];
      color_tree_add(&tree, p[0], p[1], p[2], p[3], (unsigned)i);
    }
  }

  if(mode_in->bitdepth == 16 && mode_out->bitdepth == 16) {
    for(i = 0; i != numpixels; ++i) {
      unsigned short r = 0, g = 0, b = 0, a = 0;
      getPixelColorRGBA16(&r, &g, &b, &a, in, i, mode_in);
      rgba16ToPixel(out, i, mode_out, r, g, b, a);
    }
  } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGBA) {
    getPixelColorsRGBA8(out, numpixels, in, mode_in);
  } else if(mode_out->bitdepth == 8 && mode_out->colortype == LCT_RGB) {
    getPixelColorsRGB8(out, numpixels, in, mode_in);
  } else {
    unsigned char r = 0, g = 0, b = 0, a = 0;
    for(i = 0; i != numpixels; ++i) {
      getPixelColorRGBA8(&r, &g, &b, &a, in, i, mode_in);
      error = rgba8ToPixel(out, i, mode_out, &tree, r, g, b, a);
      if (error) break;
    }
  }

  if(mode_out->colortype == LCT_PALETTE) {
    color_tree_cleanup(&tree);
  }

  return error;
}

// Assembly:
subq $0x128, %rsp            # imm = 0x128
movq %rdi, 0x118(%rsp)
movq %rsi, 0x110(%rsp)
movq %rdx, 0x108(%rsp)
movq %rcx, 0x100(%rsp)
movl %r8d, 0xfc(%rsp)
movl %r9d, 0xf8(%rsp)
movl 0xfc(%rsp), %eax
movl 0xf8(%rsp), %ecx
imulq %rcx, %rax
movq %rax, 0x60(%rsp)
movl $0x0, 0x5c(%rsp)
movq 0x100(%rsp), %rax
cmpl $0x3, (%rax)
jne 0x140c42
movq 0x100(%rsp), %rax
cmpq $0x0, 0x8(%rax)
jne 0x140c42
movl $0x6b, 0x124(%rsp)
jmp 0x14113f
movq 0x108(%rsp), %rdi
movq 0x100(%rsp), %rsi
callq 0x141150
cmpl $0x0, %eax
je 0x140ce7
movl 0xfc(%rsp), %edi
movl 0xf8(%rsp), %esi
movq 0x100(%rsp), %rdx
callq 0x13fd60
movq %rax, 0x50(%rsp)
movq $0x0, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
cmpq 0x50(%rsp), %rax
je 0x140cd7
movq 0x110(%rsp), %rax
movq 0xf0(%rsp), %rcx
movb (%rax,%rcx), %dl
movq 0x118(%rsp), %rax
movq 0xf0(%rsp), %rcx
movb %dl, (%rax,%rcx)
movq 0xf0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xf0(%rsp)
jmp 0x140c8c
movl $0x0, 0x124(%rsp)
jmp 0x14113f
movq 0x108(%rsp), %rax
cmpl $0x3, (%rax)
jne 0x140eca
movq 0x108(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x48(%rsp)
movq 0x108(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x40(%rsp)
movq 0x108(%rsp), %rax
movl 0x4(%rax), %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, 0x38(%rsp)
cmpq $0x0, 0x48(%rsp)
jne 0x140e18
movq 0x100(%rsp), %rax
movq 0x10(%rax), %rax
movq %rax, 0x48(%rsp)
movq 0x100(%rsp), %rax
movq 0x8(%rax), %rax
movq %rax, 0x40(%rsp)
movq 0x100(%rsp), %rax
cmpl $0x3, (%rax)
jne 0x140e16
movq 0x100(%rsp), %rax
movl 0x4(%rax), %eax
movq 0x108(%rsp), %rcx
cmpl 0x4(%rcx), %eax
jne 0x140e16
movl 0xfc(%rsp), %edi
movl 0xf8(%rsp), %esi
movq 0x100(%rsp), %rdx
callq 0x13fd60
movq %rax, 0x30(%rsp)
movq $0x0, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
cmpq 0x30(%rsp), %rax
je 0x140e06
movq 0x110(%rsp), %rax
movq 0xf0(%rsp), %rcx
movb (%rax,%rcx), %dl
movq 0x118(%rsp), %rax
movq 0xf0(%rsp), %rcx
movb %dl, (%rax,%rcx)
movq 0xf0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xf0(%rsp)
jmp 0x140dbb
movl $0x0, 0x124(%rsp)
jmp 0x14113f
jmp 0x140e18
movq 0x48(%rsp), %rax
cmpq 0x38(%rsp), %rax
jae 0x140e2e
movq 0x48(%rsp), %rax
movq %rax, 0x38(%rsp)
leaq 0x68(%rsp), %rdi
callq 0x1412b0
movq $0x0, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
cmpq 0x38(%rsp), %rax
je 0x140ec8
movq 0x40(%rsp), %rax
movq 0xf0(%rsp), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, 0x28(%rsp)
movq 0x28(%rsp), %rax
movb (%rax), %sil
movq 0x28(%rsp), %rax
movb 0x1(%rax), %dl
movq 0x28(%rsp), %rax
movb 0x2(%rax), %cl
movq 0x28(%rsp), %rax
movb 0x3(%rax), %al
movq 0xf0(%rsp), %rdi
movl %edi, %r9d
leaq 0x68(%rsp), %rdi
movzbl %sil, %esi
movzbl %dl, %edx
movzbl %cl, %ecx
movzbl %al, %r8d
callq 0x141300
movq 0xf0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xf0(%rsp)
jmp 0x140e44
jmp 0x140eca
movq 0x100(%rsp), %rax
cmpl $0x10, 0x4(%rax)
jne 0x140fbc
movq 0x108(%rsp), %rax
cmpl $0x10, 0x4(%rax)
jne 0x140fbc
movq $0x0, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
cmpq 0x60(%rsp), %rax
je 0x140fb7
movw $0x0, 0x26(%rsp)
movw $0x0, 0x24(%rsp)
movw $0x0, 0x22(%rsp)
movw $0x0, 0x20(%rsp)
movq 0x110(%rsp), %r8
movq 0xf0(%rsp), %r9
movq 0x100(%rsp), %rax
leaq 0x26(%rsp), %rdi
leaq 0x24(%rsp), %rsi
leaq 0x22(%rsp), %rdx
leaq 0x20(%rsp), %rcx
movq %rax, (%rsp)
callq 0x141400
movq 0x118(%rsp), %rdi
movq 0xf0(%rsp), %rsi
movq 0x108(%rsp), %rdx
movw 0x26(%rsp), %cx
movw 0x24(%rsp), %r8w
movw 0x22(%rsp), %ax
movzwl %cx, %ecx
movzwl %r8w, %r8d
movzwl %ax, %r9d
movzwl 0x20(%rsp), %eax
movl %eax, (%rsp)
callq 0x1417a0
movq 0xf0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xf0(%rsp)
jmp 0x140efa
jmp 0x14111d
movq 0x108(%rsp), %rax
cmpl $0x8, 0x4(%rax)
jne 0x140ffe
movq 0x108(%rsp), %rax
cmpl $0x6, (%rax)
jne 0x140ffe
movq 0x118(%rsp), %rdi
movq 0x60(%rsp), %rsi
movq 0x110(%rsp), %rdx
movq 0x100(%rsp), %rcx
callq 0x141ac0
jmp 0x14111b
movq 0x108(%rsp), %rax
cmpl $0x8, 0x4(%rax)
jne 0x141040
movq 0x108(%rsp), %rax
cmpl $0x2, (%rax)
jne 0x141040
movq 0x118(%rsp), %rdi
movq 0x60(%rsp), %rsi
movq 0x110(%rsp), %rdx
movq 0x100(%rsp), %rcx
callq 0x142350
jmp 0x141119
movb $0x0, 0x1f(%rsp)
movb $0x0, 0x1e(%rsp)
movb $0x0, 0x1d(%rsp)
movb $0x0, 0x1c(%rsp)
movq $0x0, 0xf0(%rsp)
movq 0xf0(%rsp), %rax
cmpq 0x60(%rsp), %rax
je 0x141117
movq 0x110(%rsp), %r8
movq 0xf0(%rsp), %r9
movq 0x100(%rsp), %rax
leaq 0x1f(%rsp), %rdi
leaq 0x1e(%rsp), %rsi
leaq 0x1d(%rsp), %rdx
leaq 0x1c(%rsp), %rcx
movq %rax, (%rsp)
callq 0x142880
movq 0x118(%rsp), %rdi
movq 0xf0(%rsp), %rsi
movq 0x108(%rsp), %rdx
movb 0x1f(%rsp), %r8b
movb 0x1e(%rsp), %r9b
movb 0x1d(%rsp), %al
leaq 0x68(%rsp), %rcx
movzbl %r8b, %r8d
movzbl %r9b, %r9d
movzbl %al, %eax
movl %eax, (%rsp)
movzbl 0x1c(%rsp), %eax
movl %eax, 0x8(%rsp)
callq 0x142e60
movl %eax, 0x5c(%rsp)
cmpl $0x0, 0x5c(%rsp)
je 0x1410fc
jmp 0x141117
jmp 0x1410fe
movq 0xf0(%rsp), %rax
addq $0x1, %rax
movq %rax, 0xf0(%rsp)
jmp 0x141060
jmp 0x141119
jmp 0x14111b
jmp 0x14111d
movq 0x108(%rsp), %rax
cmpl $0x3, (%rax)
jne 0x141134
leaq 0x68(%rsp), %rdi
callq 0x1432a0
movl 0x5c(%rsp), %eax
movl %eax, 0x124(%rsp)
movl 0x124(%rsp), %eax
addq $0x128, %rsp            # imm = 0x128
retq
nop