// File: tomfunkhouser[P]gaps/pkgs/R2Shapes/R2Image.cpp
// Function: gaps::R2Image::ReadBMPFile(char const*)
int R2Image::
ReadBMPFile(const char *filename)
{
  // Open file
  FILE *fp = fopen(filename, "rb");
  if (!fp) {
    RNFail("Unable to open image file: %s", filename);
    return 0;
  }

  /* Read file header */
  BMPBITMAPFILEHEADER bmfh;
  bmfh.bfType = WordReadLE(fp);
  bmfh.bfSize = DWordReadLE(fp);
  bmfh.bfReserved1 = WordReadLE(fp);
  bmfh.bfReserved2 = WordReadLE(fp);
  bmfh.bfOffBits = DWordReadLE(fp);
  
  /* Check file header */
  // assert(bmfh.bfType == BMP_BF_TYPE);
  /* ignore bmfh.bfSize */
  /* ignore bmfh.bfReserved1 */
  /* ignore bmfh.bfReserved2 */
  // assert(bmfh.bfOffBits == BMP_BF_OFF_BITS);
  
  /* Read info header */
  BMPBITMAPINFOHEADER bmih;
  bmih.biSize = DWordReadLE(fp);
  bmih.biWidth = LongReadLE(fp);
  bmih.biHeight = LongReadLE(fp);
  bmih.biPlanes = WordReadLE(fp);
  bmih.biBitCount = WordReadLE(fp);
  bmih.biCompression = DWordReadLE(fp);
  bmih.biSizeImage = DWordReadLE(fp);
  bmih.biXPelsPerMeter = LongReadLE(fp);
  bmih.biYPelsPerMeter = LongReadLE(fp);
  bmih.biClrUsed = DWordReadLE(fp);
  bmih.biClrImportant = DWordReadLE(fp);

  // Check if unsupported file type
  // If so, just fill in with default
  if ((bmih.biSize != BMP_BI_SIZE) || (bmih.biPlanes > 1) ||
      (bmih.biBitCount != 24) || (bmih.biCompression != BI_RGB)) {
    RNFail("Unsupported BMP version\n");
    fclose(fp);
    return 0;
  }

  // Check info header 
  assert(bmih.biSize == BMP_BI_SIZE);
  assert(bmih.biWidth > 0);
  assert(bmih.biHeight > 0);
  assert(bmih.biPlanes == 1);
  assert(bmih.biCompression == BI_RGB);   /* RGB */
  int lineLength = bmih.biWidth * bmih.biBitCount / 8;
  if ((lineLength % 4) != 0) lineLength = (lineLength / 4 + 1) * 4;

  // Allocate buffer
  unsigned int buffer_size = lineLength * bmih.biHeight;
  unsigned char *buffer = new unsigned char [buffer_size];
  if (!buffer) {
    RNFail("Unable to allocate memory for BMP file");
    fclose(fp);
    return 0;
  }

  // Read buffer 
  fseek(fp, (long) bmfh.bfOffBits, SEEK_SET);
  if (fread(buffer, 1, buffer_size, fp) != buffer_size) {
    RNFail("Error while reading BMP file %s", filename);
    delete [] buffer;
    return 0;
  }

  // Assign width, height, and ncomponents
  width = bmih.biWidth;
  height = bmih.biHeight;
  ncomponents = (bmih.biBitCount <= 8) ? 1 : 3;
  rowsize = ncomponents * width;
  if ((rowsize % 4) != 0) rowsize = (rowsize / 4 + 1) * 4;

  // Allocate pixels
  int nbytes = rowsize * height;
  pixels = new unsigned char [nbytes];
  if (!pixels) {
    RNFail("Unable to allocate memory for BMP file");
    delete [] buffer;
    fclose(fp);
    return 0;
  }

  // Copy pixels from buffer
  for (int j = 0; j < height; j++) {
    unsigned char *p = &pixels[j * rowsize];
    unsigned char *b = &buffer[j * lineLength];
    for (int i = 0; i < width; i++) {
      if (bmih.biBitCount == 1) {
        // Binary (this is not right, should be index into color table)
        p[i] = (b[i/8]>>(7-(i%8)) & 0x1) ? 255 : 0;
      }
      else if (bmih.biBitCount == 8) {
        // 8-bit (this is not right, should be index into color table)
        p[i] = b[i];
      }
      else if (bmih.biBitCount == 24) {
        // RGB - swap blue and red in each pixel
        p[i*3+0] = b[i*3+2];
        p[i*3+1] = b[i*3+1];
        p[i*3+2] = b[i*3+0];
      }
    }
  }

  // Delete buffer
  delete [] buffer;

  // Close file
  fclose(fp);

  // Return success
  return 1;
}

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0xa8(%rsp)
movq %rsi, 0xa0(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x28(%rsp)
movq 0xa0(%rsp), %rdi
leaq 0x6cba6(%rip), %rsi     # 0x1335d9
callq 0xf5e0
movq %rax, 0x98(%rsp)
cmpq $0x0, 0x98(%rsp)
jne 0xc6a71
movq 0xa0(%rsp), %rsi
leaq 0x6fa33(%rip), %rdi     # 0x13648d
movb $0x0, %al
callq 0xd4f30
movl $0x0, 0xb4(%rsp)
jmp 0xc6fa0
movq 0x98(%rsp), %rdi
callq 0xc9b00
movw %ax, 0x88(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x8c(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b00
movw %ax, 0x90(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b00
movw %ax, 0x92(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x94(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x60(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9bb0
movl %eax, 0x64(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9bb0
movl %eax, 0x68(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b00
movw %ax, 0x6c(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b00
movw %ax, 0x6e(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x70(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x74(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9bb0
movl %eax, 0x78(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9bb0
movl %eax, 0x7c(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x80(%rsp)
movq 0x98(%rsp), %rdi
callq 0xc9b40
movl %eax, 0x84(%rsp)
cmpl $0x28, 0x60(%rsp)
jne 0xc6bc0
movzwl 0x6c(%rsp), %eax
cmpl $0x1, %eax
jg 0xc6bc0
movzwl 0x6e(%rsp), %eax
cmpl $0x18, %eax
jne 0xc6bc0
movl 0x70(%rsp), %eax
cmpq $0x0, %rax
je 0xc6beb
leaq 0x6f8e4(%rip), %rdi     # 0x1364ab
movb $0x0, %al
callq 0xd4f30
movq 0x98(%rsp), %rdi
callq 0xf4b0
movl $0x0, 0xb4(%rsp)
jmp 0xc6fa0
movl 0x64(%rsp), %eax
movzwl 0x6e(%rsp), %ecx
imull %ecx, %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
je 0xc6c2a
movl 0x5c(%rsp), %eax
movl $0x4, %ecx
cltd
idivl %ecx
addl $0x1, %eax
shll $0x2, %eax
movl %eax, 0x5c(%rsp)
movl 0x5c(%rsp), %eax
imull 0x68(%rsp), %eax
movl %eax, 0x58(%rsp)
movl 0x58(%rsp), %eax
movl %eax, %edi
callq 0xf030
movq %rax, 0x50(%rsp)
cmpq $0x0, 0x50(%rsp)
jne 0xc6c7a
leaq 0x6f86e(%rip), %rdi     # 0x1364c4
movb $0x0, %al
callq 0xd4f30
movq 0x98(%rsp), %rdi
callq 0xf4b0
movl $0x0, 0xb4(%rsp)
jmp 0xc6fa0
movq 0x98(%rsp), %rdi
movl 0x94(%rsp), %eax
movl %eax, %esi
xorl %edx, %edx
callq 0xf590
movq 0x50(%rsp), %rdi
movl 0x58(%rsp), %eax
movl %eax, %edx
movq 0x98(%rsp), %rcx
movl $0x1, %esi
callq 0xf780
movl 0x58(%rsp), %ecx
cmpq %rcx, %rax
je 0xc6cf8
movq 0xa0(%rsp), %rsi
leaq 0x6f824(%rip), %rdi     # 0x1364eb
movb $0x0, %al
callq 0xd4f30
movq 0x50(%rsp), %rax
movq %rax, 0x20(%rsp)
cmpq $0x0, %rax
je 0xc6ce8
movq 0x20(%rsp), %rdi
callq 0xf670
movl $0x0, 0xb4(%rsp)
jmp 0xc6fa0
movq 0x28(%rsp), %rax
movl 0x64(%rsp), %ecx
movl %ecx, (%rax)
movl 0x68(%rsp), %ecx
movl %ecx, 0x4(%rax)
movzwl 0x6e(%rsp), %esi
movl $0x3, %ecx
movl $0x1, %edx
cmpl $0x8, %esi
cmovlel %edx, %ecx
movl %ecx, 0x8(%rax)
movl 0x8(%rax), %ecx
imull (%rax), %ecx
movl %ecx, 0xc(%rax)
movl 0xc(%rax), %eax
movl $0x4, %ecx
cltd
idivl %ecx
cmpl $0x0, %edx
je 0xc6d5b
movq 0x28(%rsp), %rax
movl 0xc(%rax), %eax
movl $0x4, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq 0x28(%rsp), %rax
addl $0x1, %ecx
shll $0x2, %ecx
movl %ecx, 0xc(%rax)
movq 0x28(%rsp), %rcx
movl 0xc(%rcx), %eax
imull 0x4(%rcx), %eax
movl %eax, 0x4c(%rsp)
movslq 0x4c(%rsp), %rdi
callq 0xf030
movq %rax, %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x10(%rax)
cmpq $0x0, 0x10(%rax)
jne 0xc6dcd
leaq 0x6f735(%rip), %rdi     # 0x1364c4
movb $0x0, %al
callq 0xd4f30
movq 0x50(%rsp), %rax
movq %rax, 0x18(%rsp)
cmpq $0x0, %rax
je 0xc6db0
movq 0x18(%rsp), %rdi
callq 0xf670
movq 0x98(%rsp), %rdi
callq 0xf4b0
movl $0x0, 0xb4(%rsp)
jmp 0xc6fa0
movl $0x0, 0x48(%rsp)
movq 0x28(%rsp), %rcx
movl 0x48(%rsp), %eax
cmpl 0x4(%rcx), %eax
jge 0xc6f70
movq 0x28(%rsp), %rdx
movq 0x10(%rdx), %rax
movl 0x48(%rsp), %ecx
imull 0xc(%rdx), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, 0x40(%rsp)
movq 0x50(%rsp), %rax
movl 0x48(%rsp), %ecx
imull 0x5c(%rsp), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, 0x38(%rsp)
movl $0x0, 0x34(%rsp)
movq 0x28(%rsp), %rcx
movl 0x34(%rsp), %eax
cmpl (%rcx), %eax
jge 0xc6f5e
movzwl 0x6e(%rsp), %eax
cmpl $0x1, %eax
jne 0xc6ea6
movq 0x38(%rsp), %rax
movq %rax, 0x8(%rsp)
movl 0x34(%rsp), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq 0x8(%rsp), %rax
movslq %ecx, %rcx
movzbl (%rax,%rcx), %eax
movl %eax, 0x14(%rsp)
movl 0x34(%rsp), %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %edx, %eax
movl 0x14(%rsp), %edx
movl $0x7, %ecx
subl %eax, %ecx
sarl %cl, %edx
andl $0x1, %edx
xorl %eax, %eax
movl $0xff, %ecx
cmpl $0x0, %edx
cmovnel %ecx, %eax
movb %al, %dl
movq 0x40(%rsp), %rax
movslq 0x34(%rsp), %rcx
movb %dl, (%rax,%rcx)
jmp 0xc6f4c
movzwl 0x6e(%rsp), %eax
cmpl $0x8, %eax
jne 0xc6ecc
movq 0x38(%rsp), %rax
movslq 0x34(%rsp), %rcx
movb (%rax,%rcx), %dl
movq 0x40(%rsp), %rax
movslq 0x34(%rsp), %rcx
movb %dl, (%rax,%rcx)
jmp 0xc6f4a
movzwl 0x6e(%rsp), %eax
cmpl $0x18, %eax
jne 0xc6f48
movq 0x38(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x2, %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %dl
movq 0x40(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x0, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movq 0x38(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %dl
movq 0x40(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x1, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
movq 0x38(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x0, %ecx
movslq %ecx, %rcx
movb (%rax,%rcx), %dl
movq 0x40(%rsp), %rax
imull $0x3, 0x34(%rsp), %ecx
addl $0x2, %ecx
movslq %ecx, %rcx
movb %dl, (%rax,%rcx)
jmp 0xc6f4a
jmp 0xc6f4c
jmp 0xc6f4e
movl 0x34(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x34(%rsp)
jmp 0xc6e24
jmp 0xc6f60
movl 0x48(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x48(%rsp)
jmp 0xc6dd5
movq 0x50(%rsp), %rax
movq %rax, (%rsp)
cmpq $0x0, %rax
je 0xc6f88
movq (%rsp), %rdi
callq 0xf670
movq 0x98(%rsp), %rdi
callq 0xf4b0
movl $0x1, 0xb4(%rsp)
movl 0xb4(%rsp), %eax
addq $0xb8, %rsp
retq
nop