// File: nicoeps[P]NicoGB/src/ppu.cpp
// Function: PPU::drawSprites()
void PPU::drawSprites() {
    if (!(lcdc & 0x2)) {
        return;
    }
    int size = ((lcdc & 0x4) >> 2) ? 16 : 8;
    const uint16_t OAM = 0xFE00;

    typedef std::tuple<int, int, int> SpriteTuple;
    std::vector<SpriteTuple> sprites = std::vector<SpriteTuple>();
    sprites.reserve(10);
    for (int byte = 0; byte < 0x9F; byte += 4) {
        int Y = memory.read(OAM+byte) - 16;
        int X = memory.read(OAM+byte + 1) - 8;

        if (Y <= ly && Y > ly - size) {
            sprites.push_back(std::make_tuple(byte, Y, X));
            if (sprites.size() >= 10) {
                break;
            }
        }
    }

    std::sort(sprites.begin(), sprites.end(),
        [](const SpriteTuple& a, const SpriteTuple& b) {
            return (std::get<2>(a) >= std::get<2>(b));
        }
    );

    for (const auto &sprite : sprites) {
        int byte = std::get<0>(sprite);
        int Y = std::get<1>(sprite);
        int X = std::get<2>(sprite);

        if (X == -8 || X >= 160) {
            continue;
        }

        uint8_t tileNumber = memory.read(OAM+byte+2);
        if (size == 16) {
            tileNumber &= ~1;
        }

        uint8_t attributes = memory.read(OAM+byte+3);
        std::vector<uint32_t> col = getPalette((attributes & 0x10) ? obp1 : obp0);
        bool xFlip = attributes & 0x20;
        bool yFlip = attributes & 0x40;
        bool priority = attributes & 0x80;

        int i = ly - Y;
        uint8_t byte1 = memory.read(0x8000 + (tileNumber*16) + i * 2);
        uint8_t byte2 = memory.read(0x8000 + (tileNumber*16) + i * 2 + 1);
        if (yFlip) {
            byte1 = memory.read(0x8000 + (tileNumber*16) + (size - 1 - i) * 2);
            byte2 = memory.read(0x8000 + (tileNumber*16) + (size - 1 - i) * 2 + 1);
        }

        for (int j = 0; j < 8; ++j) {
            int XX = X + j;
            if (ly < 144 && XX < 160 && XX >= 0) {
                if (priority && line[XX] > 0) {
                    continue;
                }
                uint8_t bit1 = (byte1 >> (7 - j)) & 0x1;
                uint8_t bit2 = (byte2 >> (7 - j)) & 0x1;
                if (xFlip) {
                    bit1 = (byte1 >> j) & 0x1;
                    bit2 = (byte2 >> j) & 0x1;
                }
                uint8_t color = (bit2 << 1) | bit1;
                uint32_t pixel = col[color];

                if (color != 0) {
                    writebuffer[ly * 160 + XX] = pixel;
                }
            }
        }
    }
}

