// File: jpbalarini[P]otsus/./framework/CImage.cpp
// Function: CImage::load_PNG(char*)
void CImage::load_PNG(char *filename) {
  png_structp png_ptr;
  png_infop info_ptr;
  png_bytep * row_pointers;
  const unsigned PNG_SIG_LEN = 4;

  png_byte header[8];    // 8 is the maximum size that can be checked
  size_t dummy;
  
  /* open file and test for it being a png */
  FILE *fp = fopen(filename, "rb");
  if (!fp) {
    PRINT_ERROR("error opening PNG file %s!\n", filename);
    exit(-1);
  }

  dummy = fread(header, 1, PNG_SIG_LEN, fp);
  dummy = dummy; // To prevent the warning
  if (png_sig_cmp(header, 0, PNG_SIG_LEN)) {
    PRINT_ERROR("file %s is not recognized as a PNG file!\n", filename);
    exit(-1);
  }

  /* initialize stuff */
  png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if (!png_ptr) {
    PRINT_ERROR("png_create_read_struct failed\n");
    exit(-1);
  }

  info_ptr = png_create_info_struct(png_ptr);
  if (!info_ptr) {
    PRINT_ERROR("png_create_info_struct failed\n");
    exit(-1);
  }

  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("Error during setjmp\n");
    exit(-1);
  }

  png_init_io(png_ptr, fp);
  png_set_sig_bytes(png_ptr, PNG_SIG_LEN);

  png_read_info(png_ptr, info_ptr);
  
  //png_get_IHDR(png_ptr, info_ptr, &this->Nx, &this->Ny, &this->bits,
  //    color_type, NULL, NULL, NULL);

  this->Nx = png_get_image_width(png_ptr, info_ptr);
  this->Ny = png_get_image_height(png_ptr, info_ptr);
  //color_type = png_get_color_type(png_ptr, info_ptr);
  this->bits = png_get_bit_depth(png_ptr, info_ptr);

  png_set_interlace_handling(png_ptr);
  png_read_update_info(png_ptr, info_ptr);

  /* read file */
  if (setjmp(png_jmpbuf(png_ptr))) {
    PRINT_ERROR("Error during read_image\n");
    exit(-1);
  }

  int bytes_per_row = png_get_rowbytes(png_ptr, info_ptr);  
  png_byte *png_buffer = new png_byte[this->Ny * bytes_per_row];
  
  row_pointers = (png_bytep*)png_malloc(png_ptr, this->Ny * sizeof(png_bytep));
  for (int y = 0; y < this->Ny; y++)
    row_pointers[y] = &png_buffer[y * bytes_per_row];  

  png_read_image(png_ptr, row_pointers);
  int num_channels = png_get_channels(png_ptr, info_ptr);
  fclose(fp);
  
  // Create data channels
  create_channels(num_channels, Nx, Ny);  

  switch (this->bits) {
    case 8:
      for (int ch = 0; ch < num_channels; ch++) {
        float *m = this->get_channel(ch);

        for (int y = 0; y < this->Ny; y++) {
          for (int x = 0; x < this->Nx; x++) {
            int pos = x * num_channels  + ch;
            m[this->Nx * y + x] = row_pointers[y][pos];
          }
        }
      }
      break;
    case 16:
      for (int ch = 0; ch < num_channels; ch++) {
        float *m = this->get_channel(ch);

        for (int y = 0; y < this->Ny; y++) {
          for (int x = 0; x < this->Nx; x++) {
            int pos = (num_channels * x + ch) * 2;
            m[this->Nx * y + x] = 256 * row_pointers[y][pos] + row_pointers[y][pos + 1];
          }
        }
      }
      break;
  }

  // Free memory
  free(row_pointers);
  delete[] png_buffer;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xb0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0xa0(%rbp)
