oamSet takes x coordinates in range 0..255, but their actual range is -255..255. The most significant (sign) bit lies in the upper 32 bytes of OAM.
(Note that -256 doesn't work correctly in hardware and therefore shouldn't be used).
Code would be something similar to this (note: not "optimized", also: C99/C++)
Code: Select all
void oamSetXY_fixed(unsigned int id, unsigned int x, unsigned char y) {
const OAM_HI_TABLE_START = 128*4;
// Set low byte of x position and y position:
unsigned char x_lo = (unsigned char)x;
oamSetXY(id,x,y);
// Note that id isn't the OAM id, but a direct index into OAM shadow memory;
// the result is that id/4 is the actual oam index, which is required for determining
// the OAM high table position.
unsigned char oam_id = (unsigned char)(id >> 2);
// Set highest bit of x position: Either at bit 0,2,4,6 depending on oam id,
// as 4 oam entries are merged into one byte of the OAM high table.
int bit_shift = 2*(oam_id % 4);
int in_byte_position = 1 << bit_shift;
int oam_high_table_pos = OAM_HI_TABLE_START + oam_id / 4;
oamMemory[oam_high_table_pos] &= ~in_byte_position; // Clear current high bit of x
oamMemory[oam_high_table_pos] |= (x>>8)<<bit_shift; // Fill in new high bit of x
}
In fact, after looking at the oamInit code, it is another bug in the library: It sets the x position of every entry to (you probably guessed it) -256.
Since I'm already writing so much, I'll explain the curious behavior, too: If I recall correctly, sprites with x=-256 aren't displayed (as their x position is far too small), but due to a bug in the PPU they are considered on screen! They each take up a sprite slot, which has a hardware-based hard limit of 32, i.e. no more than 32 8x8 sprite tiles can be displayed per line. Since all sprites you didn't set to x=-255 are considered on the first 8 lines for sprite display, your sprite gets dropped. Manually setting all sprite positions to x=-255 should fix this.
Please excuse any errors, my last clash with the SNES was several years ago
