Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
alexbevi
GitHub Repository: alexbevi/BizHawk
Path: blob/master/libsnes/bsnes/gameboy/lcd/cgb.cpp
2 views
1
#ifdef LCD_CPP
2
3
void LCD::cgb_render() {
4
for(unsigned n = 0; n < 160; n++) {
5
line[n] = 0x7fff;
6
origin[n] = Origin::None;
7
}
8
9
if(status.display_enable) {
10
cgb_render_bg();
11
if(status.window_display_enable) cgb_render_window();
12
if(status.ob_enable) cgb_render_ob();
13
}
14
15
uint16 *output = screen + status.ly * 160;
16
for(unsigned n = 0; n < 160; n++) output[n] = line[n];
17
interface->lcdScanline();
18
}
19
20
//Attributes:
21
//0x80: 0 = OAM priority, 1 = BG priority
22
//0x40: vertical flip
23
//0x20: horizontal flip
24
//0x08: VRAM bank#
25
//0x07: palette#
26
void LCD::cgb_read_tile(bool select, unsigned x, unsigned y, unsigned &tile, unsigned &attr, unsigned &data) {
27
unsigned tmaddr = 0x1800 + (select << 10);
28
tmaddr += (((y >> 3) << 5) + (x >> 3)) & 0x03ff;
29
30
tile = vram[0x0000 + tmaddr];
31
attr = vram[0x2000 + tmaddr];
32
33
unsigned tdaddr = attr & 0x08 ? 0x2000 : 0x0000;
34
if(status.bg_tiledata_select == 0) {
35
tdaddr += 0x1000 + ((int8)tile << 4);
36
} else {
37
tdaddr += 0x0000 + (tile << 4);
38
}
39
40
y &= 7;
41
if(attr & 0x40) y ^= 7;
42
tdaddr += y << 1;
43
44
data = vram[tdaddr++] << 0;
45
data |= vram[tdaddr++] << 8;
46
if(attr & 0x20) data = hflip(data);
47
}
48
49
void LCD::cgb_render_bg() {
50
unsigned iy = (status.ly + status.scy) & 255;
51
unsigned ix = status.scx, tx = ix & 7;
52
53
unsigned tile, attr, data;
54
cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data);
55
56
for(unsigned ox = 0; ox < 160; ox++) {
57
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
58
| ((data & (0x8000 >> tx)) ? 2 : 0);
59
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
60
unsigned palette = 0;
61
palette |= bgpd[palette_index++] << 0;
62
palette |= bgpd[palette_index++] << 8;
63
palette &= 0x7fff;
64
65
line[ox] = palette;
66
origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG);
67
68
ix = (ix + 1) & 255;
69
tx = (tx + 1) & 7;
70
if(tx == 0) cgb_read_tile(status.bg_tilemap_select, ix, iy, tile, attr, data);
71
}
72
}
73
74
void LCD::cgb_render_window() {
75
if(status.ly - status.wy >= 144u) return;
76
if(status.wx >= 167u) return;
77
unsigned iy = status.wyc++;
78
unsigned ix = (7 - status.wx) & 255, tx = ix & 7;
79
80
unsigned tile, attr, data;
81
cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data);
82
83
for(unsigned ox = 0; ox < 160; ox++) {
84
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
85
| ((data & (0x8000 >> tx)) ? 2 : 0);
86
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
87
unsigned palette = 0;
88
palette |= bgpd[palette_index++] << 0;
89
palette |= bgpd[palette_index++] << 8;
90
palette &= 0x7fff;
91
92
if(ox - (status.wx - 7) < 160u) {
93
line[ox] = palette;
94
origin[ox] = (attr & 0x80 ? Origin::BGP : Origin::BG);
95
}
96
97
ix = (ix + 1) & 255;
98
tx = (tx + 1) & 7;
99
if(tx == 0) cgb_read_tile(status.window_tilemap_select, ix, iy, tile, attr, data);
100
}
101
}
102
103
//Attributes:
104
//0x80: 0 = OBJ above BG, 1 = BG above OBJ
105
//0x40: vertical flip
106
//0x20: horizontal flip
107
//0x08: VRAM bank#
108
//0x07: palette#
109
void LCD::cgb_render_ob() {
110
const unsigned Height = (status.ob_size == 0 ? 8 : 16);
111
unsigned sprite[10], sprites = 0;
112
113
//find first ten sprites on this scanline
114
for(unsigned s = 0; s < 40; s++) {
115
unsigned sy = oam[(s << 2) + 0] - 16;
116
unsigned sx = oam[(s << 2) + 1] - 8;
117
118
sy = status.ly - sy;
119
if(sy >= Height) continue;
120
121
sprite[sprites++] = s;
122
if(sprites == 10) break;
123
}
124
125
//sort by X-coordinate, when equal, lower address comes first
126
for(unsigned x = 0; x < sprites; x++) {
127
for(unsigned y = x + 1; y < sprites; y++) {
128
signed sx = oam[(sprite[x] << 2) + 1] - 8;
129
signed sy = oam[(sprite[y] << 2) + 1] - 8;
130
if(sy < sx) {
131
sprite[x] ^= sprite[y];
132
sprite[y] ^= sprite[x];
133
sprite[x] ^= sprite[y];
134
}
135
}
136
}
137
138
//render backwards, so that first sprite has highest priority
139
for(signed s = sprites - 1; s >= 0; s--) {
140
unsigned n = sprite[s] << 2;
141
unsigned sy = oam[n + 0] - 16;
142
unsigned sx = oam[n + 1] - 8;
143
unsigned tile = oam[n + 2] & ~status.ob_size;
144
unsigned attr = oam[n + 3];
145
146
sy = status.ly - sy;
147
if(sy >= Height) continue;
148
if(attr & 0x40) sy ^= (Height - 1);
149
150
unsigned tdaddr = (attr & 0x08 ? 0x2000 : 0x0000) + (tile << 4) + (sy << 1), data = 0;
151
data |= vram[tdaddr++] << 0;
152
data |= vram[tdaddr++] << 8;
153
if(attr & 0x20) data = hflip(data);
154
155
for(unsigned tx = 0; tx < 8; tx++) {
156
unsigned index = ((data & (0x0080 >> tx)) ? 1 : 0)
157
| ((data & (0x8000 >> tx)) ? 2 : 0);
158
if(index == 0) continue;
159
160
unsigned palette_index = ((attr & 0x07) << 3) + (index << 1);
161
unsigned palette = 0;
162
palette |= obpd[palette_index++] << 0;
163
palette |= obpd[palette_index++] << 8;
164
palette &= 0x7fff;
165
166
unsigned ox = sx + tx;
167
168
if(ox < 160) {
169
//When LCDC.D0 (BG enable) is off, OB is always rendered above BG+Window
170
if(status.bg_enable) {
171
if(origin[ox] == Origin::BGP) continue;
172
if(attr & 0x80) {
173
if(origin[ox] == Origin::BG || origin[ox] == Origin::BGP) {
174
if(line[ox] > 0) continue;
175
}
176
}
177
}
178
line[ox] = palette;
179
origin[ox] = Origin::OB;
180
}
181
}
182
}
183
}
184
185
#endif
186
187