movl $0x4, -0x2c(%rbp)
movq -0x10(%rbp), %rdi
leaq 0x62a2(%rip), %rsi      # 0xd152
callq 0x33c0
movq %rax, -0x48(%rbp)
cmpq $0x0, -0x48(%rbp)
jne 0x6f0a
movq 0xc0f1(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x61f8(%rip), %rsi      # 0xd0c9
movl $0x124, %edx            # imm = 0x124
leaq 0x63ed(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xc0cd(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
movq -0x10(%rbp), %rdx
leaq 0x6568(%rip), %rsi      # 0xd461
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
leaq -0x34(%rbp), %rdi
movq -0x48(%rbp), %rcx
movl $0x1, %esi
movl $0x4, %edx
callq 0x34c0
movq %rax, -0x40(%rbp)
movq -0x40(%rbp), %rax
movq %rax, -0x40(%rbp)
leaq -0x34(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x4, %edx
callq 0x3220
cmpl $0x0, %eax
je 0x6f8e
movq 0xc06d(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x6174(%rip), %rsi      # 0xd0c9
movl $0x12b, %edx            # imm = 0x12B
leaq 0x6369(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xc049(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
movq -0x10(%rbp), %rdx
leaq 0x6500(%rip), %rsi      # 0xd47d
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
leaq 0x6512(%rip), %rdi      # 0xd4a7
xorl %eax, %eax
movl %eax, %ecx
movq %rcx, %rsi
movq %rcx, %rdx
callq 0x3080
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
jne 0x6ff5
movq 0xc002(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x6109(%rip), %rsi      # 0xd0c9
movl $0x133, %edx            # imm = 0x133
leaq 0x62fe(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xbfde(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x64ca(%rip), %rsi      # 0xd4ae
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
movq -0x18(%rbp), %rdi
callq 0x3550
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x704f
movq 0xbfa8(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x60af(%rip), %rsi      # 0xd0c9
movl $0x139, %edx            # imm = 0x139
leaq 0x62a4(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xbf84(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x648f(%rip), %rsi      # 0xd4cd
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
movq -0x18(%rbp), %rdi
movq 0xbf2e(%rip), %rsi      # 0x12f88
movl $0xc8, %edx
callq 0x3350
movq %rax, %rdi
callq 0x3480
cmpl $0x0, %eax
je 0x70b7
movq 0xbf40(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x6047(%rip), %rsi      # 0xd0c9
movl $0x13e, %edx            # imm = 0x13E
leaq 0x623c(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xbf1c(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x6446(%rip), %rsi      # 0xd4ec
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
movq -0x18(%rbp), %rdi
movq -0x48(%rbp), %rsi
callq 0x35b0
movq -0x18(%rbp), %rdi
movl $0x4, %esi
callq 0x30f0
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x3280
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x3210
movl %eax, %ecx
movq -0xa0(%rbp), %rax
movl %ecx, (%rax)
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x35f0
movl %eax, %ecx
movq -0xa0(%rbp), %rax
movl %ecx, 0x4(%rax)
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x3040
movb %al, %cl
movq -0xa0(%rbp), %rax
movzbl %cl, %ecx
movl %ecx, 0x8(%rax)
movq -0x18(%rbp), %rdi
callq 0x3540
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x3060
movq -0x18(%rbp), %rdi
movq 0xbe3b(%rip), %rsi      # 0x12f88
movl $0xc8, %edx
callq 0x3350
movq %rax, %rdi
callq 0x3480
cmpl $0x0, %eax
je 0x71aa
movq 0xbe4d(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x5f54(%rip), %rsi      # 0xd0c9
movl $0x154, %edx            # imm = 0x154
leaq 0x6149(%rip), %rcx      # 0xd2ca
movb $0x0, %al
callq 0x3470
movq 0xbe29(%rip), %rax      # 0x12fb8
movq (%rax), %rdi
leaq 0x6368(%rip), %rsi      # 0xd501
movb $0x0, %al
callq 0x3470
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x33e0
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x30c0
movq %rax, %rcx
movq -0xa0(%rbp), %rax
movl %ecx, -0x4c(%rbp)
movl 0x4(%rax), %eax
imull -0x4c(%rbp), %eax
movslq %eax, %rdi
callq 0x3030
movq %rax, %rcx
movq -0xa0(%rbp), %rax
movq %rcx, -0x58(%rbp)
movq -0x18(%rbp), %rdi
movslq 0x4(%rax), %rsi
shlq $0x3, %rsi
callq 0x3520
movq %rax, -0x28(%rbp)
movl $0x0, -0x5c(%rbp)
movq -0xa0(%rbp), %rcx
movl -0x5c(%rbp), %eax
cmpl 0x4(%rcx), %eax
jge 0x7233
movq -0x58(%rbp), %rdx
movl -0x5c(%rbp), %eax
imull -0x4c(%rbp), %eax
cltq
addq %rax, %rdx
movq -0x28(%rbp), %rax
movslq -0x5c(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x5c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x5c(%rbp)
jmp 0x71fd
movq -0x18(%rbp), %rdi
movq -0x28(%rbp), %rsi
callq 0x3130
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x35c0
movzbl %al, %eax
movl %eax, -0x60(%rbp)
movq -0x48(%rbp), %rdi
callq 0x32e0
movq -0xa0(%rbp), %rdi
movl -0x60(%rbp), %esi
movl (%rdi), %edx
movl 0x4(%rdi), %ecx
callq 0x6740
movq -0xa0(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0xa4(%rbp)
subl $0x8, %eax
je 0x729b
jmp 0x7287
movl -0xa4(%rbp), %eax
subl $0x10, %eax
je 0x7361
jmp 0x7481
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x60(%rbp), %eax
jge 0x735c
movq -0xa0(%rbp), %rdi
movl -0x64(%rbp), %esi
callq 0x81e0
movq %rax, -0x70(%rbp)
movl $0x0, -0x74(%rbp)
movq -0xa0(%rbp), %rcx
movl -0x74(%rbp), %eax
cmpl 0x4(%rcx), %eax
jge 0x734c
movl $0x0, -0x78(%rbp)
movq -0xa0(%rbp), %rcx
movl -0x78(%rbp), %eax
cmpl (%rcx), %eax
jge 0x733c
movq -0xa0(%rbp), %rcx
movl -0x78(%rbp), %eax
movl -0x60(%rbp), %edx
imull %edx, %eax
movl -0x64(%rbp), %edx
addl %edx, %eax
movl %eax, -0x7c(%rbp)
movq -0x28(%rbp), %rax
movslq -0x74(%rbp), %rdx
movq (%rax,%rdx,8), %rax
movslq -0x7c(%rbp), %rdx
movzbl (%rax,%rdx), %eax
cvtsi2ss %eax, %xmm0
movq -0x70(%rbp), %rax
movl (%rcx), %ecx
imull -0x74(%rbp), %ecx
addl -0x78(%rbp), %ecx
movslq %ecx, %rcx
movss %xmm0, (%rax,%rcx,4)
movl -0x78(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x78(%rbp)
jmp 0x72de
jmp 0x733e
movl -0x74(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x74(%rbp)
jmp 0x72c8
jmp 0x734e
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x72a2
jmp 0x7481
movl $0x0, -0x80(%rbp)
movl -0x80(%rbp), %eax
cmpl -0x60(%rbp), %eax
jge 0x747f
movq -0xa0(%rbp), %rdi
movl -0x80(%rbp), %esi
callq 0x81e0
movq %rax, -0x88(%rbp)
movl $0x0, -0x8c(%rbp)
movq -0xa0(%rbp), %rcx
movl -0x8c(%rbp), %eax
cmpl 0x4(%rcx), %eax
jge 0x746f
movl $0x0, -0x90(%rbp)
movq -0xa0(%rbp), %rcx
movl -0x90(%rbp), %eax
cmpl (%rcx), %eax
jge 0x7459
movq -0xa0(%rbp), %rcx
movl -0x60(%rbp), %eax
imull -0x90(%rbp), %eax
addl -0x80(%rbp), %eax
shll %eax
movl %eax, -0x94(%rbp)
movq -0x28(%rbp), %rax
movslq -0x8c(%rbp), %rdx
movq (%rax,%rdx,8), %rax
movslq -0x94(%rbp), %rdx
movzbl (%rax,%rdx), %eax
shll $0x8, %eax
movq -0x28(%rbp), %rdx
movslq -0x8c(%rbp), %rsi
movq (%rdx,%rsi,8), %rdx
movl -0x94(%rbp), %esi
addl $0x1, %esi
movslq %esi, %rsi
movzbl (%rdx,%rsi), %edx
addl %edx, %eax
cvtsi2ss %eax, %xmm0
movq -0x88(%rbp), %rax
movl (%rcx), %ecx
imull -0x8c(%rbp), %ecx
addl -0x90(%rbp), %ecx
movslq %ecx, %rcx
movss %xmm0, (%rax,%rcx,4)
movl -0x90(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x90(%rbp)
jmp 0x73b4
jmp 0x745b
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x7394
jmp 0x7471
movl -0x80(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x80(%rbp)
jmp 0x7368
jmp 0x7481
movq -0x28(%rbp), %rdi
callq 0x33d0
movq -0x58(%rbp), %rax
movq %rax, -0xb0(%rbp)
cmpq $0x0, %rax
je 0x74a7
movq -0xb0(%rbp), %rdi
callq 0x3440
addq $0xb0, %rsp
popq %rbp
retq