// File: /workspace/github_cpp_makefile_star2_O2/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, -0x8(%rsp)
movq %rsi, -0x20(%rsp)
testb $0x7, %sil
jne 0x39f7
movq -0x8(%rsp), %rax
movq 0x8(%rax), %r9
movzbl 0x3c019(%r9), %ecx
movl %ecx, %eax
andl $0x8, %eax
je 0x39f7
movq -0x20(%rsp), %rax
sarl $0x3, %eax
testl %eax, %eax
jg 0x3a02
andl $0x2, %ecx
jne 0x3a02
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movzwl 0x3c01a(%r9), %esi
movzbl %sil, %ecx
movl %ecx, -0xc(%rsp)
shrl $0x8, %esi
movl $0x4, %ecx
cltd
idivl %ecx
leal 0x23c0(,%rax,8), %eax
movl %eax, -0x14(%rsp)
movq -0x20(%rsp), %rax
movl %eax, %ecx
shrb $0x2, %cl
andb $0x4, %cl
movb %cl, -0x25(%rsp)
leal 0x2000(,%rax,4), %eax
movl %eax, -0x18(%rsp)
negl %esi
movl %esi, -0x24(%rsp)
xorl %eax, %eax
cmpl $0x20, %eax
je 0x39f7
movl %eax, %r13d
shrl $0x2, %r13d
orl -0x14(%rsp), %r13d
movl %eax, %edx
andb $0x2, %dl
movl -0x18(%rsp), %ebp
movl %eax, -0x10(%rsp)
orl %eax, %ebp
xorl %r14d, %r14d
cmpl $0x8, %r14d
je 0x3b7e
movl %r14d, %ebx
orl -0x20(%rsp), %ebx
subl -0xc(%rsp), %ebx
movl %ebx, %eax
shll $0x8, %eax
leal 0xf000(%rax), %r15d
testl %ebx, %ebx
cmovnsl %eax, %r15d
movl -0x24(%rsp), %eax
movl %eax, %r11d
movl $0x7, %r8d
cmpl $-0x1, %r8d
je 0x3b76
movl %r11d, %esi
shrl $0x17, %esi
andl $0x100, %esi            # imm = 0x100
addl %r15d, %esi
addl %r11d, %esi
cmpl $0xefff, %esi           # imm = 0xEFFF
jg 0x3b6b
movl %r11d, %eax
shrl $0x1f, %eax
movzbl 0x3c010(%r9), %edi
movl %edi, %ecx
andl $0x3, %ecx
xorl %eax, %ecx
shll $0xa, %ecx
movl %ecx, %r12d
xorl $0x800, %r12d           # imm = 0x800
testl %ebx, %ebx
cmovnsl %ecx, %r12d
movq (%r9), %r10
leal (%r12,%r13), %eax
movb (%r10,%rax), %al
movb -0x25(%rsp), %cl
shrb %cl, %al
movl %edx, %ecx
shrb %cl, %al
andl $0x10, %edi
shll $0x8, %edi
addl %ebp, %r12d
movzbl (%r10,%r12), %ecx
shll $0x4, %ecx
orl %edi, %ecx
orl %r14d, %ecx
movzbl (%r10,%rcx), %edi
xorl %r12d, %r12d
btl %r8d, %edi
setb %r12b
movzbl 0x8(%r10,%rcx), %edi
movl %r8d, %ecx
shrl %cl, %edi
andl $0x1, %edi
leal (%r12,%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 (%r10,%rax), %eax
movq -0x8(%rsp), %rcx
movl 0x38(%rcx,%rax,4), %eax
movslq %esi, %rcx
movl %eax, 0x10(%r9,%rcx,4)
decl %r8d
incl %r11d
jmp 0x3aa3
incl %r14d
jmp 0x3a6f
movl -0x10(%rsp), %eax
incl %eax
addl $0x8, -0x24(%rsp)
jmp 0x3a4c