// File: tomfunkhouser[P]gaps/pkgs/R2Shapes/R2Image.cpp
// Function: gaps::R2Image::WriteBMPFile(char const*) const
int R2Image::
WriteBMPFile(const char *filename) const
{
  // Check ncomponents
  assert(ncomponents == 3);

  // Open file
  FILE *fp = fopen(filename, "wb");
  if (!fp) {
    RNFail("Unable to open image file: %s", filename);
    return 0;
  }

  // Write file header 
  BMPBITMAPFILEHEADER bmfh;
  bmfh.bfType = BMP_BF_TYPE;
  bmfh.bfSize = BMP_BF_OFF_BITS + rowsize * height;
  bmfh.bfReserved1 = 0;
  bmfh.bfReserved2 = 0;
  bmfh.bfOffBits = BMP_BF_OFF_BITS;
  WordWriteLE(bmfh.bfType, fp);
  DWordWriteLE(bmfh.bfSize, fp);
  WordWriteLE(bmfh.bfReserved1, fp);
  WordWriteLE(bmfh.bfReserved2, fp);
  DWordWriteLE(bmfh.bfOffBits, fp);

  // Write info header 
  BMPBITMAPINFOHEADER bmih;
  bmih.biSize = BMP_BI_SIZE;
  bmih.biWidth = width;
  bmih.biHeight = height;
  bmih.biPlanes = 1;
  bmih.biBitCount = 8 * ncomponents;
  bmih.biCompression = BI_RGB;   
  bmih.biSizeImage = rowsize * (unsigned int) bmih.biHeight;  
  bmih.biXPelsPerMeter = 2925;
  bmih.biYPelsPerMeter = 2925;
  bmih.biClrUsed = 0;
  bmih.biClrImportant = 0;
  DWordWriteLE(bmih.biSize, fp);
  LongWriteLE(bmih.biWidth, fp);
  LongWriteLE(bmih.biHeight, fp);
  WordWriteLE(bmih.biPlanes, fp);
  WordWriteLE(bmih.biBitCount, fp);
  DWordWriteLE(bmih.biCompression, fp);
  DWordWriteLE(bmih.biSizeImage, fp);
  LongWriteLE(bmih.biXPelsPerMeter, fp);
  LongWriteLE(bmih.biYPelsPerMeter, fp);
  DWordWriteLE(bmih.biClrUsed, fp);
  DWordWriteLE(bmih.biClrImportant, fp);

  // Write image
  int pad = rowsize - width * ncomponents;
  for (int j = 0; j < height; j++) {
    // Write row of pixels BGR
    unsigned char *p = &pixels[j * rowsize];
    for (int i = 0; i < width; i++) {
      if (ncomponents == 1) {
        // Write gray value
        fputc(*(p++), fp);
      }
      else {
        // Write BRG, swapping blue and red in each pixel
        fputc(*(p+2), fp);
        fputc(*(p+1), fp);
        fputc(*(p+0), fp);
        p += 3;
      }
    }

    // Pad row
    for (int i = 0; i < pad; i++) fputc(0, fp);
  }
  
  // Close file
  fclose(fp);

  // Return success
  return 1;  
}

