-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgba.c
137 lines (119 loc) · 4.26 KB
/
gba.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#include "gba.h"
volatile unsigned short *videoBuffer = (volatile unsigned short *) 0x6000000;
u32 vBlankCounter = 0;
/*
Wait until the start of the next VBlank. This is useful to avoid tearing.
Completing this function is required.
*/
void waitForVBlank(void) {
while (SCANLINECOUNTER >= 160);
while (SCANLINECOUNTER != 160);
vBlankCounter++;
}
static int __qran_seed = 42;
static int qran(void) {
__qran_seed = 1664525 * __qran_seed + 1013904223;
return (__qran_seed >> 16) & 0x7FFF;
}
int randint(int min, int max) { return (qran() * (max - min) >> 15) + min; }
/*
Sets a pixel in the video buffer to a given color.
Using DMA is NOT recommended. (In fact, using DMA with this function would be really slow!)
*/
void setPixel(int row, int col, u16 color) {
videoBuffer[row * WIDTH + col] = color;
}
/*
Draws a rectangle of a given color to the video buffer.
The width and height, as well as the top left corner of the rectangle, are passed as parameters.
This function can be completed using `height` DMA calls.
*/
void drawRectDMA(int row, int col, int width, int height, volatile u16 color) {
DMA[3].src = &color;
for (int i = 0; i < height; ++i) {
DMA[3].dst = videoBuffer + ((row + i) * WIDTH + col);
DMA[3].cnt = DMA_ON | DMA_SOURCE_FIXED | DMA_DESTINATION_INCREMENT | width;
}
}
/*
Draws a fullscreen image to the video buffer.
The image passed in must be of size WIDTH * HEIGHT.
This function can be completed using a single DMA call.
*/
void drawFullScreenImageDMA(const u16 *image) {
DMA[3].src = image;
DMA[3].dst = videoBuffer;
DMA[3].cnt = DMA_ON | DMA_SOURCE_INCREMENT | DMA_DESTINATION_INCREMENT | (WIDTH*HEIGHT);
}
/*
Draws an image to the video buffer.
The width and height, as well as the top left corner of the image, are passed as parameters.
The image passed in must be of size width * height.
Completing this function is required.
This function can be completed using `height` DMA calls. Solutions that use more DMA calls will not get credit.
*/
void drawImageDMA(int row, int col, int width, int height, const u16 *image) {
for (int i = 0; i < height; ++i) {
DMA[3].src = image + (i * width);
DMA[3].dst = videoBuffer + ((row + i) * WIDTH + col);
DMA[3].cnt = DMA_ON | DMA_SOURCE_INCREMENT | DMA_DESTINATION_INCREMENT | width;
}
}
void drawImageFlippedDMA(int row, int col, int width, int height, const u16 *image) {
for (int i = 0; i < height; ++i) {
DMA[3].src = image + ((height - 1 - i) * width);
DMA[3].dst = videoBuffer + ((row + i) * WIDTH + col);
DMA[3].cnt = DMA_ON | DMA_SOURCE_INCREMENT | DMA_DESTINATION_INCREMENT | width;
}
}
/*
Draws a rectangular chunk of a fullscreen image to the video buffer.
The width and height, as well as the top left corner of the chunk to be drawn, are passed as parameters.
The image passed in must be of size WIDTH * HEIGHT.
This function can be completed using `height` DMA calls.
*/
void undrawImageDMA(int row, int col, int width, int height, const u16 *image) {
for (int i = 0; i < height; ++i) {
DMA[3].src = image + ((row + i) * WIDTH + col);
DMA[3].dst = videoBuffer + ((row + i) * WIDTH + col);
DMA[3].cnt = DMA_ON | DMA_SOURCE_INCREMENT | DMA_DESTINATION_INCREMENT | width;
}
}
/*
Fills the video buffer with a given color.
This function can be completed using a single DMA call.
*/
void fillScreenDMA(volatile u16 color) {
DMA[3].src = &color;
DMA[3].dst = videoBuffer;
DMA[3].cnt = DMA_ON | DMA_SOURCE_FIXED | DMA_DESTINATION_INCREMENT | (WIDTH*HEIGHT);
}
/* STRING-DRAWING FUNCTIONS (provided) */
void drawChar(int row, int col, char ch, u16 color) {
for (int i = 0; i < 6; i++) {
for (int j = 0; j < 8; j++) {
if (fontdata_6x8[OFFSET(j, i, 6) + ch * 48]) {
setPixel(row + j, col + i, color);
}
}
}
}
void drawString(int row, int col, char *str, u16 color) {
while (*str) {
drawChar(row, col, *str++, color);
col += 6;
}
}
void drawCenteredString(int row, int col, int width, int height, char *str, u16 color) {
u32 len = 0;
char *strCpy = str;
while (*strCpy) {
len++;
strCpy++;
}
u32 strWidth = 6 * len;
u32 strHeight = 8;
int new_row = row + ((height - strHeight) >> 1);
int new_col = col + ((width - strWidth) >> 1);
drawString(new_row, new_col, str, color);
}