@@ -74,7 +74,7 @@ void ksNesDrawClearEFBFirst(ksNesCommonWorkObj* wp) {
7474 GXClearVtxDesc ();
7575 GXSetVtxDesc (GX_VA_POS, GX_DIRECT);
7676 GXSetVtxDesc (GX_VA_CLR0, GX_DIRECT);
77- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4 , 0 );
77+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16 , 0 );
7878 GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
7979 GXSetCurrentMtx (0 );
8080 GXLoadPosMtxImm (wp->draw_ctx .draw_mtx , 0 );
@@ -366,9 +366,9 @@ void ksNesDrawBG(ksNesCommonWorkObj* wp, ksNesStateObj* sp) {
366366 GXSetVtxDesc (GX_VA_POS, GX_DIRECT);
367367 GXSetVtxDesc (GX_VA_CLR0, GX_DIRECT);
368368 GXSetVtxDesc (GX_VA_TEX0, GX_DIRECT);
369- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4 , 0 );
369+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16 , 0 );
370370 GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
371- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBX8 , 10 );
371+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_S, GX_U16 , 10 );
372372 GXInitTexObj (&obj0, wp->draw_ctx .bg_palette_attr_texture , 40 , 256 , GX_TF_I4, GX_CLAMP, GX_REPEAT, 0 );
373373 GXInitTexObjLOD (&obj0, GX_NEAR, GX_NEAR, 0.0 , 0.0 , 0.0 , 0 , 0 , GX_ANISO_1);
374374 GXLoadTexObj (&obj0, GX_TEXMAP0);
@@ -478,7 +478,7 @@ void ksNesDrawBG(ksNesCommonWorkObj* wp, ksNesStateObj* sp) {
478478 GXClearVtxDesc ();
479479 GXSetVtxDesc (GX_VA_POS, GX_DIRECT);
480480 GXSetVtxDesc (GX_VA_CLR0, GX_DIRECT);
481- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4 , 0 );
481+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16 , 0 );
482482 GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
483483 GXSetTevDirect (GX_TEVSTAGE0);
484484 GXSetTevOrder (GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0);
@@ -577,11 +577,21 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
577577 wp->draw_ctx .sprite_scanline_limit [i] = i < KS_NES_SCANLINE_COUNT ? ((state->frame_flags & KS_NES_FLAG_NINES_OVER_MODE) ? 255 : KS_NES_SPRITES_PER_SCANLINE) : 0 ;
578578
579579 // Disable sprites if the ppu's config on this scanline doesn't have sprites enabled.
580+ // @BUG - ppu_scanline_regs only has 240 entries, but this loop iterates 272 times.
581+ // When i >= 240, this reads 32 bytes past the array into OAMTable memory,
582+ // treating random OAM data as PPU mask flags to decide if sprites should be disabled.
583+ #ifndef BUGFIXES
580584 if ((wp->draw_ctx .ppu_scanline_regs [i].ppumask_flags & KS_NES_PPU_MASK_SHOW_SPRITES) == 0 ) {
581585 wp->draw_ctx .sprite_scanline_limit [i] = 0 ;
582586 }
587+ #else
588+ if (i < KS_NES_SCANLINE_COUNT && (wp->draw_ctx .ppu_scanline_regs [i].ppumask_flags & KS_NES_PPU_MASK_SHOW_SPRITES) == 0 ) {
589+ wp->draw_ctx .sprite_scanline_limit [i] = 0 ;
590+ }
591+ #endif
583592 }
584593
594+
585595 if (state->prg_size == 0x40000 && memcmp (state->prgromp + 0x3ffe9 , " MARIO 3" , 7 ) == 0 ) {
586596 for (i = 0 ; i < ARRAY_COUNT (wp->draw_ctx .ppu_scanline_regs ); i++) {
587597 // This is a hack for SMB3 where the emulator was drawing sprites (OBJ) on transition screens because
@@ -599,42 +609,47 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
599609 int a;
600610 int _j;
601611 ksNesSpriteQuadData* quad_p = wp->draw_ctx .sprite_quad_data ;
612+ int idx2;
602613
614+ idx2 = 0 ;
603615 for (i = 0 ; i < 0x100 ; i += 4 ) {
604616 _j = 8 ; // 8x8 sprite
605- if (wp->draw_ctx .ppu_scanline_regs [wp->draw_ctx .OAMTable [i]. y_pos ].ppu_ctrl & KS_NES_PPU_CTRL_SPRITE_SIZE) {
617+ if (wp->draw_ctx .ppu_scanline_regs [((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + i))-> y_pos ].ppu_ctrl & KS_NES_PPU_CTRL_SPRITE_SIZE) {
606618 _j = 16 ; // 8x16 sprite
607619 }
608620 a = 0 ;
609- if (wp->draw_ctx .OAMTable [i]. attributes & KS_NES_OAM_ATTR_FLIP_VERTICAL) {
621+ if (((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + i))-> attributes & KS_NES_OAM_ATTR_FLIP_VERTICAL) {
610622 b = _j << 2 ;
611623 _c = -4 ;
612624 } else {
613625 b = 0 ;
614626 _c = 4 ;
615627 }
616628 for (j = 0 ; j < _j; j++) {
617- if (wp->draw_ctx .sprite_scanline_limit [wp->draw_ctx .OAMTable [i].y_pos + j] != 0 ) {
618- wp->draw_ctx .sprite_scanline_limit [wp->draw_ctx .OAMTable [i].y_pos + j]--;
629+ u32 ypos = ((ksNesOAMEntry*)((u8 *)wp->draw_ctx .OAMTable + i))->y_pos ;
630+ ypos += j;
631+ if (wp->draw_ctx .sprite_scanline_limit [((ksNesOAMEntry*)((u8 *)wp->draw_ctx .OAMTable + i))->y_pos + j] != 0 ) {
632+ wp->draw_ctx .sprite_scanline_limit [((ksNesOAMEntry*)((u8 *)wp->draw_ctx .OAMTable + i))->y_pos + j]--;
619633 if ((a & 2 ) == 0 ) {
620- quad_p->y_and_v_pairs [a] = j + wp->draw_ctx .OAMTable [i]. y_pos ;
634+ quad_p->y_and_v_pairs [a] = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + i))-> y_pos + j ;
621635 quad_p->y_and_v_pairs [a + 1 ] = b;
622636 a += 2 ;
623637 }
624638 } else if ((a & 2 ) != 0 ) {
625- quad_p->y_and_v_pairs [a] = j + wp->draw_ctx .OAMTable [i]. y_pos ;
639+ quad_p->y_and_v_pairs [a] = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + i))-> y_pos + j ;
626640 quad_p->y_and_v_pairs [a + 1 ] = b;
627641 a += 2 ;
628642 }
629643 b += _c;
630644 }
631645 if ((a & 2 ) != 0 ) {
632- quad_p->y_and_v_pairs [a] = j + wp->draw_ctx .OAMTable [i]. y_pos ;
646+ quad_p->y_and_v_pairs [a] = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + i))-> y_pos + j ;
633647 quad_p->y_and_v_pairs [a + 1 ] = b;
634648 a += 2 ;
635649 }
636650 wp->draw_ctx .sprite_vertex_count [i >> 2 ] = a;
637651 quad_p++;
652+ idx2++;
638653 }
639654 }
640655 GXSetNumChans (1 );
@@ -647,10 +662,10 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
647662 GXSetVtxDesc (GX_VA_CLR0, GX_DIRECT);
648663 GXSetVtxDesc (GX_VA_TEX0, GX_DIRECT);
649664 GXSetVtxDesc (GX_VA_TEX1, GX_DIRECT);
650- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4 , 0 );
665+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16 , 0 );
651666 GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0 );
652- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBX8 , 10 );
653- GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX1, GX_CLR_RGBA, GX_RGBX8 , 10 );
667+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX0, GX_TEX_S, GX_U16 , 10 );
668+ GXSetVtxAttrFmt (GX_VTXFMT0, GX_VA_TEX1, GX_TEX_S, GX_U16 , 10 );
654669 GXInitTexObj (&GStack_7c, wp->chr_to_u8_bufp , 0x400 , (u16 )(size >> 10 ), GX_TF_I8, GX_MIRROR, GX_CLAMP, 0 );
655670 GXInitTexObjLOD (&GStack_7c, GX_NEAR, GX_NEAR, 0 .0f , 0 .0f , 0 .0f , 0 , 0 , GX_ANISO_1);
656671 GXLoadTexObj (&GStack_7c, GX_TEXMAP0);
@@ -707,37 +722,40 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
707722 GXSetAlphaCompare (GX_GREATER, 0 , GX_AOP_AND, GX_ALWAYS, 0 );
708723
709724 u32 n_verts = 0 ;
725+ u32 idx2 = 0 ;
710726 for (i = 0 ; i < ARRAY_COUNT (wp->draw_ctx .OAMTable ); i++) {
711727 // draw sprites
712- if (sprite_priority_pass == 0 || (wp->draw_ctx .OAMTable [i]. attributes & KS_NES_OAM_ATTR_PRIORITY) != 0 ) {
713- n_verts += wp->draw_ctx .sprite_vertex_count [i ];
728+ if (sprite_priority_pass == 0 || (((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx2))-> attributes & KS_NES_OAM_ATTR_PRIORITY) != 0 ) {
729+ n_verts += wp->draw_ctx .sprite_vertex_count [idx2 >> 2 ];
714730 }
731+
732+ idx2 += 4 ;
715733 }
716734
717- // u32 idx = 0x100-4;
718- u32 idx2 = ARRAY_COUNT (wp->draw_ctx .OAMTable ) - 1 ;
735+ u32 idx = 0x100 -4 ;
736+ idx2 = ARRAY_COUNT (wp->draw_ctx .OAMTable ) - 1 ;
719737 GXBegin (GX_QUADS, GX_VTXFMT0, n_verts);
720738 while (TRUE ) {
721- ksNesSpriteQuadData* quad_p = &wp->draw_ctx .sprite_quad_data [idx2];
722- u8 * quad_pairs = quad_p->y_and_v_pairs ;
739+ // ksNesSpriteQuadData* quad_p = &wp->draw_ctx.sprite_quad_data[idx2];
723740 // u32 scanline_idx = wp->draw_ctx.OAMTable[idx];
724- u32 tile_index = wp->draw_ctx .OAMTable [idx2].tile_index ;
741+ u8 * quad_pairs = ((ksNesSpriteQuadData*)((u8 *)wp->draw_ctx .sprite_quad_data + (idx << 3 )))->y_and_v_pairs ;
742+ u32 tile_index = ((ksNesOAMEntry*)((u8 *)wp->draw_ctx .OAMTable + idx))->tile_index ;
725743 u32 flags2;
726744
727- if (wp->draw_ctx .ppu_scanline_regs [wp->draw_ctx .OAMTable [idx2]. y_pos ].ppu_ctrl & KS_NES_PPU_CTRL_SPRITE_SIZE) {
745+ if (wp->draw_ctx .ppu_scanline_regs [((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> y_pos ].ppu_ctrl & KS_NES_PPU_CTRL_SPRITE_SIZE) {
728746 // 8x16 sprite
729- flags2 = wp->draw_ctx .ppu_scanline_regs [wp->draw_ctx .OAMTable [idx2]. y_pos ].chr_bank_sprite [(tile_index >> 6 ) | ((tile_index & KS_NES_OAM_TILE_BANK) << 2 )];
747+ flags2 = wp->draw_ctx .ppu_scanline_regs [((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> y_pos ].chr_bank_sprite [(tile_index >> 6 ) | ((tile_index & KS_NES_OAM_TILE_BANK) << 2 )];
730748 tile_index &= KS_NES_OAM_TILE_IDX;
731749 } else {
732750 // 8x8 sprite
733- flags2 = wp->draw_ctx .ppu_scanline_regs [wp->draw_ctx .OAMTable [idx2]. y_pos ].chr_bank_sprite [(tile_index >> 6 ) | ((wp->draw_ctx .ppu_scanline_regs [wp->draw_ctx .OAMTable [idx2]. y_pos ].ppu_ctrl >> 1 ) & 4 )];
751+ flags2 = wp->draw_ctx .ppu_scanline_regs [((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> y_pos ].chr_bank_sprite [(tile_index >> 6 ) | ((wp->draw_ctx .ppu_scanline_regs [((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> y_pos ].ppu_ctrl >> 1 ) & 4 )];
734752 }
735753
736754 // u32 flags3 = wp->draw_ctx.OAMTable[idx + 2];
737- u32 oam_attrs = wp->draw_ctx .OAMTable [idx2]. attributes ;
738- u32 x0 = wp->draw_ctx .OAMTable [idx2]. x_pos + 128 ;
739- u32 x1 = wp->draw_ctx .OAMTable [idx2]. x_pos + 136 ;
740- u32 color = ((wp->draw_ctx .OAMTable [idx2]. x_pos & 3 ) * 16 + 4 ) * 0x01000000 ;
755+ u32 oam_attrs = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> attributes ;
756+ u32 x0 = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> x_pos + 128 ;
757+ u32 x1 = ((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> x_pos + 136 ;
758+ u32 color = ((((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> x_pos & 3 ) * 16 + 4 ) * 0x01000000 ;
741759
742760 if (sprite_priority_pass != 0 ) {
743761 // We're in the BG pass so skip if the sprite is supposed to be drawn in front of the BG
@@ -764,15 +782,15 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
764782 t0 = (flags2 & 0xFE ) * 2 ; // select chr bank offset
765783 temp = ((tile_index & 0x3F ) * 0x20 ) | ((flags2 & 0x01 ) * 0x800 ); // flags2 bit0 determines the pattern table
766784
767- if (wp->draw_ctx .OAMTable [idx2]. attributes & KS_NES_OAM_ATTR_FLIP_HORIZONTAL) {
785+ if (((ksNesOAMEntry*)(( u8 *) wp->draw_ctx .OAMTable + idx))-> attributes & KS_NES_OAM_ATTR_FLIP_HORIZONTAL) {
768786 s1 = temp + 32 ;
769787 s1_2 = temp;
770788 } else {
771789 s1 = temp;
772790 s1_2 = temp + 32 ;
773791 }
774792
775- for (j = 0 ; j < wp->draw_ctx .sprite_vertex_count [idx2 ]; j += 4 ) {
793+ for (j = 0 ; j < wp->draw_ctx .sprite_vertex_count [idx >> 2 ]; j += 4 ) {
776794 u32 y0 = -129 - quad_pairs[0 ];
777795 t1 = quad_pairs[1 ];
778796 u32 y1 = -129 - quad_pairs[2 ];
@@ -802,12 +820,12 @@ void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 sprite_prior
802820
803821
804822loop_condition:
805- if (idx2 == 0 ) {
823+ if (idx == 0 ) {
806824 break ;
807825 }
808826
809- // idx -= 4;
810- idx2--;
827+ idx -= 4 ;
828+ // idx2--;
811829 }
812830
813831 GXEnd ();
0 commit comments