// Assembly:
subq $0x108, %rsp            # imm = 0x108
movq %rdi, 0x100(%rsp)
movq 0x100(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0x28(%rax), %rax
movzbl (%rax), %eax
andl $0x2, %eax
cmpl $0x0, %eax
jne 0x11a00
jmp 0x12015
movq 0x30(%rsp), %rax
movq 0x28(%rax), %rax
movzbl (%rax), %ecx
andl $0x4, %ecx
movl %ecx, %eax
leal 0x8(%rax,%rax), %eax
movl %eax, 0xfc(%rsp)
movw $0xfe00, 0xfa(%rsp)     # imm = 0xFE00
xorps %xmm0, %xmm0
movaps %xmm0, 0xe0(%rsp)
movq $0x0, 0xf0(%rsp)
leaq 0xe0(%rsp), %rdi
movq %rdi, 0x28(%rsp)
callq 0x13640
movq 0x28(%rsp), %rdi
movl $0xa, %esi
callq 0x13650
jmp 0x11a60
movl $0x0, 0xd0(%rsp)
cmpl $0x9f, 0xd0(%rsp)
jge 0x11ba1
movq 0x30(%rsp), %rax
movq (%rax), %rdi
movl 0xd0(%rsp), %eax
addl $0xfe00, %eax           # imm = 0xFE00
movzwl %ax, %esi
callq 0xef80
movb %al, 0x27(%rsp)
jmp 0x11a9e
movq 0x30(%rsp), %rax
movb 0x27(%rsp), %cl
movzbl %cl, %ecx
addl $-0x10, %ecx
movl %ecx, 0xcc(%rsp)
movq (%rax), %rdi
movl 0xd0(%rsp), %eax
addl $0xfe01, %eax           # imm = 0xFE01
movzwl %ax, %esi
callq 0xef80
movb %al, 0x26(%rsp)
jmp 0x11ad1
movq 0x30(%rsp), %rcx
movb 0x26(%rsp), %al
movzbl %al, %eax
subl $0x8, %eax
movl %eax, 0xc8(%rsp)
movl 0xcc(%rsp), %eax
movq 0x48(%rcx), %rcx
movzbl (%rcx), %ecx
cmpl %ecx, %eax
jg 0x11b89
movq 0x30(%rsp), %rcx
movl 0xcc(%rsp), %eax
movq 0x48(%rcx), %rcx
movzbl (%rcx), %ecx
subl 0xfc(%rsp), %ecx
cmpl %ecx, %eax
jle 0x11b89
leaq 0xbc(%rsp), %rdi
leaq 0xd0(%rsp), %rsi
leaq 0xcc(%rsp), %rdx
leaq 0xc8(%rsp), %rcx
callq 0x13790
jmp 0x11b42
leaq 0xe0(%rsp), %rdi
leaq 0xbc(%rsp), %rsi
callq 0x13760
jmp 0x11b59
leaq 0xe0(%rsp), %rdi
callq 0x137d0
cmpq $0xa, %rax
jb 0x11b87
jmp 0x11ba1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd8(%rsp)
movl %eax, 0xd4(%rsp)
jmp 0x1201d
jmp 0x11b89
jmp 0x11b8b
movl 0xd0(%rsp), %eax
addl $0x4, %eax
movl %eax, 0xd0(%rsp)
jmp 0x11a6b
leaq 0xe0(%rsp), %rdi
movq %rdi, 0x18(%rsp)
callq 0x137f0
movq 0x18(%rsp), %rdi
movq %rax, 0xb0(%rsp)
callq 0x13820
movq %rax, 0xa8(%rsp)
movq 0xb0(%rsp), %rdi
movq 0xa8(%rsp), %rsi
callq 0x12040
jmp 0x11be4
leaq 0xe0(%rsp), %rax
movq %rax, 0x98(%rsp)
movq 0x98(%rsp), %rdi
callq 0x137f0
movq %rax, 0x90(%rsp)
movq 0x98(%rsp), %rdi
callq 0x13820
movq %rax, 0x88(%rsp)
leaq 0x90(%rsp), %rdi
leaq 0x88(%rsp), %rsi
callq 0x13850
testb $0x1, %al
jne 0x11c3c
jmp 0x12008
leaq 0x90(%rsp), %rdi
callq 0x13890
movq %rax, 0x80(%rsp)
movq 0x80(%rsp), %rdi
callq 0x138a0
movl (%rax), %eax
movl %eax, 0x7c(%rsp)
movq 0x80(%rsp), %rdi
callq 0x138b0
movl (%rax), %eax
movl %eax, 0x78(%rsp)
movq 0x80(%rsp), %rdi
callq 0x138c0
movl (%rax), %eax
movl %eax, 0x74(%rsp)
cmpl $-0x8, 0x74(%rsp)
je 0x11c9b
cmpl $0xa0, 0x74(%rsp)
jl 0x11ca0
jmp 0x11ff6
movq 0x30(%rsp), %rax
movq (%rax), %rdi
movl 0x7c(%rsp), %eax
addl $0xfe02, %eax           # imm = 0xFE02
movzwl %ax, %esi
callq 0xef80
movb %al, 0x17(%rsp)
jmp 0x11cbf
movb 0x17(%rsp), %al
movb %al, 0x73(%rsp)
cmpl $0x10, 0xfc(%rsp)
jne 0x11cdd
movzbl 0x73(%rsp), %eax
andl $-0x2, %eax
movb %al, 0x73(%rsp)
movq 0x30(%rsp), %rax
movq (%rax), %rdi
movl 0x7c(%rsp), %eax
addl $0xfe03, %eax           # imm = 0xFE03
movzwl %ax, %esi
callq 0xef80
movb %al, 0x16(%rsp)
jmp 0x11cfc
movb 0x16(%rsp), %al
movb %al, 0x72(%rsp)
movzbl 0x72(%rsp), %eax
andl $0x10, %eax
cmpl $0x0, %eax
je 0x11d22
movq 0x30(%rsp), %rax
movq 0x68(%rax), %rax
movb (%rax), %al
movb %al, 0x15(%rsp)
jmp 0x11d31
movq 0x30(%rsp), %rax
movq 0x60(%rax), %rax
movb (%rax), %al
movb %al, 0x15(%rsp)
movq 0x30(%rsp), %rsi
movb 0x15(%rsp), %al
movzbl %al, %edx
leaq 0x58(%rsp), %rdi
callq 0x10e60
jmp 0x11d49
movq 0x30(%rsp), %rax
movzbl 0x72(%rsp), %ecx
andl $0x20, %ecx
shrl $0x5, %ecx
movb %cl, 0x57(%rsp)
movzbl 0x72(%rsp), %ecx
andl $0x40, %ecx
shrl $0x6, %ecx
movb %cl, 0x56(%rsp)
movb 0x72(%rsp), %cl
shrb $0x7, %cl
movb %cl, 0x55(%rsp)
movq 0x48(%rax), %rcx
movzbl (%rcx), %ecx
movl 0x78(%rsp), %edx
subl %edx, %ecx
movl %ecx, 0x50(%rsp)
movq (%rax), %rdi
movzbl 0x73(%rsp), %edx
shll $0x4, %edx
movl 0x50(%rsp), %eax
movl %eax, %ecx
movl %edx, %eax
leal 0x8000(%rax,%rcx,2), %eax
movzwl %ax, %esi
callq 0xef80
movb %al, 0x14(%rsp)
jmp 0x11db0
movq 0x30(%rsp), %rax
movb 0x14(%rsp), %cl
movb %cl, 0x4f(%rsp)
movq (%rax), %rdi
movzbl 0x73(%rsp), %edx
shll $0x4, %edx
movl 0x50(%rsp), %eax
movl %eax, %ecx
movl %edx, %eax
leal 0x8001(%rax,%rcx,2), %eax
movzwl %ax, %esi
callq 0xef80
movb %al, 0x13(%rsp)
jmp 0x11de5
movb 0x13(%rsp), %al
movb %al, 0x4e(%rsp)
testb $0x1, 0x56(%rsp)
je 0x11e9d
movq 0x30(%rsp), %rax
movq (%rax), %rdi
movzbl 0x73(%rsp), %ecx
shll $0x4, %ecx
movl 0xfc(%rsp), %eax
movl 0x50(%rsp), %edx
notl %edx
addl %eax, %edx
movl %ecx, %eax
movl %edx, %ecx
leal 0x8000(%rax,%rcx,2), %eax
movzwl %ax, %esi
callq 0xef80
movb %al, 0x12(%rsp)
jmp 0x11e30
movq 0x30(%rsp), %rax
movb 0x12(%rsp), %cl
movb %cl, 0x4f(%rsp)
movq (%rax), %rdi
movzbl 0x73(%rsp), %ecx
shll $0x4, %ecx
movl 0xfc(%rsp), %eax
movl 0x50(%rsp), %edx
notl %edx
addl %eax, %edx
movl %ecx, %eax
movl %edx, %ecx
leal 0x8001(%rax,%rcx,2), %eax
movzwl %ax, %esi
callq 0xef80
movb %al, 0x11(%rsp)
jmp 0x11e70
movb 0x11(%rsp), %al
movb %al, 0x4e(%rsp)
jmp 0x11e9d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, 0xd8(%rsp)
movl %eax, 0xd4(%rsp)
leaq 0x58(%rsp), %rdi
callq 0xd450
jmp 0x1201d
movl $0x0, 0x48(%rsp)
cmpl $0x8, 0x48(%rsp)
jge 0x11fec
movq 0x30(%rsp), %rax
movl 0x74(%rsp), %ecx
addl 0x48(%rsp), %ecx
movl %ecx, 0x44(%rsp)
movq 0x48(%rax), %rax
movzbl (%rax), %eax
cmpl $0x90, %eax
jge 0x11fda
cmpl $0xa0, 0x44(%rsp)
jge 0x11fda
cmpl $0x0, 0x44(%rsp)
jl 0x11fda
testb $0x1, 0x55(%rsp)
je 0x11f16
movq 0x30(%rsp), %rdi
addq $0xa0, %rdi
movslq 0x44(%rsp), %rsi
callq 0x40f0
movzbl (%rax), %eax
cmpl $0x0, %eax
jle 0x11f16
jmp 0x11fdc
movzbl 0x4f(%rsp), %eax
movl $0x7, %ecx
subl 0x48(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
movb %al, 0x43(%rsp)
movzbl 0x4e(%rsp), %eax
movl $0x7, %ecx
subl 0x48(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
movb %al, 0x42(%rsp)
testb $0x1, 0x57(%rsp)
je 0x11f6f
movzbl 0x4f(%rsp), %eax
movl 0x48(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
movb %al, 0x43(%rsp)
movzbl 0x4e(%rsp), %eax
movl 0x48(%rsp), %ecx
sarl %cl, %eax
andl $0x1, %eax
movb %al, 0x42(%rsp)
movzbl 0x42(%rsp), %eax
shll %eax
movzbl 0x43(%rsp), %ecx
orl %ecx, %eax
movb %al, 0x41(%rsp)
movzbl 0x41(%rsp), %eax
movl %eax, %esi
leaq 0x58(%rsp), %rdi
callq 0x134d0
movl (%rax), %eax
movl %eax, 0x3c(%rsp)
movzbl 0x41(%rsp), %eax
cmpl $0x0, %eax
je 0x11fd8
movq 0x30(%rsp), %rax
movl 0x3c(%rsp), %ecx
movl %ecx, 0xc(%rsp)
movq %rax, %rdi
addq $0x88, %rdi
movq 0x48(%rax), %rax
movzbl (%rax), %eax
imull $0xa0, %eax, %eax
addl 0x44(%rsp), %eax
movslq %eax, %rsi
callq 0x134d0
movl 0xc(%rsp), %ecx
movl %ecx, (%rax)
jmp 0x11fda
jmp 0x11fdc
movl 0x48(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x48(%rsp)
jmp 0x11ea5
leaq 0x58(%rsp), %rdi
callq 0xd450
leaq 0x90(%rsp), %rdi
callq 0x138d0
jmp 0x11c1e
leaq 0xe0(%rsp), %rdi
callq 0x138f0
addq $0x108, %rsp            # imm = 0x108
retq
leaq 0xe0(%rsp), %rdi
callq 0x138f0
movq 0xd8(%rsp), %rdi
callq 0x33d0
nopw (%rax,%rax)