diff options
Diffstat (limited to 'src/uxn/devices/ppu.c')
-rw-r--r-- | src/uxn/devices/ppu.c | 163 |
1 files changed, 90 insertions, 73 deletions
diff --git a/src/uxn/devices/ppu.c b/src/uxn/devices/ppu.c index 60ede0a..97b5e4f 100644 --- a/src/uxn/devices/ppu.c +++ b/src/uxn/devices/ppu.c | |||
@@ -143,9 +143,9 @@ static Uint32 unpack_icon_lut_flipx[256] = { | |||
143 | }; | 143 | }; |
144 | 144 | ||
145 | EWRAM_BSS | 145 | EWRAM_BSS |
146 | static u32 *backbuffer_bg0[30 * 20 * sizeof(Tile) / 4]; | 146 | static u32 *backbuffer_bg0[32 * 20 * sizeof(Tile) / 4]; |
147 | EWRAM_BSS | 147 | EWRAM_BSS |
148 | static u32 *backbuffer_bg1[30 * 20 * sizeof(Tile) / 4]; | 148 | static u32 *backbuffer_bg1[32 * 20 * sizeof(Tile) / 4]; |
149 | static u32 dirty_tiles[20] = {0}; | 149 | static u32 dirty_tiles[20] = {0}; |
150 | 150 | ||
151 | void | 151 | void |
@@ -173,7 +173,7 @@ putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { | |||
173 | size_t tile_y = y / 8; | 173 | size_t tile_y = y / 8; |
174 | size_t start_col = x % 8; | 174 | size_t start_col = x % 8; |
175 | size_t start_row = y % 8; | 175 | size_t start_row = y % 8; |
176 | size_t pos = (start_row + ((tile_x + tile_y * 30) * 8)); | 176 | size_t pos = (start_row + ((tile_x + tile_y * 32) * 8)); |
177 | size_t shift = start_col * 4; | 177 | size_t shift = start_col * 4; |
178 | layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); | 178 | layer[pos] = (layer[pos] & (~(0xF << shift))) | (color << shift); |
179 | dirty_tiles[tile_y] |= 1 << tile_x; | 179 | dirty_tiles[tile_y] |= 1 << tile_x; |
@@ -181,77 +181,96 @@ putpixel(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 color) { | |||
181 | 181 | ||
182 | IWRAM_CODE | 182 | IWRAM_CODE |
183 | void | 183 | void |
184 | puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, | 184 | puticn(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, Uint8 flipx, Uint8 flipy) { |
185 | Uint8 flipx, Uint8 flipy) { | 185 | Uint8 sprline; |
186 | if(x >= 30 * 8 || y >= 20 * 8) { | 186 | Uint8 xrightedge = x < ((32 - 1) * 8); |
187 | return; | 187 | Uint16 v; |
188 | } | 188 | Uint32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); |
189 | size_t tile_x = x / 8; | ||
190 | size_t tile_y = y / 8; | ||
191 | size_t start_col = x % 8; | ||
192 | size_t start_row = y % 8; | ||
193 | size_t shift_left = start_col * 4; | ||
194 | size_t shift_right = (8 - start_col) * 4; | ||
195 | 189 | ||
196 | if (flipy) { | 190 | Uint32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); |
197 | flipy = 7; | 191 | Uint32 *layerptr = &layer[layerpos]; |
198 | } | 192 | Uint32 shift = (x & 7) << 2; |
193 | Uint32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; | ||
199 | 194 | ||
200 | size_t pos = (start_row + ((tile_x + tile_y * 30) * 8)); | 195 | if (flipy) flipy = 7; |
201 | size_t *layer_ptr = &layer[pos]; | 196 | |
202 | size_t *lut = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; | 197 | if (x >= 240 || y >= 160) return; |
203 | 198 | ||
204 | // There are 4 possible cases: | 199 | if (color != 0x05 && color != 0x0a && color != 0x0f) { |
205 | // 1. The sprite is exactly at the tile boundary. We can just copy the | 200 | u64 mask = ~((u64)0xFFFFFFFF << shift); |
206 | // tile directly to memory. | 201 | |
207 | // 2. The sprite covers 2 tiles horizontally. | 202 | for (v = 0; v < 8; v++, layerptr++) { |
208 | // 3. The sprite covers 2 tiles vertically. | 203 | if ((y + v) >= 160) break; |
209 | // 4. The sprite covers 4 tiles. | 204 | |
210 | if (start_row == 0 && start_col == 0) { | 205 | sprline = sprite[v ^ flipy]; |
211 | for (size_t i = 0; i < 8; ++i) { | 206 | u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; |
212 | layer_ptr[i] = lut[sprite[i ^ flipy]] * color; | 207 | data |= (u64)(lut_expand[sprline ^ 0xFF] * (color >> 2)) << shift; |
213 | } | 208 | |
214 | dirty_tiles[tile_y] |= 1 << tile_x; | 209 | layerptr[0] = (layerptr[0] & mask) | data; |
215 | } else { | 210 | if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); |
216 | u32 row_mask = 0xFFFFFFFF << shift_left; | 211 | |
217 | for (size_t i = 0; i < (8 - start_row); ++i) { | 212 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; |
218 | u32 sprite_row = lut[sprite[i ^ flipy]] * color; | 213 | } |
219 | layer_ptr[0] = (layer_ptr[0] & ~row_mask) | (sprite_row << shift_left); | 214 | } else { |
220 | layer_ptr[8] = (layer_ptr[8] & row_mask) | (sprite_row >> shift_right); | 215 | for (v = 0; v < 8; v++, layerptr++) { |
221 | layer_ptr++; | 216 | if ((y + v) >= 160) break; |
222 | } | 217 | |
223 | layer_ptr += 8 * 29; | 218 | sprline = sprite[v ^ flipy]; |
224 | for (size_t i = (8 - start_row); i < 8; ++i) { | 219 | u64 mask = ~((u64)(lut_expand[sprline] * 0xF) << shift); |
225 | u32 sprite_row = lut[sprite[i ^ flipy]] * color; | 220 | u64 data = (u64)(lut_expand[sprline] * (color & 3)) << shift; |
226 | layer_ptr[0] = (layer_ptr[0] & ~row_mask) | (sprite_row << shift_left); | 221 | |
227 | layer_ptr[8] = (layer_ptr[8] & row_mask) | (sprite_row >> shift_right); | 222 | layerptr[0] = (layerptr[0] & mask) | data; |
228 | layer_ptr++; | 223 | if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); |
229 | } | 224 | |
230 | dirty_tiles[tile_y] |= 1 << tile_x; | 225 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; |
231 | dirty_tiles[tile_y] |= 1 << (tile_x + 1); | 226 | } |
232 | dirty_tiles[tile_y + 1] |= 1 << tile_x; | 227 | } |
233 | dirty_tiles[tile_y + 1] |= 1 << (tile_x + 1); | 228 | |
234 | } | 229 | dirty_tiles[y >> 3] |= dirtyflag; |
230 | dirty_tiles[(y + 7) >> 3] |= dirtyflag; | ||
235 | } | 231 | } |
236 | 232 | ||
237 | IWRAM_CODE | 233 | IWRAM_CODE |
238 | void | 234 | void |
239 | putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, | 235 | putchr(Ppu *p, Uint32 *layer, Uint16 x, Uint16 y, Uint8 *sprite, Uint8 color, |
240 | Uint8 flipx, Uint8 flipy) { | 236 | Uint8 flipx, Uint8 flipy) { |
241 | if(x >= 30 * 8 || y >= 20 * 8) { | 237 | Uint8 sprline1, sprline2; |
242 | return; | 238 | Uint8 xrightedge = x < ((32 - 1) * 8); |
243 | } | 239 | Uint16 v; |
244 | Uint16 v, h; | 240 | Uint32 dirtyflag = (1 << (x >> 3)) | (1 << ((x + 7) >> 3)); |
245 | for(v = 0; v < 8; v++) | 241 | |
246 | for(h = 0; h < 8; h++) { | 242 | Uint32 layerpos = ((y & 7) + (((x >> 3) + (y >> 3) * 32) * 8)); |
247 | Uint8 ch1 = ((sprite[v] >> (7 - h)) & 0x1) * color; | 243 | Uint32 *layerptr = &layer[layerpos]; |
248 | Uint8 ch2 = ((sprite[v + 8] >> (7 - h)) & 0x1) * color; | 244 | Uint32 shift = (x & 7) << 2; |
249 | putpixel(p, | 245 | Uint32 *lut_expand = flipx ? unpack_icon_lut : unpack_icon_lut_flipx; |
250 | layer, | 246 | |
251 | x + (flipx ? 7 - h : h), | 247 | if (flipy) flipy = 7; |
252 | y + (flipy ? 7 - v : v), | 248 | |
253 | (((ch1 + ch2 * 2) + color / 4) & 0x3)); | 249 | if (x >= 240 || y >= 160) return; |
254 | } | 250 | |
251 | u64 mask = ~((u64)0xFFFFFFFF << shift); | ||
252 | u32 colconst = (color >> 2) * 0x11111111; | ||
253 | |||
254 | for (v = 0; v < 8; v++, layerptr++) { | ||
255 | if ((y + v) >= 160) break; | ||
256 | |||
257 | sprline1 = sprite[v ^ flipy]; | ||
258 | sprline2 = sprite[(v ^ flipy) | 8]; | ||
259 | |||
260 | u32 data32 = | ||
261 | (lut_expand[sprline1] * (color & 3)) | ||
262 | + (lut_expand[sprline2] * ((color & 1) << 1)) | ||
263 | + colconst; | ||
264 | u64 data = ((u64) (data32 & 0x33333333)) << shift; | ||
265 | |||
266 | layerptr[0] = (layerptr[0] & mask) | data; | ||
267 | if (xrightedge) layerptr[8] = (layerptr[8] & (mask >> 32)) | (data >> 32); | ||
268 | |||
269 | if (((y + v) & 7) == 7) layerptr += (32 - 1) * 8; | ||
270 | } | ||
271 | |||
272 | dirty_tiles[y >> 3] |= dirtyflag; | ||
273 | dirty_tiles[(y + 7) >> 3] |= dirtyflag; | ||
255 | } | 274 | } |
256 | 275 | ||
257 | IWRAM_CODE | 276 | IWRAM_CODE |
@@ -269,8 +288,8 @@ flipbuf(Ppu *p) { | |||
269 | if (dirty_tiles[j] & k) { | 288 | if (dirty_tiles[j] & k) { |
270 | Tile *tile_fg = p->fg; | 289 | Tile *tile_fg = p->fg; |
271 | Tile *tile_bg = p->bg; | 290 | Tile *tile_bg = p->bg; |
272 | mem_fg[i + j * 30] = tile_fg[i + j * 30]; | 291 | mem_fg[i + j * 32] = tile_fg[i + j * 32]; |
273 | mem_bg[i + j * 30] = tile_bg[i + j * 30]; | 292 | mem_bg[i + j * 32] = tile_bg[i + j * 32]; |
274 | } | 293 | } |
275 | } | 294 | } |
276 | dirty_tiles[j] = 0; | 295 | dirty_tiles[j] = 0; |
@@ -298,7 +317,7 @@ initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { | |||
298 | // Clear tile memory. | 317 | // Clear tile memory. |
299 | p->fg = backbuffer_bg0; | 318 | p->fg = backbuffer_bg0; |
300 | p->bg = backbuffer_bg1; | 319 | p->bg = backbuffer_bg1; |
301 | for (size_t i = 0; i < 30 * 20 * 8; ++i) { | 320 | for (size_t i = 0; i < 32 * 20 * 8; ++i) { |
302 | p->fg[i] = 0; | 321 | p->fg[i] = 0; |
303 | p->bg[i] = 0; | 322 | p->bg[i] = 0; |
304 | } | 323 | } |
@@ -312,10 +331,8 @@ initppu(Ppu *p, Uint8 hor, Uint8 ver, Uint8 pad) { | |||
312 | // Initialize memory map. | 331 | // Initialize memory map. |
313 | u16 *mem_map = SCREENBLOCK_MEM[sb_idx]; | 332 | u16 *mem_map = SCREENBLOCK_MEM[sb_idx]; |
314 | size_t k = 0; | 333 | size_t k = 0; |
315 | for (size_t j = 0; j < 20; ++j) { | 334 | for (size_t i = 0; i < 32 * 20; ++i, ++k) { |
316 | for (size_t i = 0; i < 30; ++i, ++k) { | 335 | mem_map[i] = k; |
317 | mem_map[i + j * 32] = k; | ||
318 | } | ||
319 | } | 336 | } |
320 | 337 | ||
321 | return 1; | 338 | return 1; |