tangled
alpha
login
or
join now
baileytownsend.dev
/
DMG-Playground
0
fork
atom
Playing around with reading gameboy roms, and maybe emulation
0
fork
atom
overview
issues
pulls
pipelines
wip
baileytownsend.dev
7 months ago
ebe556d1
dcbe1c72
+126
-49
2 changed files
expand all
collapse all
unified
split
src
main.rs
tile_map.rs
+1
-2
src/main.rs
···
96
96
)
97
97
.unwrap();
98
98
let mut tile_ids: Vec<u8> = (0..100).collect();
99
99
-
let tile_map_buffer = gpu.render_tile_map(&tile_ids, 166, 144);
100
100
-
// let idk = gpu.render_tile_to_rgb(1).unwrap();
99
99
+
let tile_map_buffer = gpu.render_background_to_rgb(true, true, 25, 25); // let idk = gpu.render_tile_to_rgb(1).unwrap();
101
100
let buffer_u32: Vec<u32> = tile_map_buffer
102
101
.iter()
103
102
.map(|(r, g, b)| ((*r as u32) << 16) | ((*g as u32) << 8) | (*b as u32))
+125
-47
src/tile_map.rs
···
2
2
pub const VRAM_END: usize = 0x9FFF;
3
3
pub const VRAM_SIZE: usize = VRAM_END - VRAM_BEGIN + 1;
4
4
5
5
+
// Tilemap locations in VRAM
6
6
+
pub const TILEMAP_0_START: usize = 0x1800; // $9800 - $8000 = 0x1800
7
7
+
pub const TILEMAP_1_START: usize = 0x1C00; // $9C00 - $8000 = 0x1C00
8
8
+
pub const TILEMAP_SIZE: usize = 32 * 32; // 1024 bytes
9
9
+
5
10
#[derive(Copy, Clone, Debug, PartialEq)]
6
11
pub enum TilePixelValue {
7
12
Zero,
···
102
107
}
103
108
}
104
109
105
105
-
/// Get a tile by its index
106
106
-
pub fn get_tile(&self, tile_index: usize) -> Option<&Tile> {
107
107
-
if tile_index < self.tile_set.len() {
108
108
-
Some(&self.tile_set[tile_index])
110
110
+
/// Get a tile by its index, handling Game Boy's two addressing modes
111
111
+
pub fn get_tile(&self, tile_index: u8, use_signed_addressing: bool) -> Option<&Tile> {
112
112
+
let actual_index = if use_signed_addressing {
113
113
+
// Signed addressing mode: $8800-$97FF
114
114
+
// Index 0-127 maps to tiles 256-383, index 128-255 maps to tiles 0-127
115
115
+
if tile_index < 128 {
116
116
+
256 + tile_index as usize
117
117
+
} else {
118
118
+
(tile_index as i8 as i16 + 256) as usize
119
119
+
}
120
120
+
} else {
121
121
+
// Unsigned addressing mode: $8000-$8FFF
122
122
+
tile_index as usize
123
123
+
};
124
124
+
125
125
+
if actual_index < self.tile_set.len() {
126
126
+
Some(&self.tile_set[actual_index])
109
127
} else {
110
128
None
111
129
}
112
130
}
113
131
114
114
-
/// Render a tile to a color buffer (64 pixels as RGB values)
115
115
-
pub fn render_tile_to_rgb(&self, tile_index: usize) -> Option<[(u8, u8, u8); 64]> {
116
116
-
let tile = self.get_tile(tile_index)?;
117
117
-
let mut color_buffer = [(0, 0, 0); 64];
132
132
+
/// Read tilemap data from VRAM
133
133
+
pub fn get_tilemap_data(&self, tilemap_select: bool) -> [u8; TILEMAP_SIZE] {
134
134
+
let start_addr = if tilemap_select {
135
135
+
TILEMAP_1_START
136
136
+
} else {
137
137
+
TILEMAP_0_START
138
138
+
};
118
139
119
119
-
for (row_idx, row) in tile.iter().enumerate() {
120
120
-
for (col_idx, &pixel) in row.iter().enumerate() {
121
121
-
let buffer_index = row_idx * 8 + col_idx;
122
122
-
color_buffer[buffer_index] = pixel.to_gameboy_green();
123
123
-
}
140
140
+
let mut tilemap = [0u8; TILEMAP_SIZE];
141
141
+
for i in 0..TILEMAP_SIZE {
142
142
+
tilemap[i] = self.vram[start_addr + i];
124
143
}
125
125
-
126
126
-
Some(color_buffer)
144
144
+
tilemap
127
145
}
128
146
129
129
-
/// Render a tile to grayscale buffer (64 pixels as grayscale values)
130
130
-
pub fn render_tile_to_grayscale(&self, tile_index: usize) -> Option<[u8; 64]> {
131
131
-
let tile = self.get_tile(tile_index)?;
132
132
-
let mut gray_buffer = [0u8; 64];
147
147
+
/// Render the entire tilemap to RGB (256x256 pixels)
148
148
+
pub fn render_full_tilemap_to_rgb(
149
149
+
&self,
150
150
+
tilemap_select: bool,
151
151
+
use_signed_addressing: bool,
152
152
+
) -> Vec<(u8, u8, u8)> {
153
153
+
let tilemap_data = self.get_tilemap_data(tilemap_select);
154
154
+
let total_pixels = 256 * 256; // 32x32 tiles, each 8x8 pixels
155
155
+
let mut color_buffer = vec![(0, 0, 0); total_pixels];
133
156
134
134
-
for (row_idx, row) in tile.iter().enumerate() {
135
135
-
for (col_idx, &pixel) in row.iter().enumerate() {
136
136
-
let buffer_index = row_idx * 8 + col_idx;
137
137
-
gray_buffer[buffer_index] = pixel.to_grayscale();
157
157
+
for tilemap_y in 0..32 {
158
158
+
for tilemap_x in 0..32 {
159
159
+
let tilemap_index = tilemap_y * 32 + tilemap_x;
160
160
+
let tile_id = tilemap_data[tilemap_index];
161
161
+
162
162
+
if let Some(tile) = self.get_tile(tile_id, use_signed_addressing) {
163
163
+
// Render this tile into the color buffer
164
164
+
for tile_row in 0..8 {
165
165
+
for tile_col in 0..8 {
166
166
+
let pixel_x = tilemap_x * 8 + tile_col;
167
167
+
let pixel_y = tilemap_y * 8 + tile_row;
168
168
+
let buffer_index = pixel_y * 256 + pixel_x;
169
169
+
170
170
+
if buffer_index < color_buffer.len() {
171
171
+
color_buffer[buffer_index] =
172
172
+
tile[tile_row][tile_col].to_gameboy_green();
173
173
+
}
174
174
+
}
175
175
+
}
176
176
+
}
138
177
}
139
178
}
140
179
141
141
-
Some(gray_buffer)
180
180
+
color_buffer
142
181
}
143
182
144
144
-
/// Render multiple tiles in a grid pattern
145
145
-
pub fn render_tile_map(
183
183
+
/// Render a visible portion of the tilemap (160x144 pixels) with scrolling
184
184
+
pub fn render_background_to_rgb(
146
185
&self,
147
147
-
tile_indices: &[u8],
148
148
-
map_width: usize,
149
149
-
map_height: usize,
186
186
+
tilemap_select: bool,
187
187
+
use_signed_addressing: bool,
188
188
+
scroll_x: u8,
189
189
+
scroll_y: u8,
150
190
) -> Vec<(u8, u8, u8)> {
151
151
-
let total_pixels = map_width * 8 * map_height * 8; // 8x8 pixels per tile
152
152
-
let mut color_buffer = vec![(0, 0, 0); total_pixels];
191
191
+
let tilemap_data = self.get_tilemap_data(tilemap_select);
192
192
+
let mut color_buffer = vec![(0, 0, 0); 160 * 144];
193
193
+
194
194
+
for screen_y in 0..144 {
195
195
+
for screen_x in 0..160 {
196
196
+
// Calculate the position in the 256x256 tilemap with wrapping
197
197
+
let bg_x = ((screen_x as u16 + scroll_x as u16) % 256) as u8;
198
198
+
let bg_y = ((screen_y as u16 + scroll_y as u16) % 256) as u8;
153
199
154
154
-
for (map_idx, &tile_idx) in tile_indices.iter().enumerate() {
155
155
-
if let Some(tile) = self.get_tile(tile_idx as usize) {
156
156
-
let tile_x = map_idx % map_width;
157
157
-
let tile_y = map_idx / map_width;
200
200
+
// Which tile are we in?
201
201
+
let tile_x = (bg_x / 8) as usize;
202
202
+
let tile_y = (bg_y / 8) as usize;
203
203
+
let tilemap_index = tile_y * 32 + tile_x;
158
204
159
159
-
for (row_idx, row) in tile.iter().enumerate() {
160
160
-
for (col_idx, &pixel) in row.iter().enumerate() {
161
161
-
let pixel_x = tile_x * 8 + col_idx;
162
162
-
let pixel_y = tile_y * 8 + row_idx;
163
163
-
let buffer_index = pixel_y * (map_width * 8) + pixel_x;
205
205
+
// Which pixel within that tile?
206
206
+
let pixel_x = (bg_x % 8) as usize;
207
207
+
let pixel_y = (bg_y % 8) as usize;
164
208
165
165
-
if buffer_index < color_buffer.len() {
166
166
-
color_buffer[buffer_index] = pixel.to_gameboy_green();
167
167
-
}
168
168
-
}
209
209
+
let tile_id = tilemap_data[tilemap_index];
210
210
+
211
211
+
if let Some(tile) = self.get_tile(tile_id, use_signed_addressing) {
212
212
+
let buffer_index = screen_y * 160 + screen_x;
213
213
+
color_buffer[buffer_index] = tile[pixel_y][pixel_x].to_gameboy_green();
169
214
}
170
215
}
171
216
}
···
173
218
color_buffer
174
219
}
175
220
221
221
+
/// Render a tile to a color buffer (64 pixels as RGB values)
222
222
+
pub fn render_tile_to_rgb(&self, tile_index: usize) -> Option<[(u8, u8, u8); 64]> {
223
223
+
if tile_index >= self.tile_set.len() {
224
224
+
return None;
225
225
+
}
226
226
+
227
227
+
let tile = &self.tile_set[tile_index];
228
228
+
let mut color_buffer = [(0, 0, 0); 64];
229
229
+
230
230
+
for (row_idx, row) in tile.iter().enumerate() {
231
231
+
for (col_idx, &pixel) in row.iter().enumerate() {
232
232
+
let buffer_index = row_idx * 8 + col_idx;
233
233
+
color_buffer[buffer_index] = pixel.to_gameboy_green();
234
234
+
}
235
235
+
}
236
236
+
237
237
+
Some(color_buffer)
238
238
+
}
239
239
+
240
240
+
/// Debug function to print tilemap as hex values
241
241
+
pub fn print_tilemap_hex(&self, tilemap_select: bool) {
242
242
+
let tilemap_data = self.get_tilemap_data(tilemap_select);
243
243
+
println!("Tilemap {} contents:", if tilemap_select { 1 } else { 0 });
244
244
+
245
245
+
for row in 0..32 {
246
246
+
for col in 0..32 {
247
247
+
let index = row * 32 + col;
248
248
+
print!("{:02X} ", tilemap_data[index]);
249
249
+
}
250
250
+
println!();
251
251
+
}
252
252
+
}
253
253
+
176
254
/// Debug function to print a tile as ASCII art
177
255
pub fn print_tile_ascii(&self, tile_index: usize) {
178
178
-
if let Some(tile) = self.get_tile(tile_index) {
179
179
-
// println!("Tile {}:", tile_index);
256
256
+
if let Some(tile) = self.tile_set.get(tile_index) {
257
257
+
println!("Tile {}:", tile_index);
180
258
for row in tile {
181
259
for &pixel in row {
182
260
let char = match pixel {
···
187
265
};
188
266
print!("{}", char);
189
267
}
190
190
-
// println!();
268
268
+
println!();
191
269
}
192
270
} else {
193
271
println!("Tile {} not found", tile_index);