mirror of
https://github.com/ACreTeam/ac-decomp
synced 2026-05-22 22:24:16 -04:00
Improve ks_nes_draw funcs scores some, a bunch of documentation and improvements in ks_nes_core.
This commit is contained in:
@@ -13,6 +13,8 @@ extern "C" {
|
||||
#define KS_NES_WIDTH 256
|
||||
#define KS_NES_HEIGHT 228
|
||||
|
||||
#define KS_NES_PPU_CYCLES_PER_SCANLINE 341
|
||||
#define KS_NES_CPU_CYCLES_PER_SCANLINE 114
|
||||
|
||||
#define KS_NES_SCANLINE_COUNT 240 // 228 visible + 8 pre-render + 8 post-render
|
||||
#define KS_NES_SCANLINE_SPRITE_OVERDRAW_COUNT (KS_NES_SCANLINE_COUNT + 32) // 272
|
||||
@@ -123,6 +125,32 @@ extern "C" {
|
||||
#define KS_NES_MAPPER_KONAMI_VRC6A 24
|
||||
#define KS_NES_MAPPER_KONAMI_VRC6B 26
|
||||
|
||||
// Memory mapped register addresses
|
||||
|
||||
// APU Registers & Flags
|
||||
#define KS_NES_REG_APU_STATUS 0x4015
|
||||
#define KS_NES_REG_APU_STATUS_FLG_PULSE1_ENABLE (1 << 0)
|
||||
#define KS_NES_REG_APU_STATUS_FLG_PULSE2_ENABLE (1 << 1)
|
||||
#define KS_NES_REG_APU_STATUS_FLG_TRIANGLE_ENABLE (1 << 2)
|
||||
#define KS_NES_REG_APU_STATUS_FLG_NOISE_ENABLE (1 << 3)
|
||||
#define KS_NES_REG_APU_STATUS_FLG_DMC_ENABLE (1 << 4)
|
||||
|
||||
// MMC5 Audio Registers & Flags
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE1_TIMER 0x5000
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE1_LENGTH_CTR 0x5001
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE1_ENVELOPE 0x5002
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE1_SWEEP 0x5003
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE2_TIMER 0x5004
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE2_LENGTH_CTR 0x5005
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE2_ENVELOPE 0x5006
|
||||
#define KS_NES_REG_MMC5_AUDIO_PULSE2_SWEEP 0x5007
|
||||
#define KS_NES_REG_MMC5_AUDIO_PCM_MODE_IRQ 0x5010 // bit0 = mode select, 0 = write, 1 = read & bit7 = PCM IRQ enable
|
||||
#define KS_NES_REG_MMC5_AUDIO_RAW_PCM 0x5011
|
||||
#define KS_NES_REG_MMC5_AUDIO_STATUS 0x5015 // only bottom two bits are used (bit0/1) and toggle pulse1/2
|
||||
#define KS_NES_REG_MMC5_AUDIO_STATUS_PULSE1 (1 << 0)
|
||||
#define KS_NES_REG_MMC5_AUDIO_STATUS_PULSE2 (1 << 1)
|
||||
#define KS_NES_REG_MMC5_AUDIO_STATUS_PULSE_MASK (KS_NES_REG_MMC5_AUDIO_STATUS_PULSE1 | KS_NES_REG_MMC5_AUDIO_STATUS_PULSE2)
|
||||
|
||||
// Emulator flags
|
||||
#define KS_NES_FLAG_NINES_OVER_MODE (1 << 13) // 0x2000, enables "nines over" mode which allows drawing more than 8 sprites per scanline
|
||||
|
||||
@@ -160,10 +188,17 @@ typedef struct ksNesOAMEntry {
|
||||
u8 x_pos;
|
||||
} ksNesOAMEntry;
|
||||
|
||||
// I suspect this struct is fake but it makes readability easier and matches.
|
||||
typedef struct ksNesScanlineYCoords {
|
||||
u8 top;
|
||||
u8 bottom;
|
||||
} ksNesScanlineYCoords;
|
||||
|
||||
typedef struct ksNesDrawCtx {
|
||||
/* 0x0000 */ union {
|
||||
u8 sprite_scanline_limit[KS_NES_SCANLINE_SPRITE_OVERDRAW_COUNT]; // tracks the number of sprites that have been drawn on each scanline
|
||||
u8 scanline_y_coords[2 * 256]; // tracks the Y coordinate of the top & bottom of each scanline
|
||||
u8 scanline_raw_buf[512]; // raw buffer (most likely definition?)
|
||||
};
|
||||
|
||||
/* 0x0200 */ u8 mmc2_scanline_latch_tiles[KS_NES_SCANLINE_COUNT + 16]; // tracks which tiles should be accessible on each scanline based on MMC2 latch settings
|
||||
@@ -179,23 +214,25 @@ typedef struct ksNesDrawCtx {
|
||||
/* 0x8EE8 */ Mtx34 draw_mtx;
|
||||
} ksNesDrawCtx;
|
||||
|
||||
#define KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(type, draw_ctx, ofs) ((type*)((((u8*)(draw_ctx).scanline_raw_buf) + (ofs))))
|
||||
#define KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF(type, draw_ctx, idx) ((type*)(((u8*)(draw_ctx).scanline_raw_buf) + ((idx) * sizeof(type))))
|
||||
|
||||
typedef struct ksNesCommonWorkObj {
|
||||
/* 0x0000 */ u8* nesromp;
|
||||
/* 0x0004 */ u8* noise_bufp;
|
||||
/* 0x0008 */ size_t chr_to_i8_buf_size;
|
||||
/* 0x000C */ u8* chr_to_u8_bufp;
|
||||
/* 0x0010 */ u8* result_bufp;
|
||||
/* 0x0014 */ int _0014;
|
||||
/* 0x0018 */ int _0018;
|
||||
/* 0x0014 */ u32 cpu_cycle_count;
|
||||
/* 0x0018 */ u32 total_cpu_cycles;
|
||||
/* 0x001C */ u8 frames;
|
||||
/* 0x001D */ u8 _001D;
|
||||
/* 0x001D */ u8 fds_disk_count;
|
||||
/* 0x001E */ u8 _001E;
|
||||
/* 0x001F */ u8 _001F;
|
||||
/* 0x0020 */ u32 pads[4];
|
||||
/* 0x0030 */ u32 _0030;
|
||||
/* 0x0034 */ u32 _0034;
|
||||
/* 0x0038 */ u32 _0038;
|
||||
/* 0x003C */ u8 _003C[0x0048 - 0x003C];
|
||||
/* 0x0020 */ u32 pads[4+3];
|
||||
/* 0x003C */ u8 _003C;
|
||||
/* 0x0040 */ u32 _0040;
|
||||
/* 0x0044 */ u32 _0044;
|
||||
/* 0x0048 */ size_t prg_size;
|
||||
/* 0x004C */ u8 _004C[0x0060 - 0x004C];
|
||||
/* 0x0060 */ ksNesDrawCtx draw_ctx;
|
||||
@@ -205,16 +242,16 @@ typedef struct ksNesStateObj {
|
||||
/* 0x0000 */ u8 wram[KS_NES_WRAM_SIZE];
|
||||
/* 0x0800 */ u8 ppu_nametable_ram[KS_NES_PPU_NAMETABLE_RAM_SIZE];
|
||||
/* 0x1000 */ u8 cartridge_nametable_ram[28];
|
||||
/* 0x101C */ u8 primary_oam[0x100];
|
||||
/* 0x111C */ u8 _pad[4]; // this might not exist and instead the next member might be ATTRIBUTE_ALIGN(16/32)
|
||||
/* 0x101C */ u8 _pad[4]; // this might not exist and instead the next member might be ATTRIBUTE_ALIGN(16/32)
|
||||
/* 0x1020 */ ksNesOAMEntry primary_oam[KS_NES_OAM_TABLE_SIZE]; // u8 primary_oam[0x100];
|
||||
/* 0x1120 */ u8 mmc5_extension_ram[0x400];
|
||||
// these are all function pointers.
|
||||
// leaving these as void pointers until we figure out the function signature.
|
||||
/* 0x1520 */ void* store_ppu_func[8]; // ksNesStorePPUFuncTblDefault
|
||||
/* 0x1540 */ void* store_io_func[0x28]; // ksNesStoreIOFuncTblDefault
|
||||
/* 0x1540 */ void* store_io_func[40]; // ksNesStoreIOFuncTblDefault
|
||||
/* 0x15E0 */ void* store_func[8]; // ksNesStoreFuncTblDefault
|
||||
/* 0x1600 */ void* load_func[8]; // ksNesLoadFuncTblDefault
|
||||
/* 0x1620 */ void* load_io_func[0x18]; // ksNesLoadIOFuncTblDefault
|
||||
/* 0x1620 */ void* load_io_func[24]; // ksNesLoadIOFuncTblDefault
|
||||
/* 0x1680 */ u8* cpu_0000_1fff; // work RAM and its mirrors
|
||||
/* 0x1684 */ u8* cpu_2000_3fff; // PPU registers and their mirrors
|
||||
/* 0x1688 */ u8* cpu_4000_5fff; // APU registers, I/O registers, and usually unmapped cartridge addresses
|
||||
|
||||
@@ -2119,11 +2119,11 @@ static int famicom_rom_load() {
|
||||
u32 flags = 0;
|
||||
wp->prg_size = KS_NES_PRGROM_SIZE;
|
||||
wp->noise_bufp = famicomCommon.noise_bufp;
|
||||
wp->_001D = 4;
|
||||
wp->fds_disk_count = 4;
|
||||
wp->chr_to_u8_bufp = famicomCommon.chr_to_i8_bufp;
|
||||
wp->chr_to_i8_buf_size = CHR_TO_I8_BUF_SIZE;
|
||||
wp->result_bufp = famicomCommon.result_bufp;
|
||||
wp->_0018 = 0;
|
||||
wp->total_cpu_cycles = 0;
|
||||
|
||||
if (famicomCommon.noise_bufp == nullptr) {
|
||||
flags |= 0x40; // no sound?
|
||||
@@ -2412,9 +2412,9 @@ extern void famicom_1frame() {
|
||||
}
|
||||
|
||||
famicom_key_convert();
|
||||
famicomCommon.wp->_0030 = 0;
|
||||
famicomCommon.wp->_0034 = 0;
|
||||
famicomCommon.wp->_0038 = 0;
|
||||
famicomCommon.wp->pads[4] = 0;
|
||||
famicomCommon.wp->pads[5] = 0;
|
||||
famicomCommon.wp->pads[6] = 0;
|
||||
|
||||
/* Special input modes activated when L & R are held */
|
||||
/*
|
||||
@@ -2502,7 +2502,7 @@ extern void famicom_1frame() {
|
||||
speed_show--;
|
||||
}
|
||||
|
||||
famicomCommon.wp->_0014 = 0;
|
||||
famicomCommon.wp->cpu_cycle_count = 0;
|
||||
famicomCommon.wp->frames = frames;
|
||||
|
||||
do {
|
||||
|
||||
+223
-213
File diff suppressed because it is too large
Load Diff
@@ -106,11 +106,14 @@ void ksNesDrawMakeBGIndTex(ksNesCommonWorkObj* wp, u32 mmc3) {
|
||||
u32 scanline_ctrl1 = wp->draw_ctx.ppu_scanline_regs[row].vram_addr_coarse_x;
|
||||
u32 mask;
|
||||
u32 nibble_acc; // @bug - uninitialized
|
||||
u8* patternPtrBase = (u8*)wp->draw_ctx.ppu_scanline_regs[row].chr_bank_bg;
|
||||
u8* patternPtrBase;
|
||||
u32 tile_byte;
|
||||
u32 palette_bits;
|
||||
u32 dst_idx;
|
||||
u8* nametable_p;
|
||||
u32 flags;
|
||||
|
||||
patternPtrBase = (u8*)wp->draw_ctx.ppu_scanline_regs[row].chr_bank_bg;
|
||||
|
||||
mask = mask = (scanline_ctrl0 & 0x04) ? CHR_flag_xor : 0; // bruh
|
||||
|
||||
@@ -128,7 +131,7 @@ void ksNesDrawMakeBGIndTex(ksNesCommonWorkObj* wp, u32 mmc3) {
|
||||
tile_byte = nametable_p[((scanline_ctrl0 & 0xF8) << 2) + ((scanline_ctrl1 & 0xF8) >> 3)];
|
||||
}
|
||||
|
||||
palette_bits = patternPtrBase[((u8)tile_byte >> 6) | ((wp->draw_ctx.ppu_scanline_regs[row].ppu_ctrl & 0x10) >> 2)];
|
||||
palette_bits = patternPtrBase[((u8)tile_byte >> 6) | ((wp->draw_ctx.ppu_scanline_regs[row].ppu_ctrl & KS_NES_PPU_CTRL_BG_PATTERN) >> 2)];
|
||||
|
||||
// issue is here
|
||||
wp->draw_ctx.bg_tile_index_texture[(((col & 0x3C) * 8) + ((col & 3) * 2) + ((row >> 2) * 288) + ((row & 3) * 8)) + 0] = (((palette_bits & 1) << 6) | (tile_byte & 0x3F)) - (col & 1);
|
||||
@@ -892,6 +895,7 @@ void ksNesDrawOBJMMC5(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 sprite_prio
|
||||
u32 clr;
|
||||
u32 oam_attrs;
|
||||
u8 *work;
|
||||
ksNesScanlineYCoords* coords_p;
|
||||
|
||||
GXSetNumChans(1);
|
||||
GXSetNumTexGens(2);
|
||||
@@ -968,7 +972,7 @@ void ksNesDrawOBJMMC5(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 sprite_prio
|
||||
|
||||
var_r24 = 0;
|
||||
for (i = 0; i < ARRAY_COUNT(wp->draw_ctx.OAMTable); i++) {
|
||||
if (sprite_priority_pass == 0 || (wp->draw_ctx.OAMTable[i].attributes & KS_NES_PPU_CTRL_SPRITE_SIZE) != 0) {
|
||||
if (sprite_priority_pass == 0 || (wp->draw_ctx.OAMTable[i].attributes & KS_NES_OAM_ATTR_PRIORITY) != 0) {
|
||||
var_r24 += (wp->draw_ctx.ppu_scanline_regs[wp->draw_ctx.OAMTable[i].y_pos].ppu_ctrl & KS_NES_PPU_CTRL_SPRITE_SIZE) ? 8 : 4;
|
||||
}
|
||||
}
|
||||
@@ -982,8 +986,9 @@ void ksNesDrawOBJMMC5(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 sprite_prio
|
||||
j = (ARRAY_COUNT(wp->draw_ctx.OAMTable) - 1) * sizeof(wp->draw_ctx.OAMTable[0]);
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, var_r24);
|
||||
while (TRUE) {
|
||||
u8 scanline = ((u8*)wp->draw_ctx.OAMTable)[j + 0];
|
||||
u32 tile_idx = ((u8*)wp->draw_ctx.OAMTable)[j + 1]; // loading tile index & bank
|
||||
ksNesOAMEntry* oam_p = KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesOAMEntry, wp->draw_ctx, j);
|
||||
u8 scanline = oam_p->y_pos;
|
||||
u32 tile_idx = oam_p->tile_index; // loading tile index & bank
|
||||
u32 size_mode = (wp->draw_ctx.ppu_scanline_regs[scanline].ppu_ctrl >> 5) & 1; // sprite size mode, 0 = 8x8, 1 = 8x16
|
||||
u32 palette_bits;
|
||||
u32 tmp;
|
||||
@@ -1000,9 +1005,9 @@ void ksNesDrawOBJMMC5(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 sprite_prio
|
||||
}
|
||||
|
||||
|
||||
oam_attrs = ((u8*)wp->draw_ctx.OAMTable)[j + 2]; // OAM attributes
|
||||
x1 = ((u8*)wp->draw_ctx.OAMTable)[j + 3] + 128; // OAM X position
|
||||
x2 = ((u8*)wp->draw_ctx.OAMTable)[j + 3] + 128 + 8; // OAM X position + 8
|
||||
oam_attrs = oam_p->attributes; // OAM attributes
|
||||
x1 = oam_p->x_pos + 128; // OAM X position
|
||||
x2 = oam_p->x_pos + 128 + 8; // OAM X position + 8
|
||||
clr = ((((oam_attrs & KS_NES_OAM_ATTR_PALETTE_MASK) * 16) + 4) | (wp->draw_ctx.ppu_scanline_regs[scanline].ppu_ctrl & (KS_NES_PPU_CTRL_NMI_ENABLE | KS_NES_PPU_CTRL_MASTER_SLAVE))) << 24;
|
||||
|
||||
if (sprite_priority_pass != 0) {
|
||||
@@ -1069,7 +1074,7 @@ void ksNesDrawOBJMMC5(ksNesCommonWorkObj* wp, ksNesStateObj* sp, u32 sprite_prio
|
||||
|
||||
loop_point:
|
||||
if (j == 0) break;
|
||||
j -= sizeof(wp->draw_ctx.OAMTable[0]);
|
||||
j -= sizeof(ksNesOAMEntry);
|
||||
}
|
||||
|
||||
GXEnd();
|
||||
@@ -1102,18 +1107,20 @@ loop_point:
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, quads << 1);
|
||||
for (i = 0; i < quads; i += 2) {
|
||||
work = (u8*)wp + i; // wp->draw_ctx.scanline_y_coords[i, i + 1] (top & bottom)
|
||||
x = 0x180;
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[(u8)((u8*)wp + i)[0x60]].ppumask_flags & KS_NES_PPU_MASK_SPRITES_COMBINED) == KS_NES_PPU_MASK_SHOW_SPRITES) {
|
||||
x = 0x88;
|
||||
ksNesScanlineYCoords* coords_p = KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i);
|
||||
u8 scanline_top = (u8)KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i)->top;
|
||||
// work = (u8*)wp + i; // wp->draw_ctx.scanline_y_coords[i, i + 1] (top & bottom)
|
||||
x = 384;
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[scanline_top].ppumask_flags & KS_NES_PPU_MASK_SPRITES_COMBINED) == KS_NES_PPU_MASK_SHOW_SPRITES) {
|
||||
x = 136;
|
||||
}
|
||||
GXPosition2s16(0x80, -128 - x);
|
||||
GXPosition2s16(128, -128 - x);
|
||||
GXColor1u32(0);
|
||||
GXPosition2s16(x, -128 - work[0x60]);
|
||||
GXPosition2s16(x, -128 - coords_p->top);
|
||||
GXColor1u32(0);
|
||||
GXPosition2s16(x, -128 - work[0x60] - work[0x61]);
|
||||
GXPosition2s16(x, -128 - coords_p->top - coords_p->bottom);
|
||||
GXColor1u32(0);
|
||||
GXPosition2s16(0x80, -128 - work[0x60] - work[0x61]);
|
||||
GXPosition2s16(128, -128 - coords_p->top - coords_p->bottom);
|
||||
GXColor1u32(0);
|
||||
}
|
||||
GXEnd();
|
||||
@@ -1121,8 +1128,8 @@ loop_point:
|
||||
|
||||
void ksNesDrawFlushEFBToRed8(u8* buf) {
|
||||
static const GXColor black = { 0, 0, 0, 0 };
|
||||
GXSetTexCopySrc(0x80, 0x88, 0x100, 0xe4);
|
||||
GXSetTexCopyDst(0x100, 0xe4, GX_CTF_R8, GX_FALSE);
|
||||
GXSetTexCopySrc(128, 136, 256, 228);
|
||||
GXSetTexCopyDst(256, 228, GX_CTF_R8, GX_FALSE);
|
||||
GXSetCopyClear(black, 0xffffff);
|
||||
GXCopyTex(buf, GX_FALSE);
|
||||
GXPixModeSync();
|
||||
@@ -1132,8 +1139,7 @@ void ksNesDrawFlushEFBToRed8(u8* buf) {
|
||||
void ksNesDrawOBJI8ToEFB(ksNesCommonWorkObj* wp, u8* buf) {
|
||||
GXTexObj obj;
|
||||
u32 i;
|
||||
s32 u;
|
||||
u8* work;
|
||||
u32 x;
|
||||
u32 cnt;
|
||||
|
||||
GXSetNumChans(0);
|
||||
@@ -1167,21 +1173,21 @@ void ksNesDrawOBJI8ToEFB(ksNesCommonWorkObj* wp, u8* buf) {
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, cnt * 2);
|
||||
|
||||
for (i = 0; i < cnt; i += 2) {
|
||||
work = (u8*)wp + i; // if it works...
|
||||
u = (wp->draw_ctx.ppu_scanline_regs[(u8)((u8*)wp)[i + 0x60]].ppumask_flags & KS_NES_PPU_MASK_SPRITES_COMBINED) == KS_NES_PPU_MASK_SHOW_SPRITES ? 8 : 0;
|
||||
|
||||
GXPosition2s16(u + 0x80, -128 - work[0x60]);
|
||||
GXTexCoord2u16(u, work[0x60] - 8);
|
||||
for (i = 0; i < cnt; i += sizeof(ksNesScanlineYCoords)) {
|
||||
ksNesScanlineYCoords* scanline_y_coords = KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i);
|
||||
x = (wp->draw_ctx.ppu_scanline_regs[(u8)KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i)->top].ppumask_flags & KS_NES_PPU_MASK_SPRITES_COMBINED) == KS_NES_PPU_MASK_SHOW_SPRITES ? 8 : 0;
|
||||
|
||||
GXPosition2s16(0x180, -128 - work[0x60]);
|
||||
GXTexCoord2u16(0x100, work[0x60] - 8);
|
||||
GXPosition2s16(x + 0x80, -128 - scanline_y_coords->top);
|
||||
GXTexCoord2u16(x, scanline_y_coords->top - 8);
|
||||
|
||||
GXPosition2s16(0x180, -128 - work[0x60] - work[0x61]);
|
||||
GXTexCoord2u16(0x100, work[0x60] + work[0x61] - 8);
|
||||
GXPosition2s16(0x180, -128 - scanline_y_coords->top);
|
||||
GXTexCoord2u16(0x100, scanline_y_coords->top - 8);
|
||||
|
||||
GXPosition2s16(u + 0x80, -128 - work[0x60] - work[0x61]);
|
||||
GXTexCoord2u16(u, work[0x60] + work[0x61] - 8);
|
||||
GXPosition2s16(0x180, -128 - scanline_y_coords->top - scanline_y_coords->bottom);
|
||||
GXTexCoord2u16(0x100, scanline_y_coords->top + scanline_y_coords->bottom - 8);
|
||||
|
||||
GXPosition2s16(x + 0x80, -128 - scanline_y_coords->top - scanline_y_coords->bottom);
|
||||
GXTexCoord2u16(x, scanline_y_coords->top + scanline_y_coords->bottom - 8);
|
||||
}
|
||||
|
||||
GXEnd();
|
||||
@@ -1203,7 +1209,7 @@ void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) {
|
||||
u8 y;
|
||||
u32 val;
|
||||
u32 clr;
|
||||
u8 *work;
|
||||
ksNesScanlineYCoords* scanline_y_coords;
|
||||
GXTexObj obj;
|
||||
GXTexObj obj2;
|
||||
|
||||
@@ -1246,14 +1252,16 @@ void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) {
|
||||
|
||||
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0);
|
||||
|
||||
// Count non-grayscale scanlines
|
||||
cnt = 0;
|
||||
for (i = 0; wp->draw_ctx.scanline_y_coords[i] != 0xFF; i += 2) {
|
||||
for (i = 0; wp->draw_ctx.scanline_y_coords[i] != 0xFF; i += sizeof(ksNesScanlineYCoords)) {
|
||||
val = wp->draw_ctx.ppu_scanline_regs[wp->draw_ctx.scanline_y_coords[i]].ppumask_flags;
|
||||
if ((val & KS_NES_PPU_MASK_COLOR_EFFECTS) == 0) {
|
||||
cnt += 4; // has color and no color emphasis
|
||||
}
|
||||
}
|
||||
|
||||
// Draw non-grayscale scanlines
|
||||
if (cnt != 0) {
|
||||
GXSetNumChans(0);
|
||||
GXSetNumTexGens(1);
|
||||
@@ -1270,25 +1278,26 @@ void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) {
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, cnt);
|
||||
|
||||
do {
|
||||
i -= 2;
|
||||
work = ((u8*)wp + i);
|
||||
val = wp->draw_ctx.ppu_scanline_regs[work[0x60]].ppumask_flags & KS_NES_PPU_MASK_COLOR_EFFECTS;
|
||||
i -= sizeof(ksNesScanlineYCoords);
|
||||
scanline_y_coords = KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i);
|
||||
val = wp->draw_ctx.ppu_scanline_regs[scanline_y_coords->top].ppumask_flags & KS_NES_PPU_MASK_COLOR_EFFECTS;
|
||||
if (val == 0) {
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x60]);
|
||||
GXTexCoord2u16(256, work[0x60]);
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->top);
|
||||
GXTexCoord2u16(256, scanline_y_coords->top);
|
||||
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x61]);
|
||||
GXTexCoord2u16(256, work[0x61]);
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->bottom);
|
||||
GXTexCoord2u16(256, scanline_y_coords->bottom);
|
||||
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x61]);
|
||||
GXTexCoord2u16(0, work[0x61]);
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->bottom);
|
||||
GXTexCoord2u16(0, scanline_y_coords->bottom);
|
||||
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x60]);
|
||||
GXTexCoord2u16(0, work[0x60]);
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->top);
|
||||
GXTexCoord2u16(0, scanline_y_coords->top);
|
||||
}
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
// Count grayscale scanlines
|
||||
cnt = 0;
|
||||
for (i = 0; wp->draw_ctx.scanline_y_coords[i] != 0xFF; i += 2) {
|
||||
val = wp->draw_ctx.ppu_scanline_regs[wp->draw_ctx.scanline_y_coords[i]].ppumask_flags;
|
||||
@@ -1297,6 +1306,7 @@ void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) {
|
||||
}
|
||||
}
|
||||
|
||||
// Draw grayscale scanlines
|
||||
if (cnt != 0) {
|
||||
GXSetNumChans(1);
|
||||
GXSetNumTexGens(1);
|
||||
@@ -1358,35 +1368,37 @@ void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) {
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, cnt);
|
||||
|
||||
do {
|
||||
i -= 2;
|
||||
work = (u8*)wp + i; // wp->draw_ctx.scanline_y_coords[i, i + 1] (top & bottom)
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[work[0x60]].ppumask_flags & KS_NES_PPU_MASK_COLOR_EFFECTS) != 0) {
|
||||
clr = 0x2F2F2F00;
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[work[0x60]].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_RED) != 0) {
|
||||
i -= sizeof(ksNesScanlineYCoords);
|
||||
scanline_y_coords = KS_NES_TYPE_FROM_DRAW_CTX_SCANLINE_BUF_OFS(ksNesScanlineYCoords, wp->draw_ctx, i);
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[scanline_y_coords->top].ppumask_flags & KS_NES_PPU_MASK_COLOR_EFFECTS) != 0) {
|
||||
clr = 0x2F2F2F00; // If any of the grayscale color bits are set, force the color to RGB8 (47, 47, 47) (chroma removed, only luma left)
|
||||
|
||||
// For each emphasis bit set, add one to the luma value to get 48 (0x30).
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[scanline_y_coords->top].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_RED) != 0) {
|
||||
clr += 0x10000000;
|
||||
}
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[work[0x60]].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_GREEN) != 0) {
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[scanline_y_coords->top].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_GREEN) != 0) {
|
||||
clr += 0x00100000;
|
||||
}
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[work[0x60]].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_BLUE) != 0) {
|
||||
if ((wp->draw_ctx.ppu_scanline_regs[scanline_y_coords->top].ppumask_flags & KS_NES_PPU_MASK_EMPHASIZE_BLUE) != 0) {
|
||||
clr += 0x00001000;
|
||||
}
|
||||
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x60]);
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->top);
|
||||
GXColor1u32(clr);
|
||||
GXTexCoord2u16(256, work[0x60]);
|
||||
GXTexCoord2u16(256, scanline_y_coords->top);
|
||||
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x61]);
|
||||
GXPosition2s16(KS_NES_WIDTH + KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->bottom);
|
||||
GXColor1u32(clr);
|
||||
GXTexCoord2u16(256, work[0x61]);
|
||||
GXTexCoord2u16(256, scanline_y_coords->bottom);
|
||||
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x61]);
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->bottom);
|
||||
GXColor1u32(clr);
|
||||
GXTexCoord2u16(0, work[0x61]);
|
||||
GXTexCoord2u16(0, scanline_y_coords->bottom);
|
||||
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - work[0x60]);
|
||||
GXPosition2s16(KS_NES_CENTER_X, -KS_NES_CENTER_Y - scanline_y_coords->top);
|
||||
GXColor1u32(clr);
|
||||
GXTexCoord2u16(0, work[0x60]);
|
||||
GXTexCoord2u16(0, scanline_y_coords->top);
|
||||
}
|
||||
} while (i != 0);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user