/* * gba.c */ #include "gba.h" /* the screen is simply a pointer into memory at a specific address this * * pointer points to 16-bit colors of which there are 240x160 */ volatile unsigned short* screen = (volatile unsigned short*) 0x6000000; /* the display control pointer points to the gba graphics register */ volatile unsigned long* display_control = (volatile unsigned long*) 0x4000000; /* the address of the color palette used in graphics mode 4 */ volatile unsigned short* palette = (volatile unsigned short*) 0x5000000; /* pointers to the front and back buffers - the front buffer is the start * of the screen array and the back buffer is a pointer to the second half */ volatile unsigned short* front_buffer = (volatile unsigned short*) 0x6000000; volatile unsigned short* back_buffer = (volatile unsigned short*) 0x600A000; /* the button register holds the bits which indicate whether each button has * been pressed - this has got to be volatile as well */ volatile unsigned short* buttons = (volatile unsigned short*) 0x04000130; /* the scanline counter is a memory cell which is updated to indicate how * much of the screen has been drawn */ volatile unsigned short* scanline_counter = (volatile unsigned short*) 0x4000006; /* wait for the screen to be fully drawn so we can do something during vblank */ void wait_vblank() { /* wait until all 160 lines have been updated */ while (*scanline_counter < 160) { } } /* this function checks whether a particular button has been pressed */ unsigned char button_pressed(unsigned short button) { /* and the button register with the button constant we want */ unsigned short pressed = *buttons & button; /* if this value is zero, then it's not pressed */ if (pressed == 0) { return 1; } else { return 0; } } /* * function which adds a color to the palette and returns the * index to it */ unsigned char add_color(unsigned char r, unsigned char g, unsigned char b) { static int next_palette_index = 0; unsigned short color = b << 10; color += g << 5; color += r; /* add the color to the palette */ palette[next_palette_index] = color; /* increment the index */ next_palette_index++; /* return index of color just added */ return next_palette_index - 1; } /* put a pixel on the screen in mode 4 */ void put_pixel(volatile unsigned short* buffer, int row, int col, unsigned char color) { /* find the offset which is the regular offset divided by two */ unsigned short offset = (row * WIDTH + col) >> 1; /* read the existing pixel which is there */ unsigned short pixel = buffer[offset]; /* if it's an odd column */ if (col & 1) { /* put it in the left half of the short */ buffer[offset] = (color << 8) | (pixel & 0x00ff); } else { /* it's even, put it in the left half */ buffer[offset] = (pixel & 0xff00) | color; } } /* this function takes a video buffer and returns to you the other one */ volatile unsigned short* flip_buffers(volatile unsigned short* buffer) { /* if the back buffer is up, return that */ if(buffer == front_buffer) { /* clear back buffer bit and return back buffer pointer */ *display_control &= ~SHOW_BACK; return back_buffer; } else { /* set back buffer bit and return front buffer */ *display_control |= SHOW_BACK; return front_buffer; } } /* clear the screen to black */ void clear_screen(volatile unsigned short* buffer, unsigned short color) { unsigned short row, col; /* set each pixel black */ for (row = 0; row < HEIGHT; row++) { for (col = 0; col < WIDTH; col++) { put_pixel(buffer, row, col, color); } } }