// Assembly:
subq $0x78, %rsp
movq %rdi, 0x68(%rsp)
movq %rsi, 0x60(%rsp)
movq 0x68(%rsp), %rax
movq %rax, (%rsp)
movq 0x60(%rsp), %rdi
leaq 0x6ab77(%rip), %rsi     # 0x133aba
callq 0xf5e0
movq %rax, 0x58(%rsp)
cmpq $0x0, 0x58(%rsp)
jne 0xc8f75
movq 0x60(%rsp), %rsi
leaq 0x6d52c(%rip), %rdi     # 0x13648d
movb $0x0, %al
callq 0xd4f30
movl $0x0, 0x74(%rsp)
jmp 0xc9227
movq (%rsp), %rcx
movw $0x4d42, 0x48(%rsp)     # imm = 0x4D42
movl 0xc(%rcx), %eax
imull 0x4(%rcx), %eax
addl $0x36, %eax
movl %eax, 0x4c(%rsp)
movw $0x0, 0x50(%rsp)
movw $0x0, 0x52(%rsp)
movl $0x36, 0x54(%rsp)
movw 0x48(%rsp), %ax
movq 0x58(%rsp), %rsi
movzwl %ax, %edi
callq 0xc9c20
movl 0x4c(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movw 0x50(%rsp), %ax
movq 0x58(%rsp), %rsi
movzwl %ax, %edi
callq 0xc9c20
movw 0x52(%rsp), %ax
movq 0x58(%rsp), %rsi
movzwl %ax, %edi
callq 0xc9c20
movl 0x54(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movq (%rsp), %rax
movl $0x28, 0x20(%rsp)
movl (%rax), %ecx
movl %ecx, 0x24(%rsp)
movl 0x4(%rax), %ecx
movl %ecx, 0x28(%rsp)
movw $0x1, 0x2c(%rsp)
movl 0x8(%rax), %ecx
shll $0x3, %ecx
movw %cx, 0x2e(%rsp)
movl $0x0, 0x30(%rsp)
movl 0xc(%rax), %eax
imull 0x28(%rsp), %eax
movl %eax, 0x34(%rsp)
movl $0xb6d, 0x38(%rsp)      # imm = 0xB6D
movl $0xb6d, 0x3c(%rsp)      # imm = 0xB6D
movl $0x0, 0x40(%rsp)
movl $0x0, 0x44(%rsp)
movl 0x20(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movl 0x24(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9d00
movl 0x28(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9d00
movw 0x2c(%rsp), %ax
movq 0x58(%rsp), %rsi
movzwl %ax, %edi
callq 0xc9c20
movw 0x2e(%rsp), %ax
movq 0x58(%rsp), %rsi
movzwl %ax, %edi
callq 0xc9c20
movl 0x30(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movl 0x34(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movl 0x38(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9d00
movl 0x3c(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9d00
movl 0x40(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movl 0x44(%rsp), %edi
movq 0x58(%rsp), %rsi
callq 0xc9c70
movq (%rsp), %rdx
movl 0xc(%rdx), %eax
movl (%rdx), %ecx
imull 0x8(%rdx), %ecx
subl %ecx, %eax
movl %eax, 0x1c(%rsp)
movl $0x0, 0x18(%rsp)
movq (%rsp), %rcx
movl 0x18(%rsp), %eax
cmpl 0x4(%rcx), %eax
jge 0xc9215
movq (%rsp), %rdx
movq 0x10(%rdx), %rax
movl 0x18(%rsp), %ecx
imull 0xc(%rdx), %ecx
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, 0x10(%rsp)
movl $0x0, 0xc(%rsp)
movq (%rsp), %rcx
movl 0xc(%rsp), %eax
cmpl (%rcx), %eax
jge 0xc91d8
movq (%rsp), %rax
cmpl $0x1, 0x8(%rax)
jne 0xc9180
movq 0x10(%rsp), %rax
movq %rax, %rcx
addq $0x1, %rcx
movq %rcx, 0x10(%rsp)
movzbl (%rax), %edi
movq 0x58(%rsp), %rsi
callq 0xf660
jmp 0xc91c6
movq 0x10(%rsp), %rax
movzbl 0x2(%rax), %edi
movq 0x58(%rsp), %rsi
callq 0xf660
movq 0x10(%rsp), %rax
movzbl 0x1(%rax), %edi
movq 0x58(%rsp), %rsi
callq 0xf660
movq 0x10(%rsp), %rax
movzbl (%rax), %edi
movq 0x58(%rsp), %rsi
callq 0xf660
movq 0x10(%rsp), %rax
addq $0x3, %rax
movq %rax, 0x10(%rsp)
jmp 0xc91c8
movl 0xc(%rsp), %eax
addl $0x1, %eax
movl %eax, 0xc(%rsp)
jmp 0xc9146
movl $0x0, 0x8(%rsp)
movl 0x8(%rsp), %eax
cmpl 0x1c(%rsp), %eax
jge 0xc9203
movq 0x58(%rsp), %rsi
xorl %edi, %edi
callq 0xf660
movl 0x8(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x8(%rsp)
jmp 0xc91e0
jmp 0xc9205
movl 0x18(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x18(%rsp)
jmp 0xc9112
movq 0x58(%rsp), %rdi
callq 0xf4b0
movl $0x1, 0x74(%rsp)
movl 0x74(%rsp), %eax
addq $0x78, %rsp
retq