#define FIX_SQRT_LINKAGE #include "Famicom/ks_nes_draw.h" #include "dolphin/gx.h" #include "dolphin/PPCArch.h" #include "_mem.h" #include "dolphin/os.h" u8 ksNesPaletteNormal[] = { 0xc2, 0x10, 0x80, 0x17, 0x98, 0x17, 0xc0, 0x14, 0xdc, 0x0d, 0xd8, 0x03, 0xd8, 0x00, 0xc8, 0x80, 0xbc, 0xa0, 0x80, 0xe0, 0x81, 0x21, 0x80, 0xe4, 0x80, 0xac, 0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0xe7, 0x39, 0x81, 0x7f, 0xa0, 0xff, 0xd8, 0xd9, 0xfc, 0xd5, 0xfc, 0xcb, 0xfc, 0xc3, 0xe9, 0x20, 0xe1, 0x80, 0x9d, 0xe0, 0x8e, 0x02, 0x82, 0x4c, 0x82, 0x18, 0x88, 0x42, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff, 0x82, 0x5f, 0xb6, 0x1f, 0xe9, 0xbf, 0xfd, 0xd9, 0xfd, 0xb3, 0xfd, 0xeb, 0xfe, 0x4b, 0xfe, 0x86, 0xd2, 0xe0, 0xab, 0x6d, 0xa7, 0x55, 0x83, 0x7f, 0xb1, 0x8c, 0x80, 0x00, 0x80, 0x00, 0xff, 0xff, 0xc2, 0xff, 0xde, 0xff, 0xea, 0xff, 0xfe, 0xfd, 0xfe, 0xf9, 0xff, 0x16, 0xff, 0x35, 0xff, 0x74, 0xe7, 0x93, 0xd7, 0xb6, 0xd7, 0xdd, 0xdb, 0xbf, 0xef, 0x7b, 0x80, 0x00, 0x80, 0x00, }; void ksNesDrawInit(ksNesCommonWorkObj* wp) { Mtx44 mtx; Vec v1 = { 0.f, 0.f, 800.f }; Vec v3 = { 0.f, 0.f, -100.f }; Vec v2 = { 0.f, 1.f, 0.f }; GXInvalidateTexAll(); GXInvalidateVtxCache(); GXSetClipMode(GX_CLIP_DISABLE); GXSetPixelFmt(GX_PF_RGB8_Z24, GX_ZC_LINEAR); GXSetCopyFilter(GX_FALSE, NULL, GX_FALSE, NULL); GXSetZMode(GX_FALSE, GX_ALWAYS, GX_FALSE); GXSetZTexture(GX_ZT_DISABLE, GX_TF_Z8, 0); GXSetZCompLoc(GX_FALSE); GXSetColorUpdate(GX_TRUE); GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE2, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP0, GX_TEV_SWAP0); C_MTXOrtho(mtx, 0, -480.f, 0.f, 640.f, 0.f, 2000.f); GXSetProjection(mtx, GX_ORTHOGRAPHIC); C_MTXLookAt(wp->work_priv.draw_mtx, &v1, &v2, &v3); } void ksNesDrawEnd() { GXSetClipMode(GX_CLIP_ENABLE); GXSetZCompLoc(GX_TRUE); GXSetNumIndStages(0); GXSetTevDirect(GX_TEVSTAGE0); GXSetTevDirect(GX_TEVSTAGE1); GXSetTevDirect(GX_TEVSTAGE2); GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); GXSetTevSwapModeTable(GX_TEV_SWAP0, GX_CH_RED, GX_CH_GREEN, GX_CH_BLUE, GX_CH_ALPHA); GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE2, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_FALSE, 0, 0); GXSetTexCoordScaleManually(GX_TEXCOORD1, GX_FALSE, 0, 0); } void ksNesDrawClearEFBFirst(ksNesCommonWorkObj* wp) { DCFlushRange(&wp->work_priv._2A40, sizeof(wp->work_priv._2A40)); GXSetNumChans(1); GXSetNumTexGens(0); GXSetNumTevStages(1); GXSetNumIndStages(0); GXSetTevDirect(GX_TEVSTAGE0); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_REG, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE); GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); GXSetBlendMode(GX_BM_LOGIC, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GXSetCurrentMtx(0); GXLoadPosMtxImm(wp->work_priv.draw_mtx, 0); GXBegin(GX_QUADS, GX_VTXFMT0, 4); { GXPosition2s16(128, -128); GXColor1u32(0x00ff0000); GXPosition2s16(384, -128); GXColor1u32(0x00000000); GXPosition2s16(384, -384); GXColor1u32(0x0000ff00); GXPosition2s16(128, -384); GXColor1u32(0x00000000); } GXEnd(); } // TODO: this function needs help void ksNesDrawMakeBGIndTex(ksNesCommonWorkObj* wp, u32 mapper4) { u32 trigger_col = 0x7fff; u8 CHR_flag_xor = 0x80; u32 row; u32 col; if (mapper4) { trigger_col = 9; } if (wp->chr_to_i8_buf_size <= CHR_TO_I8_BUF_SIZE * 16) { CHR_flag_xor = wp->chr_to_i8_buf_size >> 13; } for (row = 8; row < 236; row++) { u8 scanline_ctrl0 = wp->work_priv._0B40[row]._1C; u8 scanline_ctrl1 = wp->work_priv._0B40[row]._1B; u32* patternPtrBase = &wp->work_priv._0B40[row]._10; u8* nametable_p; u8 tile_byte; u8 palette_bits; u8 nibble_acc; // @bug - uninitialized u32 dst_idx; for (col = 0; col < 34; col++) { if (col == trigger_col) { patternPtrBase -= 2; } // _00 and _04 are pointers to ppu_nametable_pointers[0/1]? nametable_p = &(wp->work_priv._0B40[row]._00)[((scanline_ctrl0 >> 7) & 1)]; if (((u32)nametable_p) & OS_BASE_CACHED) { tile_byte = nametable_p[((scanline_ctrl0 & 0xF8) << 2) + ((scanline_ctrl1 & 0xF8) >> 3)]; nibble_acc = ((nametable_p[0x3C0 + ((scanline_ctrl0 & 0xE0) >> 2) + ((scanline_ctrl1 & 0xE0) >> 7)] >> (((scanline_ctrl0 & 0x10) >> 2) | ((scanline_ctrl1 & 0x10) >> 3))) & 3) | (nibble_acc << 4); } else { tile_byte = ((u32)nametable_p) >> 8; nibble_acc = (((u32)nametable_p) & 3) | (nibble_acc << 4); } palette_bits = patternPtrBase[((wp->work_priv._0B40[row]._18 & 0x10) >> 2) | (tile_byte >> 6)]; dst_idx = ((col & 3) * 2) + ((col & 0x3C) * 8) + ((row & 3) * 8) + ((row >> 2) * 288); wp->work_priv._3240[dst_idx + 0] = (((palette_bits & 1) << 6) | (tile_byte & 0x3F)) - (col & 1); wp->work_priv._3240[dst_idx + 1] = (palette_bits >> 1) ^ (CHR_flag_xor & -((scanline_ctrl0 & 0x04) >> 2)); if ((col & 1) != 0) { wp->work_priv._7840[((col >> 1) & 3) + (col & 0x38) * 4 + (row & 7) * 4 + (row >> 3) * 160] = nibble_acc; } scanline_ctrl1 += 8; } } DCFlushRangeNoSync(wp->work_priv._3240, sizeof(wp->work_priv._3240)); DCFlushRangeNoSync(wp->work_priv._7840, sizeof(wp->work_priv._7840)); } void ksNesDrawMakeBGIndTexMMC5(ksNesCommonWorkObj*, ksNesStateObj*) { } #define ksNes_MMC2_LATCH_LO 0xFD // select chr bank 0/2 #define ksNes_MMC2_LATCH_HI 0xFE // select chr bank 1/3 void ksNesDrawMakeBGIndTexMMC2(ksNesCommonWorkObj* wp, u32 mode) { } void ksNesDrawOBJSetupMMC2(ksNesCommonWorkObj* wp) { u32 i; u32 j; u32 max; u32 chr_bank; memset(&wp->work_priv._0200, 0, sizeof(wp->work_priv._0200)); for (i = 0; i < 64; i++) { // _0B40 is the scanline state, _2940 is list of scanline triggers? if (wp->work_priv._2940[i]._00 >= 236 || (wp->work_priv._2940[i]._01 != ksNes_MMC2_LATCH_HI && wp->work_priv._2940[i]._01 != ksNes_MMC2_LATCH_LO)) { continue; } j = wp->work_priv._2940[i]._00; max = (((wp->work_priv._0B40[j]._18 >> 2) & 0x08) + 8) + j; do { wp->work_priv._0200[j] = wp->work_priv._2940[i]._01; j++; } while(j < max); } // _0200 is the scanline marker entries for (i = 0, chr_bank = 0; i < ARRAY_COUNT(wp->work_priv._0200); i++) { if (wp->work_priv._0200[i] == ksNes_MMC2_LATCH_HI) { chr_bank = 0; } else if (wp->work_priv._0200[i] == ksNes_MMC2_LATCH_LO) { chr_bank = 1; } if (chr_bank) { wp->work_priv._0B40[i]._08[0] = wp->work_priv._0B40[i]._08[1] - 1; wp->work_priv._0B40[i]._08[2] = wp->work_priv._0B40[i]._08[1] + 1; wp->work_priv._0B40[i]._08[3] = wp->work_priv._0B40[i]._08[1] + 2; } else { wp->work_priv._0B40[i]._08[1] = wp->work_priv._0B40[i]._08[0] + 1; wp->work_priv._0B40[i]._08[2] = wp->work_priv._0B40[i]._08[0] + 2; wp->work_priv._0B40[i]._08[3] = wp->work_priv._0B40[i]._08[0] + 3; } } } void ksNesDrawBG(ksNesCommonWorkObj*, ksNesStateObj*) { const static GXColor color_r_0xf0 = { 240, 0, 0, 0 }; // GXSetIndTexMtx(GX_ITM_0, ); } u32 ksNesDrawMakeOBJBlankVtxList(ksNesCommonWorkObj* wp) { u32 ret = 0; u32 comparison_mask = 20; int i; for (i = 8; i < 0xf0; i++) { int bMask = wp->work_priv._0B40[i]._19 & 0x14; if (bMask != comparison_mask && ((bMask != 0) || (comparison_mask != 4)) && (bMask != 4 || comparison_mask != 0)) { if (ret & 1 != 0) { wp->work_priv._0000[ret] = i - wp->_004C[ret + 0x13]; ret++; } if ((comparison_mask == 20) || (wp->work_priv._0B40[i]._19 & 0x10) == 0) { wp->work_priv._0000[ret++] = i; } comparison_mask = wp->work_priv._0B40[i]._19 & 0x14; } } if (ret & 1) { wp->work_priv._0000[ret] = i - wp->_004C[ret + 0x13]; ret++; } return ret; } u32 ksNesDrawMakeOBJAppearVtxList(ksNesCommonWorkObj* wp) { u32 ret = 0; u32 comparison_mask = 0; int i; for (i = 8; i < 0xf0; i++) { int bMask = wp->work_priv._0B40[i]._19 & 0x14; if (bMask != comparison_mask && ((bMask != 0) || (comparison_mask != 4)) && (bMask != 4 || comparison_mask != 0)) { if (ret & 1 != 0) { wp->work_priv._0000[ret] = i - wp->_004C[ret + 0x13]; ret++; } if ((wp->work_priv._0B40[i]._19 & 0x10)) { wp->work_priv._0000[ret++] = i; } comparison_mask = wp->work_priv._0B40[i]._19 & 0x14; } } if (ret & 1) { wp->work_priv._0000[ret] = i - wp->_004C[ret + 0x13]; ret++; } return ret; } void ksNesDrawOBJ(ksNesCommonWorkObj* wp, ksNesStateObj* state, u32 c) { u32 size = wp->chr_to_i8_buf_size <= CHR_TO_I8_BUF_SIZE ? wp->chr_to_i8_buf_size : CHR_TO_I8_BUF_SIZE; // int i; GXTexObj GStack_7c; GXTexObj GStack_9c; GXTexObj GStack_bc; u32 i; u32 j; if (c == 0) { for (i = 0; i < 0x110; i++) { wp->work_priv._0000[i] = i < 0xF0 ? ((state->frame_flags & 0x2000) ? 255 : 8) : 0; if ((wp->work_priv._0B40[i]._19 & 0x10) == 0) { wp->work_priv._0000[i] = 0; } } if (state->prg_size == 0x40000 && memcmp(state->prgromp + 0x3ffe9, "MARIO 3", 7) == 0) { for (i = 0; i < 0xf0; i++) { if (wp->work_priv._0B40[i]._0C == 0x7e7e7e7e) { wp->work_priv._0000[i] = 0; } } } memset(&wp->work_priv._0340, 0, sizeof(wp->work_priv._0340)); int b; int _c; int a; int _j; _0340_struct* _340_p = wp->work_priv._0340; for (i = 0; i < 0x100; i += 4) { _j = 8; if (wp->work_priv._0B40[wp->work_priv._2940[i]._00]._18 & 0x20) { _j = 0x10; } a = 0; if (wp->work_priv._2940[i]._02 & 0x80) { b = _j << 2; _c = -4; } else { b = 0; _c = 4; } for (j = 0; j < _j; j++) { if (wp->work_priv._0000[wp->work_priv._2940[i]._00 + j] != 0) { wp->work_priv._0000[wp->work_priv._2940[i]._00 + j]--; if ((a & 2) == 0) { _340_p->_00[a] = j + wp->work_priv._2940[i]._00; _340_p->_00[a + 1] = b; a += 2; } } else if ((a & 2) != 0) { _340_p->_00[a] = j + wp->work_priv._2940[i]._00; _340_p->_00[a + 1] = b; a += 2; } b += _c; } if ((a & 2) != 0) { _340_p->_00[a] = j + wp->work_priv._2940[i]._00; _340_p->_00[a + 1] = b; a += 2; } wp->work_priv._0300[i >> 2] = a; _340_p++; } } GXSetNumChans(1); GXSetNumTexGens(2); GXSetNumTevStages(3); GXSetNumIndStages(2); GXSetBlendMode(GX_BM_LOGIC, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX1, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_CLR_RGB, GX_RGBA4, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_CLR_RGBA, GX_RGBX8, 10); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX1, GX_CLR_RGBA, GX_RGBX8, 10); GXInitTexObj(&GStack_7c, wp->chr_to_u8_bufp, 0x400, (u16)(size >> 10), GX_TF_I8, GX_MIRROR, GX_CLAMP, 0); GXInitTexObjLOD(&GStack_7c, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); GXLoadTexObj(&GStack_7c, GX_TEXMAP0); GXInitTexObj(&GStack_9c, wp->work_priv._8EC0, 8, 4, GX_TF_IA8, GX_CLAMP, GX_CLAMP, 0); GXInitTexObjLOD(&GStack_9c, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); GXLoadTexObj(&GStack_9c, GX_TEXMAP1); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c); GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 0x100, 0x101); GXSetTexCoordBias(GX_TEXCOORD0, 0, 0); GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD0, GX_TEXMAP1); GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_8, GX_ITS_1); GXSetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_OFF, GX_ITW_OFF, GX_ITW_OFF, GX_FALSE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEX_DISABLE, GX_COLOR0A0); GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE); GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_ZERO); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVREG2); GXInitTexObj(&GStack_bc, wp->work_priv._8E40, 4, 0x10, GX_TF_IA8, GX_CLAMP, GX_CLAMP, 0); GXInitTexObjLOD(&GStack_bc, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, 0, 0, GX_ANISO_1); GXLoadTexObj(&GStack_bc, GX_TEXMAP2); GXSetTexCoordGen(GX_TEXCOORD1, GX_TG_MTX2x4, GX_TG_TEX1, 0x3c); GXSetTexCoordScaleManually(GX_TEXCOORD1, GX_TRUE, 0x100, 0x101); GXSetTexCoordBias(GX_TEXCOORD1, 0, 0); GXSetIndTexOrder(GX_INDTEXSTAGE1, GX_TEXCOORD1, GX_TEXMAP2); GXSetIndTexCoordScale(GX_INDTEXSTAGE1, GX_ITS_8, GX_ITS_1); { // u32 i; for (i = 0; size > (0x8000 << i); i++) {} static f32 indtexmtx_obj[2][3] = { { 0.5f, 0.f, 0.f }, { 0.f, 0.0625f, 0.f } }; indtexmtx_obj[0][0] = 0.5f / (i >= 4 ? (1 << i - 3) : 1); indtexmtx_obj[1][1] = 0.5f / (i <= 2 ? (1 << 3 - i) : 1); GXSetIndTexMtx(GX_ITM_0, indtexmtx_obj, 36 + (i < 4 ? 0 : i - 3)); } GXSetTevIndirect(GX_TEVSTAGE1, GX_INDTEXSTAGE1, GX_ITF_8, GX_ITB_NONE, GX_ITM_0, GX_ITW_OFF, GX_ITW_0, GX_TRUE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD1, GX_TEXMAP0, GX_COLOR_NULL); GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_C2, GX_CC_ZERO, GX_CC_ZERO, GX_CC_TEXC); GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_TEXA); GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevDirect(GX_TEVSTAGE2); GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR_NULL); const static GXColor color_thres = { 0xff, 1, 0, 0 }; GXSetTevColor(GX_TEVREG0, color_thres); GXSetTevColorIn(GX_TEVSTAGE2, GX_CC_C0, GX_CC_C2, GX_CC_CPREV, GX_CC_ZERO); GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_COMP_GR16_GT, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaIn(GX_TEVSTAGE2, GX_CA_APREV, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_ALWAYS, 0); u32 n_verts = 0; for (i = 0; i < 0x100; i += 4) { if (c == 0 || (wp->work_priv._2940[i]._02 & 0x20) != 0) { n_verts += wp->work_priv._0300[i >> 2]; } } u32 idx = 0x100-4; u32 idx2 = 0x40-1; GXBegin(GX_QUADS, GX_VTXFMT0, n_verts); while (TRUE) { _0340_struct* _0340_thing = &wp->work_priv._0340[idx2]; u8* bruh = _0340_thing->_00; // u32 scanline_idx = wp->work_priv._2940[idx]; u32 flags = wp->work_priv._2940[idx]._01; u32 flags2; if (wp->work_priv._0B40[wp->work_priv._2940[idx]._00]._18 & 0x20) { flags2 = wp->work_priv._0B40[wp->work_priv._2940[idx]._00]._08[(flags >> 6) | ((flags & 1) << 2)]; flags &= (u8)~0x01; } else { flags2 = wp->work_priv._0B40[wp->work_priv._2940[idx]._00]._08[(flags >> 6) | ((wp->work_priv._0B40[wp->work_priv._2940[idx]._00]._18 >> 1) & 4)]; } // u32 flags3 = wp->work_priv._2940[idx + 2]; u32 x0 = wp->work_priv._2940[idx]._03 + 128; u32 x1 = wp->work_priv._2940[idx]._03 + 136; u32 color = ((wp->work_priv._2940[idx]._02 & 3) * 0x10 + 4) * 0x01000000; if (c != 0) { if ((flags & 0x20) == 0) { goto loop_condition; } } else { if ((flags & 0x20) != 0) { color |= 0xFF010000; } } u32 s0; u32 t0; u32 s1; u32 s1_2; u32 t1; u32 t1_2; u32 temp; // u32 j; s0 = 0; t0 = (flags2 & (u8)~0x01) * 2; temp = ((flags & 0x3F) * 0x20) | ((flags2 & 0x01) * 0x800); if (wp->work_priv._2940[idx]._02 & 0x40) { s1 = temp + 32; s1_2 = temp; } else { s1 = temp; s1_2 = temp + 32; } for (j = 0; j < wp->work_priv._0300[idx >> 2]; j += 4) { u32 y0 = -129 - bruh[0]; t1 = bruh[1]; u32 y1 = -129 - bruh[2]; t1_2 = bruh[3]; bruh += 4; GXPosition2s16(x0, y0); GXColor1u32(color); GXTexCoord2u16(s0, t0); GXTexCoord2u16(s1, t1); GXPosition2s16(x1, y0); GXColor1u32(color); GXTexCoord2u16(s0, t0); GXTexCoord2u16(s1_2, t1); GXPosition2s16(x1, y1); GXColor1u32(color); GXTexCoord2u16(s0, t0); GXTexCoord2u16(s1_2, t1_2); GXPosition2s16(x0, y1); GXColor1u32(color); GXTexCoord2u16(s0, t0); GXTexCoord2u16(s1, t1_2); } loop_condition: if (idx == 0) { break; } idx -= 4; idx2--; } GXEnd(); if (c != 0) { u32 n = ksNesDrawMakeOBJBlankVtxList(wp); if (n != 0) { GXSetNumChans(1); GXSetNumTexGens(0); GXSetNumTevStages(1); GXSetNumIndStages(0); GXSetBlendMode(GX_BM_LOGIC, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GXSetTevDirect(GX_TEVSTAGE0); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, GX_LIGHT_NULL, GX_DF_NONE, GX_AF_NONE); GXSetTevOp(GX_TEVSTAGE0, GX_PASSCLR); GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); GXBegin(GX_QUADS, GX_VTXFMT0, n * 2); for (u32 i = 0; i < n; i += 2) { s16 x1 = (wp->work_priv._0B40[wp->work_priv._0000[i]]._19 & 0x14) == 0x10 ? 136 : 384; GXPosition2s16(128, -128 - wp->work_priv._0000[i]); GXColor1u32(0x00000000); GXPosition2s16(x1, -128 - wp->work_priv._0000[i]); GXColor1u32(0x00000000); GXPosition2s16(x1, -128 - wp->work_priv._0000[i] - wp->work_priv._0000[i + 1]); GXColor1u32(0x00000000); GXPosition2s16(128, -128 - wp->work_priv._0000[i] - wp->work_priv._0000[i + 1]); GXColor1u32(0x00000000); } GXEnd(); } } } void ksNesDrawOBJMMC5(ksNesCommonWorkObj*, ksNesStateObj*, u32) { } 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); GXSetCopyClear(black, 0xffffff); GXCopyTex(buf, GX_FALSE); GXPixModeSync(); GXInvalidateTexAll(); } void ksNesDrawOBJI8ToEFB(ksNesCommonWorkObj* wp, u8* buf) { GXTexObj obj; u32 i; s32 u; u8* work; u32 cnt; GXSetNumChans(0); GXSetNumTexGens(1); GXSetNumTevStages(1); GXSetNumIndStages(0); GXSetBlendMode(GX_BM_LOGIC, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_COPY); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U16, 8); GXInitTexObj(&obj, (void*)buf, 256, 228, GX_TF_I8, GX_CLAMP, GX_CLAMP, 0); GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&obj, GX_TEXMAP0); GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 60); GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 0x100, 0x100); GXSetTexCoordBias(GX_TEXCOORD0, 0, 0); GXSetTevDirect(GX_TEVSTAGE0); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); GXSetAlphaCompare(GX_GREATER, 0, GX_AOP_AND, GX_ALWAYS, 0); cnt = ksNesDrawMakeOBJAppearVtxList(wp); if (cnt == 0) return; GXBegin(GX_QUADS, GX_VTXFMT0, cnt * 2); for (i = 0; i < cnt; i += 2) { work = (u8*)wp + i; // if it works... u = (wp->work_priv._0B40[(u8)((u8*)wp)[i + 0x60]]._19 & 0x14) == 0x10 ? 8 : 0; GXPosition2s16(u + 0x80, -128 - work[0x60]); GXTexCoord2u16(u, work[0x60] - 8); GXPosition2s16(0x180, -128 - work[0x60]); GXTexCoord2u16(0x100, work[0x60] - 8); GXPosition2s16(0x180, -128 - work[0x60] - work[0x61]); GXTexCoord2u16(0x100, work[0x60] + work[0x61] - 8); GXPosition2s16(u + 0x80, -128 - work[0x60] - work[0x61]); GXTexCoord2u16(u, work[0x60] + work[0x61] - 8); } GXEnd(); } void ksNesDrawEmuResult(ksNesCommonWorkObj* wp) { static f32 indtexmtx[2][3] = { { 1.0f, 0.0f, 0.0f }, { 0.0f, 0.0f, 0.0f } }; static const GXColor black2 = { 0, 0, 0, 0 }; // unused, corrects stack static const GXColor black = { 0, 0, 0, 0 }; static const GXColor color0 = { 0x3A, 0x3A, 0x3A, 0x00 }; static const GXColor color1 = { 0x71, 0x71, 0x71, 0x00 }; static const GXColor color2 = { 0x15, 0x15, 0x15, 0x00 }; u32 cnt; u32 i; u32 unk_r7; u8 y; u32 val; u32 clr; u8 *work; GXTexObj obj; GXTexObj obj2; cnt = 0; i = 8; unk_r7 = 0xFF; for (; i < 228 + 8; i++) { val = wp->work_priv._0B40[i]._19 & 0xE1; if (val != unk_r7) { unk_r7 = val; if ((cnt & 1) != 0) { wp->work_priv._0000[cnt++] = i - 8; } wp->work_priv._0000[cnt++] = i - 8; } } if ((cnt & 1) != 0) { wp->work_priv._0000[cnt++] = i - 8; } wp->work_priv._0000[cnt] = 0xFF; GXInitTexObj(&obj2, wp->result_bufp, 256, 228, GX_TF_I8, GX_CLAMP, GX_CLAMP, 0); GXInitTexObjLOD(&obj2, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&obj2, GX_TEXMAP1); GXInitTexObj(&obj, wp->work_priv._2A40, 256, 4, GX_TF_RGB5A3, GX_CLAMP, GX_CLAMP, 0); GXInitTexObjLOD(&obj, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&obj, GX_TEXMAP0); GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 60, GX_FALSE, 125); GXSetTexCoordScaleManually(GX_TEXCOORD0, GX_TRUE, 256, 256); GXSetTexCoordBias(GX_TEXCOORD0, 0, 0); GXSetIndTexOrder(GX_INDTEXSTAGE0, GX_TEXCOORD0, GX_TEXMAP1); GXSetIndTexCoordScale(GX_INDTEXSTAGE0, GX_ITS_1, GX_ITS_1); GXSetIndTexMtx(GX_ITM_0, indtexmtx, 1); GXSetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_0, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_AND, GX_ALWAYS, 0); cnt = 0; for (i = 0; wp->work_priv._0000[i] != 0xFF; i += 2) { val = wp->work_priv._0B40[wp->work_priv._0000[i]]._19; if ((val & 0xE1) == 0) { cnt += 4; } } if (cnt != 0) { GXSetNumChans(0); GXSetNumTexGens(1); GXSetNumTevStages(1); GXSetNumIndStages(1); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U16, 8); GXSetTevOp(GX_TEVSTAGE0, GX_REPLACE); GXBegin(GX_QUADS, GX_VTXFMT0, cnt); do { i -= 2; work = ((u8*)wp + i); val = wp->work_priv._0B40[work[0x60]]._19 & 0xE1; if (val == 0) { GXPosition2s16(0x180, -136 - work[0x60]); GXTexCoord2u16(0x100, work[0x60]); GXPosition2s16(0x180, -136 - work[0x61]); GXTexCoord2u16(0x100, work[0x61]); GXPosition2s16(0x080, -136 - work[0x61]); GXTexCoord2u16(0x000, work[0x61]); GXPosition2s16(0x080, -136 - work[0x60]); GXTexCoord2u16(0x000, work[0x60]); } } while (i != 0); } cnt = 0; for (i = 0; wp->work_priv._0000[i] != 0xFF; i += 2) { val = wp->work_priv._0B40[wp->work_priv._0000[i]]._19; if ((val & 0xE1) != 0) { cnt += 4; } } if (cnt != 0) { GXSetNumChans(1); GXSetNumTexGens(1); GXSetNumTevStages(4); GXSetNumIndStages(1); GXClearVtxDesc(); GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_CLR0, GX_DIRECT); GXSetVtxDesc(GX_VA_TEX0, GX_DIRECT); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XY, GX_S16, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_U16, 8); GXSetTevIndirect(GX_TEVSTAGE0, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_0, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE0, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); GXSetTevIndirect(GX_TEVSTAGE1, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_0, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE1, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); GXSetTevIndirect(GX_TEVSTAGE2, GX_INDTEXSTAGE0, GX_ITF_8, GX_ITB_NONE, GX_ITM_0, GX_ITW_0, GX_ITW_0, GX_FALSE, GX_FALSE, GX_ITBA_OFF); GXSetTevOrder(GX_TEVSTAGE2, GX_TEXCOORD0, GX_TEXMAP0, GX_COLOR_NULL); GXSetTevDirect(GX_TEVSTAGE3); GXSetTevOrder(GX_TEVSTAGE3, GX_TEXCOORD_NULL, GX_TEXMAP_NULL, GX_COLOR0A0); GXSetChanCtrl(GX_COLOR0A0, GX_FALSE, GX_SRC_VTX, GX_SRC_VTX, 0, GX_DF_NONE, GX_AF_NONE); GXSetTevSwapModeTable(GX_TEV_SWAP1, GX_CH_RED, GX_CH_RED, GX_CH_RED, GX_CH_ALPHA); GXSetTevSwapModeTable(GX_TEV_SWAP2, GX_CH_GREEN, GX_CH_GREEN, GX_CH_GREEN, GX_CH_ALPHA); GXSetTevSwapModeTable(GX_TEV_SWAP3, GX_CH_BLUE, GX_CH_BLUE, GX_CH_BLUE, GX_CH_ALPHA); GXSetTevSwapMode(GX_TEVSTAGE0, GX_TEV_SWAP0, GX_TEV_SWAP1); GXSetTevSwapMode(GX_TEVSTAGE1, GX_TEV_SWAP0, GX_TEV_SWAP2); GXSetTevSwapMode(GX_TEVSTAGE2, GX_TEV_SWAP0, GX_TEV_SWAP3); GXSetTevSwapMode(GX_TEVSTAGE3, GX_TEV_SWAP0, GX_TEV_SWAP0); GXSetTevColorIn(GX_TEVSTAGE0, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C0, GX_CC_ZERO); GXSetTevColorIn(GX_TEVSTAGE1, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C1, GX_CC_CPREV); GXSetTevColorIn(GX_TEVSTAGE2, GX_CC_ZERO, GX_CC_TEXC, GX_CC_C2, GX_CC_CPREV); GXSetTevColorIn(GX_TEVSTAGE3, GX_CC_RASC, GX_CC_ZERO, GX_CC_ZERO, GX_CC_CPREV); GXSetTevColorOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevColorOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevColorOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevColorOp(GX_TEVSTAGE3, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaIn(GX_TEVSTAGE0, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaIn(GX_TEVSTAGE1, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaIn(GX_TEVSTAGE2, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaIn(GX_TEVSTAGE3, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO, GX_CA_ZERO); GXSetTevAlphaOp(GX_TEVSTAGE0, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaOp(GX_TEVSTAGE1, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaOp(GX_TEVSTAGE2, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevAlphaOp(GX_TEVSTAGE3, GX_TEV_ADD, GX_TB_ZERO, GX_CS_SCALE_1, GX_TRUE, GX_TEVPREV); GXSetTevColor(GX_TEVREG0, color0); GXSetTevColor(GX_TEVREG1, color1); GXSetTevColor(GX_TEVREG2, color2); GXBegin(GX_QUADS, GX_VTXFMT0, cnt); do { i -= 2; work = (u8*)wp + i; if ((wp->work_priv._0B40[work[0x60]]._19 & 0xE1) != 0) { clr = 0x2F2F2F00; if ((wp->work_priv._0B40[work[0x60]]._19 & 0x20) != 0) { clr += 0x10000000; } if ((wp->work_priv._0B40[work[0x60]]._19 & 0x40) != 0) { clr += 0x00100000; } if ((wp->work_priv._0B40[work[0x60]]._19 & 0x80) != 0) { clr += 0x00001000; } GXPosition2s16(0x180, -136 - work[0x60]); GXColor1u32(clr); GXTexCoord2u16(0x100, work[0x60]); GXPosition2s16(0x180, -136 - work[0x61]); GXColor1u32(clr); GXTexCoord2u16(0x100, work[0x61]); GXPosition2s16(0x080, -136 - work[0x61]); GXColor1u32(clr); GXTexCoord2u16(0x000, work[0x61]); GXPosition2s16(0x080, -136 - work[0x60]); GXColor1u32(clr); GXTexCoord2u16(0x000, work[0x60]); } } while (i != 0); } GXSetTexCopySrc(128, 136, 256, 228); GXSetTexCopyDst(256, 228, GX_TF_RGB565, GX_FALSE); GXSetCopyClear(black, 0xFFFFFF); GXCopyTex(wp->result_bufp, GX_FALSE); GXPixModeSync(); } void ksNesDraw(ksNesCommonWorkObj* wp, ksNesStateObj* state) { ksNesDrawInit(wp); ksNesDrawClearEFBFirst(wp); if (state->mapper == 9 || state->mapper == 10) { ksNesDrawMakeBGIndTexMMC2(wp, state->mapper == 9 ? TRUE : FALSE); ksNesDrawOBJSetupMMC2(wp); } else if (state->mapper == 5) { ksNesDrawMakeBGIndTexMMC5(wp, state); } else { ksNesDrawMakeBGIndTex(wp, state->mapper == 4 ? TRUE : FALSE); } PPCSync(); if (state->mapper == 5) { ksNesDrawOBJMMC5(wp, state, 0); } else { ksNesDrawOBJ(wp, state, 0); } ksNesDrawFlushEFBToRed8(wp->result_bufp); if (state->mapper == 5) { ksNesDrawOBJMMC5(wp, state, 1); } else { ksNesDrawOBJ(wp, state, 1); } ksNesDrawBG(wp, state); ksNesDrawOBJI8ToEFB(wp, wp->result_bufp); ksNesDrawFlushEFBToRed8(wp->result_bufp); ksNesDrawEmuResult(wp); ksNesDrawEnd(); }