// File: /workspace/github_cpp_makefile_star2_O1/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
cmpl $0x0, 0x10(%rdx)
jne 0x3889
movq %rdx, %rcx
movl (%rdi), %r9d
movzwl 0xe(%rdx), %r8d
movl %r9d, %ebx
imull %r8d, %ebx
leal 0x1f(%rbx), %eax
addl $0x3e, %ebx
testl %eax, %eax
cmovnsl %eax, %ebx
cmpq $0x20, %r8
ja 0x3851
movl 0x4(%rdi), %r10d
movl 0x4(%rcx), %r11d
movl 0x8(%rcx), %eax
movl %eax, 0xc(%rsp)
movl 0xa(%rsi), %eax
addq %rsi, %rax
movq %rax, 0x20(%rsp)
sarl $0x5, %ebx
shll $0x2, %ebx
movl $0x112, %eax            # imm = 0x112
btq %r8, %rax
movq %r10, 0x28(%rsp)
jb 0x364c
movabsq $0x101000000, %rax      # imm = 0x101000000
btq %r8, %rax
jae 0x3730
movb $0x1, %r14b
testl %r10d, %r10d
jle 0x3877
movq 0x8(%rdi), %rax
movslq %ebx, %rcx
leal -0x1(%r9), %edx
xorl %esi, %esi
movl %esi, %ebx
notl %ebx
addl %r10d, %ebx
cmpl 0xc(%rsp), %r10d
cmovnel %esi, %ebx
testl %r9d, %r9d
jle 0x363a
movq %rsi, %rdi
imulq %rcx, %rdi
addq 0x20(%rsp), %rdi
imull %r9d, %ebx
movslq %ebx, %r10
leaq (%rax,%r10,4), %rbx
xorl %ebp, %ebp
movl %edx, %r14d
xorl %r15d, %r15d
movl %ebp, %r10d
shrl $0x3, %r10d
cmpl %r11d, %r9d
movl %r14d, %r12d
cmovel %r15d, %r12d
movslq %r12d, %r12
movzbl 0x2(%rdi,%r10), %r13d
shll $0x10, %r13d
movzwl (%rdi,%r10), %r10d
orl %r13d, %r10d
orl $0xff000000, %r10d      # imm = 0xFF000000
movl %r10d, (%rbx,%r12,4)
incl %r15d
addl %r8d, %ebp
addl $-0x1, %r14d
jb 0x35fd
incq %rsi
movq 0x28(%rsp), %r10
cmpq %r10, %rsi
jne 0x35ca
jmp 0x384c
movw $0x8, %ax
xorl %edx, %edx
divw %r8w
movb $0x1, %r14b
testl %r10d, %r10d
jle 0x3877
movl (%rcx), %ecx
leaq (%rsi,%rcx), %r15
addq $0xe, %r15
movzwl %ax, %r12d
movq 0x8(%rdi), %rax
movq %rax, 0x18(%rsp)
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
movl %r8d, %ecx
shll %cl, %eax
notl %eax
movzbl %al, %r13d
movslq %ebx, %rax
movq %rax, 0x10(%rsp)
leal -0x1(%r9), %eax
movl %eax, 0x34(%rsp)
xorl %ebp, %ebp
movl %ebp, %eax
notl %eax
addl %r10d, %eax
cmpl 0xc(%rsp), %r10d
cmovnel %ebp, %eax
testl %r9d, %r9d
jle 0x371a
movq %rbp, %rdi
imulq 0x10(%rsp), %rdi
addq 0x20(%rsp), %rdi
imull %r9d, %eax
cltq
movq 0x18(%rsp), %rcx
leaq (%rcx,%rax,4), %rbx
xorl %esi, %esi
movl 0x34(%rsp), %r14d
movl %esi, %eax
xorl %edx, %edx
divl %r12d
cmpl %r11d, %r9d
movl %r14d, %ecx
cmovel %esi, %ecx
movslq %ecx, %r10
notl %edx
leal (%rdx,%r12), %ecx
imull %r8d, %ecx
movzbl (%rdi,%rax), %eax
shrl %cl, %eax
andl %r13d, %eax
movzbl 0x2(%r15,%rax,4), %ecx
shll $0x10, %ecx
movzwl (%r15,%rax,4), %eax
orl %ecx, %eax
orl $0xff000000, %eax       # imm = 0xFF000000
movl %eax, (%rbx,%r10,4)
incl %esi
addl $-0x1, %r14d
jb 0x36d3
incq %rbp
movq 0x28(%rsp), %r10
cmpq %r10, %rbp
jne 0x369b
jmp 0x384c
cmpq $0x10, %r8
jne 0x3851
movb $0x1, %r14b
testl %r10d, %r10d
jle 0x3877
movq 0x8(%rdi), %rax
movq %rax, 0x18(%rsp)
movslq %ebx, %rax
movq %rax, 0x10(%rsp)
leal -0x1(%r9), %edx
xorl %esi, %esi
movl %esi, %ebx
notl %ebx
addl %r10d, %ebx
cmpl 0xc(%rsp), %r10d
cmovnel %esi, %ebx
testl %r9d, %r9d
jle 0x383b
movq %rsi, %rdi
imulq 0x10(%rsp), %rdi
addq 0x20(%rsp), %rdi
imull %r9d, %ebx
movslq %ebx, %r10
movq 0x18(%rsp), %rax
leaq (%rax,%r10,4), %rbx
xorl %r14d, %r14d
movl %edx, %r15d
xorl %r12d, %r12d
movl %r14d, %r10d
shrl $0x3, %r10d
cmpl %r11d, %r9d
movl %r15d, %ebp
cmovel %r12d, %ebp
movslq %ebp, %r13
movzbl (%rdi,%r10), %eax
movl %eax, %ebp
andl $0x1f, %ebp
movl %ebp, %ecx
shll $0x8, %ecx
subl %ebp, %ecx
imulq $0x8421085, %rcx, %rbp  # imm = 0x8421085
shrq $0x20, %rbp
movzbl 0x1(%rdi,%r10), %ecx
movl %ecx, %r10d
andl $0x3, %r10d
shrl $0x5, %eax
leal (%rax,%r10,8), %eax
movl %eax, %r10d
shll $0x8, %r10d
subl %eax, %r10d
imulq $0x8421085, %r10, %rax  # imm = 0x8421085
shrq $0x20, %rax
shrl $0x2, %ecx
andl $0x1f, %ecx
movl %ecx, %r10d
shll $0x8, %r10d
subl %ecx, %r10d
imulq $0x8421085, %r10, %rcx  # imm = 0x8421085
shrq $0x20, %rcx
shll $0x10, %ecx
shll $0x8, %eax
movzwl %ax, %eax
orl %ecx, %eax
movzbl %bpl, %ecx
orl %eax, %ecx
orl $0xff000000, %ecx       # imm = 0xFF000000
movl %ecx, (%rbx,%r13,4)
incl %r12d
addl %r8d, %r14d
addl $-0x1, %r15d
jb 0x379c
incq %rsi
movq 0x28(%rsp), %r10
cmpq %r10, %rsi
jne 0x375d
movb $0x1, %r14b
jmp 0x3877
movl $0x3, 0x10(%rdi)
movq 0x20(%rdi), %rdx
addq $0x18, %rdi
leaq 0xbf6(%rip), %rcx       # 0x445d
xorl %r14d, %r14d
movl $0x19, %r8d
xorl %esi, %esi
callq 0x21f0
movl %r14d, %eax
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0xb4c(%rip), %rdi       # 0x43dc
leaq 0xb61(%rip), %rsi       # 0x43f8
leaq 0xb64(%rip), %rcx       # 0x4402
movl $0xf1, %edx
callq 0x20e0