// File: /workspace/github_cpp_makefile_star2_O3/NGageMegaman[P]NEScutre/src/ppu.cpp
// Function: Ppu::draw(int)
void Ppu::draw(int n_scanline) {
    //Select what events the window will listen to
    //XEvent ev;
    unsigned int nametable;
    unsigned int idx = 0;
    unsigned int attribute_addr = 0;
    unsigned char attribute;
    unsigned int line_addr, h_offset;
    unsigned int nt_off;
    unsigned int patterntable;
    int pos_x, pos_y, sc_off_x, sc_off_y;
    //int a = XNextEvent(di, &ev);
    //if (ev.type == Expose) {
    //BG enable
    if ((mem_ppu->PPUMASK >> 3)&1) {
	if ((n_scanline & 0x7) == 0) {
	    int i = n_scanline/8;
	    //Leftmost tiles
	    if (i > 0 || ((mem_ppu->PPUMASK >> 1)&1)) {
		for (int j = 0; j<32; ++j) {
	    	    //TILE
	    	    for (int i2 = 0; i2<8; ++i2) {
			for (int j2 = 0; j2<8; ++j2) {

			    //Compute the scrolling tile offsets
			    sc_off_y = mem_ppu->PPUSCROLL & 0x00ff;
			    sc_off_x = ((mem_ppu->PPUSCROLL & 0xff00)>>8) & 0x00ff;

			    //Compute which nametable we use
			    nt_off = (mem_ppu->PPUCTRL & 3);

			    //Compute the position
			    pos_x = (j*8)+j2 - sc_off_x;
			    if (pos_x < 0) {
				pos_x += 32*8;
				nt_off = (nt_off & 2) | ((nt_off+1) & 1);
			    }
			    pos_y = (i*8)+i2 - sc_off_y;
			    if (pos_y < 0) {
				pos_y += 30*8;
				nt_off = ((nt_off+2) & 2) | (nt_off & 1);
			    }

			    nametable = 0x2000 + (nt_off * 0x0400);

			    //Compute which pattern table we use
			    patterntable = (mem_ppu->PPUCTRL >> 4) & 1;
			    //Fetch the index of the bg tile
			    idx = (mem_ppu->ram[nametable+(i*32)+j]);
			    //If we use the second pt, we add 256 to the index
			    if (patterntable) 
				idx += 256;
			    //Each pattern is 16-byte wide. i2 is the vertical offset
			    line_addr = (idx * 16) + i2;
			    //j2 is the horizontal offset. We start from the MSB
			    h_offset = (7-j2);

            	    	    //Compute the bitplane

            	    	    /*
            	    	    Each tile is formed by two bitplanes. The first one
            	    	    is followed by the second one. We fetch the line_addr byte,
            	    	    which contains the first bitplane of a given line, and the
            	    	    line_addr+8 byte, which contains the second one. Using
            	    	    h_offset we get the particular bit of the line that we want
            	    	    */

	    	    	    unsigned char bitplane = 
	    	    	     (((mem_ppu->ram[line_addr]  )>>h_offset)&1) |
	    	    	    ((((mem_ppu->ram[line_addr+8])>>h_offset)&1)<<1);

            	    	    //Compute the attribute address of the tile
            	    	    //TODO: this can be done outside the tile render loop
	    	    	    attribute_addr = nametable + 0x03c0;
            	    	    
            	    	    /*
            	    	    Each attribute contains 4 pallette indexes corresponding to
            	    	    a 2x2 tile portion of the screen. They are arranged, from
            	    	    MSB to LSB as such:

            	    	    bottom right, bottom left, top right, top left
            	    	         7,6           5,4        3,2       1,0

            	    	    That means that each pattern contains the pallette of
            	    	    two different rows and two different columns. If the
            	    	    row is odd, we shift the attribute 4 bits right, and if the
            	    	    column is odd, we shift the attribute 2 bits right. This
            	    	    way we get the correct pallette index on the lower 2 bits.
            	    	    */

	    	    	    //Determine the attribute address
	    	            attribute_addr = attribute_addr + (i/4)*8;
	    	            attribute_addr = attribute_addr + (j/4);
	    	    	    //Fetch the attribute byte
	    	            attribute = mem_ppu->ram[attribute_addr];
	    	    	    //Arrange the lower 2 bits with the correct pallette index
	    	            if ((i & 3) > 1) {
	    	                attribute = attribute >> 4;
	    	            }
	    	            if ((j & 3) > 1) {
	    	                attribute = attribute >> 2;
	    	            }
	    	    	    //We compute the final pallette index with the bitplane value
	    	            attribute = ((attribute << 2) | bitplane) & 0x000f;
			    if (bitplane == 0) attribute = 0;
	    	    	    //We fetch the color value
	    	            unsigned char color = mem_ppu->ram[0x3f00 + attribute];
			    int position = (pos_y*256)+pos_x;
			    if (position < 61440)
				mem_ppu->vram[position] = colors[color];
			}
		    }
	    	}
	    }
	}
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
movq %rdi, -0x18(%rsp)
movq %rsi, -0x30(%rsp)
testb $0x7, %sil
jne 0x528e
movq -0x18(%rsp), %rax
movq 0x8(%rax), %r9
movzbl 0x3c019(%r9), %ecx
movl %ecx, %eax
andl $0x8, %eax
je 0x528e
movq -0x30(%rsp), %rax
sarl $0x3, %eax
testl %eax, %eax
jg 0x5103
andl $0x2, %ecx
je 0x528e
movzwl 0x3c01a(%r9), %edx
movzbl %dl, %ecx
movl %ecx, -0x20(%rsp)
shrl $0x8, %edx
leal 0x3(%rax), %ecx
testl %eax, %eax
cmovnsl %eax, %ecx
andl $-0x4, %ecx
leal 0x23c0(,%rcx,2), %eax
movl %eax, -0x24(%rsp)
movq -0x30(%rsp), %rax
movl %eax, %ecx
shrb $0x2, %cl
andb $0x4, %cl
movb %cl, -0x35(%rsp)
leal 0x2000(,%rax,4), %eax
movq %rax, -0x10(%rsp)
negl %edx
movl %edx, -0x34(%rsp)
xorl %ecx, %ecx
movl %ecx, %r12d
shrl $0x2, %r12d
addl -0x24(%rsp), %r12d
movl %ecx, %edx
andb $0x2, %dl
movq -0x10(%rsp), %rax
movq %rcx, -0x8(%rsp)
leal (%rax,%rcx), %r13d
xorl %ecx, %ecx
movl %ecx, %ebx
orl -0x30(%rsp), %ebx
subl -0x20(%rsp), %ebx
movl %ebx, %eax
shll $0x8, %eax
leal 0xf000(%rax), %r15d
testl %ebx, %ebx
cmovnsl %eax, %r15d
movl $0x7, %r8d
movl %ecx, -0x1c(%rsp)
movl %ecx, %r11d
movl -0x34(%rsp), %eax
movl %eax, %esi
movl %esi, %r10d
shrl $0x17, %r10d
andl $0x100, %r10d           # imm = 0x100
addl %r15d, %r10d
addl %esi, %r10d
cmpl $0xefff, %r10d          # imm = 0xEFFF
jg 0x525e
movl %esi, %eax
shrl $0x1f, %eax
movzbl 0x3c010(%r9), %edi
movl %edi, %ecx
andl $0x3, %ecx
xorl %eax, %ecx
shll $0xa, %ecx
movl %ecx, %ebp
xorl $0x800, %ebp            # imm = 0x800
testl %ebx, %ebx
movq (%r9), %r14
cmovnsl %ecx, %ebp
leal (%r12,%rbp), %eax
movb (%r14,%rax), %al
movb -0x35(%rsp), %cl
shrb %cl, %al
movl %edx, %ecx
shrb %cl, %al
andl $0x10, %edi
shll $0x8, %edi
addl %r13d, %ebp
movzbl (%r14,%rbp), %ecx
shll $0x4, %ecx
orl %edi, %ecx
addq %r11, %rcx
movzbl (%r14,%rcx), %edi
xorl %ebp, %ebp
btl %r8d, %edi
setb %bpl
movl %ecx, %ecx
movzbl 0x8(%r14,%rcx), %edi
movl %r8d, %ecx
shrl %cl, %edi
andl $0x1, %edi
leal (%rbp,%rdi,2), %ecx
movzbl %al, %eax
andl $0x3, %eax
leal (%rcx,%rax,4), %eax
movl $0x3f00, %edi           # imm = 0x3F00
orl %edi, %eax
testl %ecx, %ecx
cmovel %edi, %eax
movzbl (%r14,%rax), %eax
movq -0x18(%rsp), %rcx
movl 0x38(%rcx,%rax,4), %eax
movslq %r10d, %rcx
movl %eax, 0x10(%r9,%rcx,4)
incl %esi
addl $-0x1, %r8d
jb 0x51a0
movl -0x1c(%rsp), %ecx
incl %ecx
cmpl $0x8, %ecx
jne 0x5171
movq -0x8(%rsp), %rcx
incl %ecx
addl $0x8, -0x34(%rsp)
cmpl $0x20, %ecx
jne 0x5150
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
nop