// File: timothyqiu[P]ssoaag/bitmap.cc
// Function: Bitmap::LoadUncompressedPixelData(BITMAPFILEHEADER const*, BITMAPINFOHEADER const*)
bool Bitmap::LoadUncompressedPixelData(BITMAPFILEHEADER const *bf,
                                       BITMAPINFOHEADER const *bi)
{
    assert(bi->biCompression == BI_RGB);

    /*
     * BI_RGB Pixel Format (R.G.B.A.X)
     *
     *        before V3  after V3
     * 16bpp  5.5.5.0.0  5.5.5.[0-1].[0-1]
     * 24bpp  8.8.8.0.0  8.8.8.0.0
     * 32bpp  8.8.8.0.0  8.8.8.[0-8].[0-8]
     */

    auto w = this->width_;
    auto h = this->height_;

    // width and height of BI_RGB bitmaps can be negative if flipped
    bool flip_x = (w != bi->biWidth );
    bool flip_y = (h != bi->biHeight);

    // for BI_RGB, color table is immediately after the info header
    auto *palette = reinterpret_cast<uint32_t const *>(
            reinterpret_cast<uint8_t const *>(bf) +
            sizeof(BITMAPFILEHEADER) +
            bi->biSize);

    // bitmap pixel data
    auto *raw = reinterpret_cast<uint8_t const *>(bf) + bf->bfOffBits;

    // echo row is rounded up to a multiple of 4 bytes by padding
    auto row_size = (bi->biBitCount * w + 31) / 32 * 4;

    // TODO: find a way to remove the switch..case
    switch (bi->biBitCount) {
    case 1: case 4: case 8: // these are all paletted image
        {
            auto ppb = 8 / bi->biBitCount;  // pixel per byte
            for (int y = 0; y < h; y++) {
                auto *line_r = raw + row_size * y;
                auto *line_w = this->pixels_ + w * (flip_y ? y : (h - 1 - y));
                for (int x = 0; x < w; x++) {
                    auto *pixel_r = line_r + x / ppb;
                    auto *pixel_w = line_w + (flip_x ? w - 1 - x : x);

                    // TODO: make the point clearer?
                    uint8_t mask = ((1 << bi->biBitCount) - 1);
                    auto shift = (ppb - 1 - (x % ppb)) * bi->biBitCount;
                    auto index = ((*pixel_r) >> shift) & mask;
                    auto *color = reinterpret_cast<uint8_t const *>(palette + index);

                    uint8_t b = color[0];
                    uint8_t g = color[1];
                    uint8_t r = color[2];

                    *pixel_w = Bitmap::MakeColor(0xFF, r, g, b);
                }
            }
        }
        break;

    case 16:    // 1555 for uncompressed. ignore any alpha channel(bit)
        for (int y = 0; y < h; y++) {
            auto *line_r = raw + row_size * y;
            auto *line_w = this->pixels_ + w * (flip_y ? y : (h - 1 - y));
            for (int x = 0; x < w; x++) {
                auto *pixel_r = line_r + x * bi->biBitCount / 8;
                auto *pixel_w = line_w + (flip_x ? w - 1 - x : x);

                auto *color = pixel_r;

                // TODO: fix the ugly code :(
                uint8_t b = (((color[0] & 0x1F) << 0)                         ) * 255 / 31;
                uint8_t g = (((color[1] & 0x03) << 3) | (color[0] >> 5 & 0x07)) * 255 / 31;
                uint8_t r = (                           (color[1] >> 2 & 0x1F)) * 255 / 31;

                *pixel_w = Bitmap::MakeColor(0xFF, r, g, b);
            }
        }
        break;

    case 24:
    case 32:    // alpha channel unsupported
        for (int y = 0; y < h; y++) {
            auto *line_r = raw + row_size * y;
            auto *line_w = this->pixels_ + w * (flip_y ? y : (h - 1 - y));
            for (int x = 0; x < w; x++) {
                auto *pixel_r = line_r + x * bi->biBitCount / 8;
                auto *pixel_w = line_w + (flip_x ? w - 1 - x : x);

                auto *color = pixel_r;

                uint8_t b = color[0];
                uint8_t g = color[1];
                uint8_t r = color[2];

                *pixel_w = Bitmap::MakeColor(0xFF, r, g, b);
            }
        }
        break;

    default:
        this->error_type_ = kUnsupportedBitmap;
        this->error_description_ = "Color depth not supported";
        return false;
    }

    return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x1a0, %rsp            # imm = 0x1A0
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x110(%rbp)
movq -0x20(%rbp), %rax
cmpl $0x0, 0x10(%rax)
jne 0x424e
jmp 0x426d
leaq 0x2194(%rip), %rdi      # 0x63e9
leaq 0x21a9(%rip), %rsi      # 0x6405
movl $0xf1, %edx
leaq 0x21a7(%rip), %rcx      # 0x640f
callq 0x2150
movq -0x110(%rbp), %rax
movl (%rax), %ecx
movl %ecx, -0x24(%rbp)
movl 0x4(%rax), %eax
movl %eax, -0x28(%rbp)
movl -0x24(%rbp), %eax
movq -0x20(%rbp), %rcx
movl 0x4(%rcx), %ecx
subl %ecx, %eax
setne -0x29(%rbp)
movl -0x28(%rbp), %eax
movq -0x20(%rbp), %rcx
movl 0x8(%rcx), %ecx
subl %ecx, %eax
setne -0x2a(%rbp)
movq -0x18(%rbp), %rax
movq -0x20(%rbp), %rcx
movl (%rcx), %ecx
leaq 0xe(%rax,%rcx), %rax
movq %rax, -0x38(%rbp)
movq -0x18(%rbp), %rax
movl 0xa(%rax), %ecx
addq %rcx, %rax
movq %rax, -0x40(%rbp)
movq -0x20(%rbp), %rax
movzwl 0xe(%rax), %ecx
movl -0x24(%rbp), %eax
imull %eax, %ecx
movl %ecx, %eax
addl $0x1f, %eax
addl $0x3e, %ecx
testl %eax, %eax
cmovsl %ecx, %eax
sarl $0x5, %eax
shll $0x2, %eax
movl %eax, -0x44(%rbp)
movq -0x20(%rbp), %rax
movzwl 0xe(%rax), %eax
movl %eax, -0x114(%rbp)
subl $0x1, %eax
je 0x4349
jmp 0x42f9
movl -0x114(%rbp), %eax
subl $0x4, %eax
je 0x4349
jmp 0x4306
movl -0x114(%rbp), %eax
subl $0x8, %eax
je 0x4349
jmp 0x4313
movl -0x114(%rbp), %eax
subl $0x10, %eax
je 0x454d
jmp 0x4324
movl -0x114(%rbp), %eax
subl $0x18, %eax
je 0x477c
jmp 0x4335
movl -0x114(%rbp), %eax
subl $0x20, %eax
je 0x477c
jmp 0x4957
movq -0x20(%rbp), %rax
movzwl 0xe(%rax), %ecx
movl $0x8, %eax
cltd
idivl %ecx
movl %eax, -0x48(%rbp)
movl $0x0, -0x4c(%rbp)
movl -0x4c(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x4548
movq -0x110(%rbp), %rax
movq -0x40(%rbp), %rcx
movl -0x44(%rbp), %edx
imull -0x4c(%rbp), %edx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, -0x58(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0x120(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0x118(%rbp)
testb $0x1, -0x2a(%rbp)
je 0x43b0
movl -0x4c(%rbp), %eax
movl %eax, -0x124(%rbp)
jmp 0x43bf
movl -0x28(%rbp), %eax
subl $0x1, %eax
subl -0x4c(%rbp), %eax
movl %eax, -0x124(%rbp)
movq -0x120(%rbp), %rax
movl -0x118(%rbp), %ecx
movl -0x124(%rbp), %edx
imull %edx, %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x60(%rbp)
movl $0x0, -0x64(%rbp)
movl -0x64(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x4538
movq -0x58(%rbp), %rax
movq %rax, -0x138(%rbp)
movl -0x64(%rbp), %eax
cltd
idivl -0x48(%rbp)
movl %eax, %ecx
movq -0x138(%rbp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x70(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x130(%rbp)
testb $0x1, -0x29(%rbp)
je 0x443d
movl -0x24(%rbp), %eax
subl $0x1, %eax
subl -0x64(%rbp), %eax
movl %eax, -0x13c(%rbp)
jmp 0x4446
movl -0x64(%rbp), %eax
movl %eax, -0x13c(%rbp)
movq -0x130(%rbp), %rax
movl -0x13c(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x78(%rbp)
movq -0x20(%rbp), %rax
movzwl 0xe(%rax), %ecx
movl $0x1, %eax
shll %cl, %eax
subl $0x1, %eax
movb %al, -0x79(%rbp)
movl -0x48(%rbp), %eax
subl $0x1, %eax
movl %eax, -0x140(%rbp)
movl -0x64(%rbp), %eax
cltd
idivl -0x48(%rbp)
movl -0x140(%rbp), %eax
subl %edx, %eax
movq -0x20(%rbp), %rcx
movzwl 0xe(%rcx), %ecx
imull %ecx, %eax
movl %eax, -0x80(%rbp)
movq -0x70(%rbp), %rax
movzbl (%rax), %eax
movl -0x80(%rbp), %ecx
sarl %cl, %eax
movzbl -0x79(%rbp), %ecx
andl %ecx, %eax
movl %eax, -0x84(%rbp)
movq -0x38(%rbp), %rax
movslq -0x84(%rbp), %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
movb (%rax), %al
movb %al, -0x91(%rbp)
movq -0x90(%rbp), %rax
movb 0x1(%rax), %al
movb %al, -0x92(%rbp)
movq -0x90(%rbp), %rax
movb 0x2(%rax), %al
movb %al, -0x93(%rbp)
movb -0x93(%rbp), %cl
movb -0x92(%rbp), %al
movl $0xff, %edi
movzbl %cl, %esi
movzbl %al, %edx
movzbl -0x91(%rbp), %ecx
callq 0x4ac0
movl %eax, %ecx
movq -0x78(%rbp), %rax
movl %ecx, (%rax)
movl -0x64(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x64(%rbp)
jmp 0x43ea
jmp 0x453a
movl -0x4c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x4c(%rbp)
jmp 0x4363
jmp 0x497b
movl $0x0, -0x98(%rbp)
movl -0x98(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x4777
movq -0x110(%rbp), %rax
movq -0x40(%rbp), %rcx
movl -0x44(%rbp), %edx
imull -0x98(%rbp), %edx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, -0xa0(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0x150(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0x144(%rbp)
testb $0x1, -0x2a(%rbp)
je 0x45b0
movl -0x98(%rbp), %eax
movl %eax, -0x154(%rbp)
jmp 0x45c2
movl -0x28(%rbp), %eax
subl $0x1, %eax
subl -0x98(%rbp), %eax
movl %eax, -0x154(%rbp)
movq -0x150(%rbp), %rax
movl -0x144(%rbp), %ecx
movl -0x154(%rbp), %edx
imull %edx, %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0xa8(%rbp)
movl $0x0, -0xac(%rbp)
movl -0xac(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x4761
movq -0xa0(%rbp), %rax
movq %rax, -0x168(%rbp)
movl -0xac(%rbp), %eax
movq -0x20(%rbp), %rcx
movzwl 0xe(%rcx), %ecx
imull %ecx, %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq -0x168(%rbp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0xb8(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x160(%rbp)
testb $0x1, -0x29(%rbp)
je 0x4667
movl -0x24(%rbp), %eax
subl $0x1, %eax
subl -0xac(%rbp), %eax
movl %eax, -0x16c(%rbp)
jmp 0x4673
movl -0xac(%rbp), %eax
movl %eax, -0x16c(%rbp)
movq -0x160(%rbp), %rax
movl -0x16c(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0xc0(%rbp)
movq -0xb8(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0xc8(%rbp), %rax
movzbl (%rax), %eax
andl $0x1f, %eax
shll $0x0, %eax
imull $0xff, %eax, %eax
movl $0x1f, %ecx
cltd
idivl %ecx
movb %al, -0xc9(%rbp)
movq -0xc8(%rbp), %rax
movzbl 0x1(%rax), %eax
andl $0x3, %eax
shll $0x3, %eax
movq -0xc8(%rbp), %rcx
movzbl (%rcx), %ecx
sarl $0x5, %ecx
andl $0x7, %ecx
orl %ecx, %eax
imull $0xff, %eax, %eax
movl $0x1f, %ecx
cltd
idivl %ecx
movb %al, -0xca(%rbp)
movq -0xc8(%rbp), %rax
movzbl 0x1(%rax), %eax
sarl $0x2, %eax
andl $0x1f, %eax
imull $0xff, %eax, %eax
movl $0x1f, %ecx
cltd
idivl %ecx
movb %al, -0xcb(%rbp)
movb -0xcb(%rbp), %cl
movb -0xca(%rbp), %al
movl $0xff, %edi
movzbl %cl, %esi
movzbl %al, %edx
movzbl -0xc9(%rbp), %ecx
callq 0x4ac0
movl %eax, %ecx
movq -0xc0(%rbp), %rax
movl %ecx, (%rax)
movl -0xac(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xac(%rbp)
jmp 0x45f3
jmp 0x4763
movl -0x98(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x98(%rbp)
jmp 0x4557
jmp 0x497b
movl $0x0, -0xd0(%rbp)
movl -0xd0(%rbp), %eax
cmpl -0x28(%rbp), %eax
jge 0x4955
movq -0x110(%rbp), %rax
movq -0x40(%rbp), %rcx
movl -0x44(%rbp), %edx
imull -0xd0(%rbp), %edx
movslq %edx, %rdx
addq %rdx, %rcx
movq %rcx, -0xd8(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0x178(%rbp)
movl -0x24(%rbp), %eax
movl %eax, -0x170(%rbp)
testb $0x1, -0x2a(%rbp)
je 0x47df
movl -0xd0(%rbp), %eax
movl %eax, -0x17c(%rbp)
jmp 0x47f1
movl -0x28(%rbp), %eax
subl $0x1, %eax
subl -0xd0(%rbp), %eax
movl %eax, -0x17c(%rbp)
movq -0x178(%rbp), %rax
movl -0x170(%rbp), %ecx
movl -0x17c(%rbp), %edx
imull %edx, %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0xe0(%rbp)
movl $0x0, -0xe4(%rbp)
movl -0xe4(%rbp), %eax
cmpl -0x24(%rbp), %eax
jge 0x493f
movq -0xd8(%rbp), %rax
movq %rax, -0x190(%rbp)
movl -0xe4(%rbp), %eax
movq -0x20(%rbp), %rcx
movzwl 0xe(%rcx), %ecx
imull %ecx, %eax
movl $0x8, %ecx
cltd
idivl %ecx
movl %eax, %ecx
movq -0x190(%rbp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0xf0(%rbp)
movq -0xe0(%rbp), %rax
movq %rax, -0x188(%rbp)
testb $0x1, -0x29(%rbp)
je 0x4896
movl -0x24(%rbp), %eax
subl $0x1, %eax
subl -0xe4(%rbp), %eax
movl %eax, -0x194(%rbp)
jmp 0x48a2
movl -0xe4(%rbp), %eax
movl %eax, -0x194(%rbp)
movq -0x188(%rbp), %rax
movl -0x194(%rbp), %ecx
movslq %ecx, %rcx
shlq $0x2, %rcx
addq %rcx, %rax
movq %rax, -0xf8(%rbp)
movq -0xf0(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x100(%rbp), %rax
movb (%rax), %al
movb %al, -0x101(%rbp)
movq -0x100(%rbp), %rax
movb 0x1(%rax), %al
movb %al, -0x102(%rbp)
movq -0x100(%rbp), %rax
movb 0x2(%rax), %al
movb %al, -0x103(%rbp)
movb -0x103(%rbp), %cl
movb -0x102(%rbp), %al
movl $0xff, %edi
movzbl %cl, %esi
movzbl %al, %edx
movzbl -0x101(%rbp), %ecx
callq 0x4ac0
movl %eax, %ecx
movq -0xf8(%rbp), %rax
movl %ecx, (%rax)
movl -0xe4(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xe4(%rbp)
jmp 0x4822
jmp 0x4941
movl -0xd0(%rbp), %eax
addl $0x1, %eax
movl %eax, -0xd0(%rbp)
jmp 0x4786
jmp 0x497b
movq -0x110(%rbp), %rdi
movl $0x3, 0x10(%rdi)
addq $0x18, %rdi
leaq 0x1afa(%rip), %rsi      # 0x646a
callq 0x22d0
movb $0x0, -0x1(%rbp)
jmp 0x497f
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x1a0, %rsp            # imm = 0x1A0
popq %rbp
retq
nopl (%rax)