diff --git a/ChangeLog.txt b/ChangeLog.txt index d3993ea..4de54c4 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -1,3 +1,18 @@ +15-09-2024 cfg 70r78.13 (release) + - Internals - changed memory start addres to avoid overlaps + - Graphics - added options for 480p Nintendo Revolution SDK bug fix patch (Thanks leseratte) + - Graphics - added options for deflickering settings (Thanks blackb0x) + - Graphics - added options for disabling dithering (Thanks blackb0x) + - Graphics - added options for framebuffer width patch (Thanks blackb0x) + - Languages - Updated KO.lang (Thanks DDinghoya) + - Languages - Updated ZH_CN.lang (Thanks kavid) + - Documentation - Moved README-CFG.txt to README.md and converted to markdown format + +03-09-2024 cfg 70r78.12 (release) + - Internals - changed online update URL paths + - GC - updated nintendont config support to version 0x0000000A + - Usability - Wiimmfi WFC patching fixed (Thanks leseratte) + 15-01-2017 cfg 70r78.11 (release) - GC - updated nintendont config support to version 0x00000006 - GC - if nintendont_config_mode=arg is set nintendont configuration is passed via command line argument diff --git a/Languages/ZH_CN.lang b/Languages/ZH_CN.lang index d09e8cc..48c0114 100644 --- a/Languages/ZH_CN.lang +++ b/Languages/ZH_CN.lang @@ -1,7 +1,7 @@ -# Configurable USB Loader ZH-CN By 91wii.com -# Copyright (C) 2010 91wii.Com THE PACKAGE'S COPYRIGHT HOLDER -# This file is distributed under the same license as the PACKAGE package. -# Kavid , 2010. +# CFG USB Loader language file template. +# Put the translated string in msgstr "" +# Fill in the Last-Translator and Language-Team fields. +# Please use utf-8 charset when editing. # #, fuzzy msgid "" @@ -15,7 +15,18 @@ msgstr "" "MIME-Version: 2.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Language: Simplified Chinese\n" + +msgid " 59 blocks" +msgstr "59格" + +msgid " 123 blocks" +msgstr "123格" + +msgid " 251 blocks" +msgstr "251格" + +msgid " 507 blocks" +msgstr "507格" #, c-format msgid "%.1fGB free of %.1fGB" @@ -74,6 +85,9 @@ msgstr ".dol文件太小" msgid "1.2+" msgstr "1.2以上版本" +msgid "1019 blocks" +msgstr "1019格" + msgid "1st-Person Shooter" msgstr "第一人称射击" @@ -86,6 +100,9 @@ msgstr "2.1以上版本" msgid "2.2+" msgstr "2.2以上版本" +msgid "2043 blocks" +msgstr "2043格" + msgid "3D cover" msgstr "3D封面" @@ -216,9 +233,15 @@ msgstr "平衡板游戏" msgid "Boot Disc" msgstr "启动光盘" +msgid "Boot Method:" +msgstr "引导方式:" + msgid "Boot disc" msgstr "运行光盘" +msgid "Boot method:" +msgstr "引导方式:" + msgid "Booting game, please wait..." msgstr "正在启动游戏,请稍等..." @@ -367,6 +390,9 @@ msgstr "板球" msgid "Current Version: %s" msgstr "当前版本:%s" +msgid "Custom" +msgstr "自定义" + #, c-format msgid "" "Custom IOS %d could not be found!\n" @@ -390,6 +416,9 @@ msgstr "cIOS %s加载成功!" msgid "DEVO" msgstr "DEVO" +msgid "DIOS MIOS" +msgstr "DIOS MIOS" + msgid "DISC cover" msgstr "光盘封面" @@ -411,6 +440,12 @@ msgstr "数据库更新成功。" msgid "Debug" msgstr "调试" +msgid "Default" +msgstr "缺省" + +msgid "Default Gamecube Loader:" +msgstr "缺省GameCube启动器:" + msgid "Delete Game" msgstr "删除游戏" @@ -475,6 +510,10 @@ msgstr "下载游戏信息" msgid "Downloadable Content" msgstr "支持下载增值内容(DLC)" +#, c-format +msgid "Downloading %s plugin." +msgstr "正在下载 %s 插件。" + msgid "Downloading ALL MISSING covers" msgstr "正在下载所有缺失的封面" @@ -501,12 +540,6 @@ msgstr "正在下载数据库" msgid "Downloading devolution." msgstr "正在下载devolution。" -msgid "Downloading mighty plugin." -msgstr "正在下载mighty插件。" - -msgid "Downloading neek2o plugin." -msgstr "正在下载neek2o 插件。" - msgid "Downloading titles.txt ..." msgstr "正在下载titles.txt文件..." @@ -836,6 +869,9 @@ msgstr "平面封面" msgid "FULL cover" msgstr "完整封面" +msgid "FWD Emulators" +msgstr "FWD模拟器" + msgid "Fav" msgstr "收藏" @@ -900,9 +936,6 @@ msgstr "飞行模拟" msgid "Football" msgstr "足球" -msgid "Force Devolution:" -msgstr "强制Devolution:" - msgid "Force NTSC" msgstr "强制NTSC" @@ -1142,6 +1175,12 @@ msgstr "读取中..." msgid "Loading..%s\n" msgstr "正在读取..%s\n" +msgid "MC size:" +msgstr "MC大小:" + +msgid "MC size::" +msgstr "MC大小:" + msgid "Main" msgstr "主菜单" @@ -1323,9 +1362,19 @@ msgstr "对应Nintendo DS" msgid "Nintendo DS Connectivity" msgstr "支持与Nintendo DS联动" +msgid "Nintendont" +msgstr "Nintendont" + +#, c-format +msgid "Nintendont Ver. %d.%d\n" +msgstr "Nintendont 版本. %d.%d\n" + msgid "No" msgstr "否" +msgid "No Speed Limit:" +msgstr "无速度限制:" + #, c-format msgid "No domain part in URL '%s'" msgstr "URL'%s'中没有域名部分" @@ -1345,6 +1394,9 @@ msgstr "未找到更新" msgid "NoDisc:" msgstr "免光盘:" +msgid "NoSSL only" +msgstr "仅用NoSSL" + msgid "None found on disc" msgstr "光盘上未找到内容" @@ -1676,6 +1728,9 @@ msgstr "按%s键弹出DVD光盘" msgid "Priiloader" msgstr "Priiloader" +msgid "Private server:" +msgstr "私服:" + msgid "Profile:" msgstr "配置:" @@ -1735,6 +1790,9 @@ msgstr "发售日期" msgid "Release Notes: (short)" msgstr "发布说明:(简介)" +msgid "Remove Speed Limit:" +msgstr "删除速度限制:" + msgid "Removing game, please wait..." msgstr "正在删除游戏,请稍候..." @@ -1842,6 +1900,9 @@ msgstr "已选游戏" msgid "Settings" msgstr "设置" +msgid "Shared" +msgstr "已分享" + msgid "Shooter" msgstr "射击游戏" @@ -2317,47 +2378,5 @@ msgstr "无法打开Wii光盘" msgid "used: %p - %p" msgstr "已使用: %p - %p" -#~ msgid " Copying files from USB to SD card...(%c)" -#~ msgstr "正在把文件从USB设备中复制到SD卡中...(%c)" - -#~ msgid "Booting Wii game, please wait..." -#~ msgstr "正在启动Wii游戏,请稍候......" - -#~ msgid "Console Def." -#~ msgstr "主机定义。" - -#~ msgid "DISK1:%s[%s]\n" -#~ msgstr "磁盘1:%s[%s]\n" - -#~ msgid "DISK2:%s[%s]2\n" -#~ msgstr "磁盘2:%s[%s]2\n" - -#~ msgid "Download titles.txt" -#~ msgstr "下载Titltes.txt文件" - -#~ msgid "Front" -#~ msgstr "前" - -#~ msgid "Loading previous game list..." -#~ msgstr "正在读取上次游戏列表..." - -#~ msgid "Not Found boot.dol!!" -#~ msgstr "未找到Boot.dol!" - -#~ msgid "Remove Game" -#~ msgstr "删除游戏" - -#~ msgid "Synopsis Len" -#~ msgstr "摘要长度" - -#~ msgid "Update WiiTDB Game Database" -#~ msgstr "更新WiiTDB游戏数据库" - -#~ msgid "Update titles.txt" -#~ msgstr "更新titles.txt" - -#~ msgid "WiiTDB Game Database" -#~ msgstr "WiiTDB游戏数据库" - -#~ msgid "Wiird" -#~ msgstr "Wii金手指" +msgid "wiimmfi.de" +msgstr "wiimmfi.de" diff --git a/Languages/lang.pot b/Languages/lang.pot index c00fe8d..5686058 100644 --- a/Languages/lang.pot +++ b/Languages/lang.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2017-01-15 00:36+0100\n" +"POT-Creation-Date: 2024-09-14 22:07+0200\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -442,6 +442,12 @@ msgstr "" msgid "Default Gamecube Loader:" msgstr "" +msgid "Defaults" +msgstr "" + +msgid "Deflicker Filter:" +msgstr "" + msgid "Delete Game" msgstr "" @@ -466,6 +472,9 @@ msgstr "" msgid "Devolution only accepts clean dumps!\n" msgstr "" +msgid "Disable Dithering:" +msgstr "" + msgid "Disc" msgstr "" @@ -917,6 +926,9 @@ msgstr "" msgid "Fitness" msgstr "" +msgid "Fix 480p:" +msgstr "" + msgid "Fixing EXTEND partition..." msgstr "" @@ -951,6 +963,9 @@ msgstr "" msgid "Found %s" msgstr "" +msgid "Framebuffer width:" +msgstr "" + msgid "French" msgstr "" @@ -1382,12 +1397,27 @@ msgstr "" msgid "Nunchuk" msgstr "" +msgid "OFF (Extended)" +msgstr "" + +msgid "OFF (Safe)" +msgstr "" + msgid "OK" msgstr "" msgid "OK!" msgstr "" +msgid "ON (High)" +msgstr "" + +msgid "ON (Low)" +msgstr "" + +msgid "ON (Medium)" +msgstr "" + msgid "Ocarina (cheats):" msgstr "" diff --git a/Makefile b/Makefile index d2dd9de..971dcdb 100644 --- a/Makefile +++ b/Makefile @@ -15,7 +15,7 @@ include $(DEVKITPPC)/wii_rules # SOURCES is a list of directories containing source code # INCLUDES is a list of directories containing extra header files #--------------------------------------------------------------------------------- -VERSION := 70r78.12 +VERSION := 70r78.13 RELEASE := release # to override RELEASE use: make announce RELEASE=beta ifeq ($(findstring compat,$(VERSION)),compat) @@ -63,8 +63,16 @@ BUILD_DEBUG := 0 ifeq ($(BUILD_DEBUG),1) BUILD := build_dbg TARGET := $(BINBASE)-dbg - BUILD_DBG_FLAG := -DBUILD_DBG=3 + BUILD_DBG_FLAG := -DBUILD_DBG=3 -DDEBUG_PATCH=1 endif + +BUILD_DEBUG_PATCH := 0 +ifeq ($(BUILD_DEBUG_PATCH),1) + BUILD := build_dbg_patch + TARGET := $(BINBASE)-dbg-patch + BUILD_DBG_FLAG := -DDEBUG_PATCH=1 +endif + #"-g" tells the compiler to include support for the debugger #"-Wall" tells it to warn us about all suspicious-looking code DEBUG_OPT = -Os @@ -74,12 +82,13 @@ CFLAGS = $(DEBUG_OPT) -Wall $(MACHDEP) $(INCLUDE) $(BUILD_FLAGS) $(DEFINES) CXXFLAGS = $(CFLAGS) # start address: -# Original: 0x80a00100 -# NeoGammaR4: 0x80dfff00 -# cfg 33-36: 0x80c00000 -# cfg 37-49: 0x80b00000 -# cfg 50-..: 0x80a80000 -LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80a80000 +# Original: 0x80a00100 +# NeoGammaR4: 0x80dfff00 +# cfg 33-36: 0x80c00000 +# cfg 37-49: 0x80b00000 +# cfg 50-..: 0x80a80000 +# cfg 70r78.13-..: 0x80a50000 +LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=0x80a50000 #--------------------------------------------------------------------------------- # any extra libraries we wish to link with the project @@ -167,6 +176,9 @@ $(BUILD): debug: @$(MAKE) --no-print-directory BUILD_DEBUG=1 + +debug_patch: + @$(MAKE) --no-print-directory BUILD_DEBUG_PATCH=1 #--------------------------------------------------------------------------------- lang: @@ -188,6 +200,7 @@ clean: @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol @rm -fr $(BUILD)_222 $(OUTPUT)-222.elf $(OUTPUT)-222.dol @rm -fr $(BUILD)_dbg $(OUTPUT)-dbg.elf $(OUTPUT)-dbg.dol + @rm -fr $(BUILD)_dbg_patch $(OUTPUT)-dbg-patch.elf $(OUTPUT)-dbg-patch.dol cleanall: clean @rm -fr *.dol *.elf diff --git a/README.md b/README.md index 961417b..d0a89b9 100644 --- a/README.md +++ b/README.md @@ -1099,6 +1099,24 @@ Example: # 1 = NoSSL only # 2 = wiimmfi.de # 3 = Custom string from "custom_private_server" + # + # fix_480p = [0], 1 + # enable/disable 480p Nintendo Revolution SDK bug fix patch + # + # deflicker = [0], 1, 2, 3, 4, 5 + # override deflicker filter settings: + # 0 = Defaults as hardcoded in the game + # 1 = Turns off deflickering setting the vfilter to Off + # 2 = Turns off deflickering setting the vfilter and patchig GXSetCopyFilter function + # 3 = Turns on deflickering setting vfilter to Low + # 4 = Turns on deflickering setting vfilter to Medium + # 5 = Turns on deflickering setting vfilter to High + # + # dithering = [0], 1 + # enable/disable dithering removal patch + # + # fix_fb = [0], 1 + # enable/disable framebuffer width patch # # Profile Options: # ================ diff --git a/data/intro4.jpg b/data/intro4.jpg index 96482db..9fb1da3 100644 Binary files a/data/intro4.jpg and b/data/intro4.jpg differ diff --git a/source/apploader.c b/source/apploader.c index 7cc23b3..df8bdd0 100644 --- a/source/apploader.c +++ b/source/apploader.c @@ -17,6 +17,7 @@ #include "gettext.h" #include "menu.h" #include "dolmenu.h" +#include "deflicker.h" /* Apploader function pointers */ typedef int (*app_main)(void **dst, int *size, int *offset); @@ -291,8 +292,7 @@ s32 Apploader_Run(entry_point *entry) TIME.size += appldr_len; // used mem range by the loader - //void *mem_start = (void*)0x80b00000; // as set in Makefile - void *mem_start = (void*)0x80a80000; // as set in Makefile + void *mem_start = (void*)0x80a50000; // as set in Makefile void *mem_end = memalign(32,32); //printf("malloc = %p sta = %p\n", mem, &ret); @@ -753,6 +753,54 @@ void maindolpatches(void *dst, int len) if (!CFG.disable_pop_patch) { PrinceOfPersiaPatch(); } + + // Deflicker filter patch + if (CFG.game.deflicker == DEFLICKER_ON_LOW) + { + patch_vfilters(dst, len, vfilter_low); + patch_vfilters_rogue(dst, len, vfilter_low); + } + else if (CFG.game.deflicker == DEFLICKER_ON_MEDIUM) + { + patch_vfilters(dst, len, vfilter_medium); + patch_vfilters_rogue(dst, len, vfilter_medium); + } + else if (CFG.game.deflicker == DEFLICKER_ON_HIGH) + { + patch_vfilters(dst, len, vfilter_high); + patch_vfilters_rogue(dst, len, vfilter_high); + } + else if (CFG.game.deflicker != DEFLICKER_DEFAULT) + { + patch_vfilters(dst, len, vfilter_off); + patch_vfilters_rogue(dst, len, vfilter_off); + // This might break fade and brightness effects + if (CFG.game.deflicker == DEFLICKER_OFF_EXTENDED) + deflicker_patch(dst, len); + } + + // 480p Pixel Fix + if (CFG.game.fix_480p) { + PatchFix480p(); + } + + // Dithering patch + if (CFG.game.dithering) { + dithering_patch(dst, len); + } + + // Framebuffer width patch + if (CFG.game.fix_fb) { + framebuffer_patch(dst, len); + } + +#ifdef DEBUG_PATCH + // wait to read debug output + printf_(gt("Press any button...")); + printf("\n"); + Wpad_WaitButtons(); +#endif + // Nintendo Wi-Fi Connection (WFC) patch if (CFG.game.private_server) { NoSSLPatch(dst, len); diff --git a/source/cfg.c b/source/cfg.c index 7a4c7c4..13f62cb 100644 --- a/source/cfg.c +++ b/source/cfg.c @@ -484,6 +484,17 @@ struct TextMap map_private_server[] = { NULL, -1 } }; +struct TextMap map_deflicker[] = +{ + { "Defaults", 0 }, + { "OFF (Safe)", 1 }, + { "OFF (Extended)", 2 }, + { "ON (Low)", 3 }, + { "ON (Medium)", 4 }, + { "ON (High)", 5 }, + { NULL, -1 } +}; + struct playStat { char id[7]; s32 playCount; @@ -1423,6 +1434,10 @@ void CFG_Default() CFG.game.alt_controller_cfg = 0; CFG.game.rem_speed_limit = 0; CFG.game.private_server = 0; //off + CFG.game.deflicker = 0; //default game settings + CFG.game.fix_480p = 0; //off + CFG.game.dithering = 0; //default game settings + CFG.game.fix_fb = 0; //default game settings cfg_ios_set_idx(DEFAULT_IOS_IDX); // all other game settings are 0 (memset(0) above) STRCOPY(CFG.sort_ignore, "A,An,The"); @@ -2508,6 +2523,10 @@ void cfg_set_game(char *name, char *val, struct Game_CFG *game_cfg) cfg_map_auto("hooktype", map_hook, &game_cfg->hooktype); cfg_int_max("write_playlog", &game_cfg->write_playlog, 3); cfg_int_max("private_server", &game_cfg->private_server, 3); + cfg_int_max("deflicker", &game_cfg->deflicker, 5); + cfg_bool("fix_480p", &game_cfg->fix_480p); + cfg_bool("dithering", &game_cfg->dithering); + cfg_bool("fix_fb", &game_cfg->fix_fb); } @@ -3286,6 +3305,10 @@ bool CFG_Save_Settings(int verbose) SAVE_BOOL(alt_controller_cfg); SAVE_BOOL(rem_speed_limit); SAVE_NUM(private_server); + SAVE_NUM(deflicker); + SAVE_BOOL(fix_480p); + SAVE_BOOL(dithering); + SAVE_BOOL(fix_fb); if (game_cfg->clean == CFG_CLEAN_OFF) { SAVE_STR("clear_patches", "0"); } else if (game_cfg->clean == CFG_CLEAN_ON) { diff --git a/source/cfg.h b/source/cfg.h index 0bb86ac..77296b0 100644 --- a/source/cfg.h +++ b/source/cfg.h @@ -269,6 +269,10 @@ struct Game_CFG int alt_controller_cfg; int rem_speed_limit; int private_server; + int deflicker; + int fix_480p; + int dithering; + int fix_fb; }; struct Game_CFG_2 @@ -750,6 +754,7 @@ extern struct TextMap map_channel_boot[]; extern struct TextMap map_gc_boot[]; extern struct TextMap map_mem_card_size[]; extern struct TextMap map_private_server[]; +extern struct TextMap map_deflicker[]; extern char *names_vpatch[CFG_VIDEO_PATCH_NUM]; extern u8 cIOS_base[]; diff --git a/source/deflicker.c b/source/deflicker.c new file mode 100644 index 0000000..3e6e324 --- /dev/null +++ b/source/deflicker.c @@ -0,0 +1,184 @@ +/* + * Deflicker filter patching by wiidev (blackb0x @ GBAtemp) + */ + +#include +#include +#include +#include +#include + +#ifdef DEBUG_PATCH +#define debug_printf(fmt, args...) \ + printf(fmt, ##args) +#else +#define debug_printf(fmt, args...) +#endif + +static u8 PATTERN[12][2] = { + {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6}, + {6, 6}, {6, 6}, {6, 6} +}; + +static u8 PATTERN_AA[12][2] = { + {3, 2}, {9, 6}, {3, 10}, + {3, 2}, {9, 6}, {3, 10}, + {9, 2}, {3, 6}, {9, 10}, + {9, 2}, {3, 6}, {9, 10} +}; + +// Patch known and unknown vfilters within GXRModeObj structures +void patch_vfilters(u8 *addr, u32 len, u8 *vfilter) +{ + u8 *addr_start = addr; + while (len >= sizeof(GXRModeObj)) + { + GXRModeObj *vidmode = (GXRModeObj *)addr_start; + if ((memcmp(vidmode->sample_pattern, PATTERN, 24) == 0 || memcmp(vidmode->sample_pattern, PATTERN_AA, 24) == 0) && + (vidmode->fbWidth == 640 || vidmode->fbWidth == 608 || vidmode->fbWidth == 512) && + (vidmode->field_rendering == 0 || vidmode->field_rendering == 1) && + (vidmode->aa == 0 || vidmode->aa == 1)) + { + debug_printf("Replaced vfilter %02x%02x%02x%02x%02x%02x%02x @ %p (GXRModeObj)\n", + vidmode->vfilter[0], vidmode->vfilter[1], vidmode->vfilter[2], vidmode->vfilter[3], + vidmode->vfilter[4], vidmode->vfilter[5], vidmode->vfilter[6], addr_start); + memcpy(vidmode->vfilter, vfilter, 7); + addr_start += (sizeof(GXRModeObj) - 4); + len -= (sizeof(GXRModeObj) - 4); + } + addr_start += 4; + len -= 4; + } +} + +// Patch rogue vfilters found in some games +void patch_vfilters_rogue(u8 *addr, u32 len, u8 *vfilter) +{ + u8 known_vfilters[7][7] = { + {8, 8, 10, 12, 10, 8, 8}, // Ntsc480ProgSoft + {4, 8, 12, 16, 12, 8, 4}, // Ntsc480ProgAa + {7, 7, 12, 12, 12, 7, 7}, // Mario Kart Wii + {5, 5, 15, 14, 15, 5, 5}, // Mario Kart Wii + {4, 4, 15, 18, 15, 4, 4}, // Sonic Colors + {4, 4, 16, 16, 16, 4, 4}, // DKC Returns + {2, 2, 17, 22, 17, 2, 2} + }; + u8 *addr_start = addr; + u8 *addr_end = addr + len - 8; + while (addr_start <= addr_end) + { + u8 known_vfilter[7]; + int i; + for (i = 0; i < 7; i++) + { + int x; + for (x = 0; x < 7; x++) + known_vfilter[x] = known_vfilters[i][x]; + if (!addr_start[7] && memcmp(addr_start, known_vfilter, 7) == 0) + { + debug_printf("Replaced vfilter %02x%02x%02x%02x%02x%02x%02x @ %p\n", addr_start[0], addr_start[1], + addr_start[2], addr_start[3], addr_start[4], addr_start[5], addr_start[6], addr_start); + memcpy(addr_start, vfilter, 7); + addr_start += 7; + break; + } + } + addr_start += 1; + } +} + +// Patch GXSetCopyFilter to disable the deflicker filter +void deflicker_patch(u8 *addr, u32 len) +{ + u32 SearchPattern[18] = { + 0x3D20CC01, 0x39400061, 0x99498000, + 0x2C050000, 0x38800053, 0x39600000, + 0x90098000, 0x38000054, 0x39800000, + 0x508BC00E, 0x99498000, 0x500CC00E, + 0x90698000, 0x99498000, 0x90E98000, + 0x99498000, 0x91098000, 0x41820040}; + u8 *addr_start = addr; + u8 *addr_end = addr + len - sizeof(SearchPattern); + while (addr_start <= addr_end) + { + if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0) + { + *((u32 *)addr_start + 17) = 0x48000040; // Change beq to b + debug_printf("Patched GXSetCopyFilter @ %p\n", addr_start); + return; + } + addr_start += 4; + } +} + +// Patch Dithering +void dithering_patch(u8 *addr, u32 len) +{ + u32 SearchPattern[10] = { + 0x3C80CC01, 0x38A00061, 0x38000000, + 0x80C70220, 0x5066177A, 0x98A48000, + 0x90C48000, 0x90C70220, 0xB0070002, + 0x4E800020}; + u8 *addr_start = addr; + u8 *addr_end = addr + len - sizeof(SearchPattern); + while (addr_start <= addr_end) + { + if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0) + { + *((u32 *)addr_start - 1) = 0x48000028; + debug_printf("Patched Dithering @ %p\n", addr_start - 1); + return; + } + addr_start += 4; + } +} + +// Patch Framebuffer Width +void framebuffer_patch(void *addr, u32 len) +{ + u8 SearchPattern[32] = { + 0x40, 0x82, 0x00, 0x08, 0x48, 0x00, 0x00, 0x1C, + 0x28, 0x09, 0x00, 0x03, 0x40, 0x82, 0x00, 0x08, + 0x48, 0x00, 0x00, 0x10, 0x2C, 0x03, 0x00, 0x00, + 0x40, 0x82, 0x00, 0x08, 0x54, 0xA5, 0x0C, 0x3C}; + u8 *addr_start = (u8 *)addr; + u8 *addr_end = addr_start + len - sizeof(SearchPattern); + while (addr_start <= addr_end) + { + if (memcmp(addr_start, SearchPattern, sizeof(SearchPattern)) == 0) + { + if (addr_start[-0x70] == 0xA0 && addr_start[-0x6E] == 0x00 && addr_start[-0x6D] == 0x0A) + { + if (addr_start[-0x44] == 0xA0 && addr_start[-0x42] == 0x00 && addr_start[-0x41] == 0x0E) + { + u8 reg_a = (addr_start[-0x6F] >> 5); + u8 reg_b = (addr_start[-0x43] >> 5); + + // Patch to the framebuffer resolution + addr_start[-0x41] = 0x04; + + // Center the image + void *offset = addr_start - 0x70; + + u32 old_heap_ptr = *(u32 *)0x80003110; + *(u32 *)0x80003110 = old_heap_ptr - 0x40; + u32 heap_space = old_heap_ptr - 0x40; + + u32 org_address = (addr_start[-0x70] << 24) | (addr_start[-0x6F] << 16); + *(u32 *)(heap_space + 0x00) = org_address | 4; + *(u32 *)(heap_space + 0x04) = 0x200002D0 | (reg_b << 21) | (reg_a << 16); + *(u32 *)(heap_space + 0x08) = 0x38000002 | (reg_a << 21); + *(u32 *)(heap_space + 0x0C) = 0x7C000396 | (reg_a << 21) | (reg_b << 16) | (reg_a << 11); + + *(u32 *)offset = 0x48000000 + ((heap_space - (u32)offset) & 0x3ffffff); + *(u32 *)(heap_space + 0x10) = 0x48000000 + ((((u32)offset + 0x04) - (heap_space + 0x10)) & 0x3ffffff); + debug_printf("Patched resolution. Branched from 0x%x to 0x%x\n", (u32) offset, (u32) heap_space); + return; + } + } + } + addr_start += 4; + } +} \ No newline at end of file diff --git a/source/deflicker.h b/source/deflicker.h new file mode 100644 index 0000000..e0b8e8c --- /dev/null +++ b/source/deflicker.h @@ -0,0 +1,24 @@ +/* + * Deflicker filter patching by wiidev (blackb0x @ GBAtemp) + */ + +enum +{ + DEFLICKER_DEFAULT, + DEFLICKER_OFF, + DEFLICKER_OFF_EXTENDED, + DEFLICKER_ON_LOW, + DEFLICKER_ON_MEDIUM, + DEFLICKER_ON_HIGH +}; + +u8 vfilter_off[7] = {0, 0, 21, 22, 21, 0, 0}; +u8 vfilter_low[7] = {4, 4, 16, 16, 16, 4, 4}; +u8 vfilter_medium[7] = {4, 8, 12, 16, 12, 8, 4}; +u8 vfilter_high[7] = {8, 8, 10, 12, 10, 8, 8}; + +void patch_vfilters(u8 *addr, u32 len, u8 *vfilter); +void patch_vfilters_rogue(u8 *addr, u32 len, u8 *vfilter); +void deflicker_patch(u8 *addr, u32 len); +void dithering_patch(u8 *addr, u32 len); +void framebuffer_patch(void *addr, u32 len); \ No newline at end of file diff --git a/source/guimenu.c b/source/guimenu.c index dbf2194..140c536 100644 --- a/source/guimenu.c +++ b/source/guimenu.c @@ -478,6 +478,10 @@ struct W_GameCfg Widget *alt_controller_cfg; Widget *rem_speed_limit; Widget *private_server; + Widget *deflicker; + Widget *fix_480p; + Widget *dithering; + Widget *fix_fb; } wgame; @@ -1160,6 +1164,10 @@ void InitGameOptionsPage(Widget *pp, int bh) char *names_private_server[num_private_server]; num_private_server = map_to_list(map_private_server, num_private_server, names_private_server); + int num_deflicker = map_get_num(map_deflicker); + char *names_deflicker[num_deflicker]; + num_deflicker = map_to_list(map_deflicker, num_deflicker, names_deflicker); + ww = wgui_add_game_opt(op, gt("Language:"), CFG_LANG_NUM, languages); BIND_OPT(language); @@ -1218,7 +1226,19 @@ void InitGameOptionsPage(Widget *pp, int bh) ww = wgui_add_game_opt(op, gt("Private server:"), num_private_server, names_private_server); BIND_OPT(private_server); - + + ww = wgui_add_game_opt(op, gt("Fix 480p:"), 2, NULL); + BIND_OPT(fix_480p); + + ww = wgui_add_game_opt(op, gt("Deflicker Filter:"), num_deflicker, names_deflicker); + BIND_OPT(deflicker); + + ww = wgui_add_game_opt(op, gt("Disable Dithering:"), 2, NULL); + BIND_OPT(dithering); + + ww = wgui_add_game_opt(op, gt("Framebuffer width:"), 2, NULL); + BIND_OPT(fix_fb); + pos_move_to(pp, PAD0, -bh); pos_pad(pp, PAD0); pos_columns(pp, 4, SIZE_FULL); diff --git a/source/menu.c b/source/menu.c index 0212375..f29d3f9 100644 --- a/source/menu.c +++ b/source/menu.c @@ -212,6 +212,16 @@ char *str_private_server[4] = gts("Custom") }; +char *str_deflicker[6] = +{ + gts("Defaults"), + gts("OFF (Safe)"), + gts("OFF (Extended)"), + gts("ON (Low)"), + gts("ON (Medium)"), + gts("ON (High)") +}; + int Menu_Global_Options(); int Menu_Game_Options(); void Switch_Favorites(bool enable); @@ -1836,7 +1846,7 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { int opt_saved; //int opt_ios_reload; int opt_language, opt_video, opt_video_patch, opt_vidtv, opt_padhook, opt_nand_emu; - int opt_mem_card_emu, opt_mem_card_size, opt_country_patch, opt_anti_002, opt_ocarina, opt_wide_screen, opt_nodisc, opt_ntsc_j_patch, opt_screenshot, opt_private_server; + int opt_mem_card_emu, opt_mem_card_size, opt_country_patch, opt_anti_002, opt_ocarina, opt_wide_screen, opt_nodisc, opt_ntsc_j_patch, opt_screenshot, opt_private_server, opt_deflicker, opt_fix_480p, opt_dithering, opt_fix_fb; f32 size = 0.0; int redraw_cover = 0; int i; @@ -1882,7 +1892,7 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { game_cfg = &game_cfg2->curr; struct Menu menu; - int NUM_OPT = 20; + int NUM_OPT = 24; if (header->magic == GC_GAME_ON_DRIVE) NUM_OPT = 18; if (header->magic == CHANNEL_MAGIC) NUM_OPT = 19; char active[NUM_OPT]; @@ -1927,6 +1937,10 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { opt_ntsc_j_patch = game_cfg->ntsc_j_patch; opt_nand_emu = game_cfg->nand_emu; opt_private_server = game_cfg->private_server; + opt_deflicker = game_cfg->deflicker; + opt_fix_480p = game_cfg->fix_480p; + opt_dithering = game_cfg->dithering; + opt_fix_fb = game_cfg->fix_fb; if (game_cfg->clean == CFG_CLEAN_ALL) { opt_language = CFG_LANG_CONSOLE; @@ -1943,6 +1957,10 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { opt_nodisc = 0; opt_screenshot = 0; opt_private_server = 0; + opt_deflicker = 0; + opt_fix_480p = 0; + opt_dithering = 0; + opt_fix_fb = 0; active[1] = 0; // language active[2] = 0; // video active[3] = 0; // video_patch @@ -2174,6 +2192,14 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { PRINT_OPT_A(gt("Savegame:"), gt("Dump savegame")); if (menu_window_mark(&menu)) PRINT_OPT_A(gt("Private server:"), gt(str_private_server[opt_private_server])); + if (menu_window_mark(&menu)) + PRINT_OPT_B(gt("Fix 480p:"), opt_fix_480p); + if (menu_window_mark(&menu)) + PRINT_OPT_A(gt("Deflicker Filter:"), gt(str_deflicker[opt_deflicker])); + if (menu_window_mark(&menu)) + PRINT_OPT_B(gt("Disable Dithering:"), opt_dithering); + if (menu_window_mark(&menu)) + PRINT_OPT_B(gt("Framebuffer width:"), opt_fix_fb); } DefaultColor(); @@ -2445,6 +2471,18 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) { case 19: CHANGE(game_cfg->private_server, 3); break; + case 20: + CHANGE(game_cfg->fix_480p, 1); + break; + case 21: + CHANGE(game_cfg->deflicker, 5); + break; + case 22: + CHANGE(game_cfg->dithering, 1); + break; + case 23: + CHANGE(game_cfg->fix_fb, 1); + break; } } if (buttons & CFG.button_confirm.mask) { diff --git a/source/patchcode.c b/source/patchcode.c index 5b14634..8d1c99d 100644 --- a/source/patchcode.c +++ b/source/patchcode.c @@ -12,7 +12,12 @@ //#include "fwrite_patch.h" //#include "fwrite_patch_slota.h" //#include "main.h" +#ifdef DEBUG_PATCH +#define debug_printf(fmt, args...) \ + printf(fmt, ##args) +#else #define debug_printf(fmt, args...) +#endif bool hookpatched = false; @@ -1077,3 +1082,102 @@ u32 do_new_wiimmfi() { // returns 0 when all patching is done and game is ready to be booted. return 0; } + +/* + * 480p Pixel Fix Patch by leseratte + * + * fix for a Nintendo Revolution SDK bug found by Extrems affecting early Wii console when using 480p video mode. + * https://shmups.system11.org/viewtopic.php?p=1361158#p1361158 + * https://github.com/ExtremsCorner/libogc-rice/commit/941d687e271fada68c359bbed98bed1fbb454448 + * + */ +void PatchFix480p() +{ + u8 prefix[2] = { 0x4b, 0xff }; + + /// Patch offset: ----------VVVVVVVV + u32 Pattern_MKW[8] = { 0x38000065, 0x9b810019, 0x38810018, 0x386000e0, 0x98010018, 0x38a00002}; + u32 patches_MKW[2] = { 0x38600003, 0x98610019 }; + /// Used by: MKWii, Wii Play, Need for Speed Nitro, Wii Sports, ... + + /// Patch offset: ----------------------------------------------VVVVVVVV + u32 Pattern_NSMB[8] = { 0x38000065, 0x9801001c, 0x3881001c, 0x386000e0, 0x9b81001d, 0x38a00002}; + u32 patches_NSMB[2] = { 0x38a00003, 0x98a1001d }; + /// Used by: New Super Mario Bros, ... + + /* + * Code block that is being patched (in MKW): + * + * 4bffe30d: bl WaitMicroTime + * 38000065: li r0, 0x65 + * 9b810019: stb r28, 25(r1) // store the wrong value (1) + * 38810018: addi r4, r1, 0x18 + * 386000e0: li r3, 0xe0 + * 98010018: stb r0, 24(r1) + * 38a00002: li r5, 2 + * 4bffe73d: bl __VISendI2CData + * + * r28 is a register that is set to 1 at the beginning of the function. + * However, its contents are used elsewhere as well, so we can't just modify this one function. + * + * The following code first searches for one of the patterns above, then replaces the + * "stb r28, 25(r1)" instruction that stores the wrong value on the stack with a branch instead + * That branch branches to the injected custom code ("li r3, 3; stb r3, 25(r1)") that stores the + * correct value (3) instead. At the end of the injected code will be another branch that branches + * back to the instruction after the one that has been replaced (so, to "addi r4, r1, 0x18"). + * r3 can safely be used as a temporary register because its contents will be replaced immediately + * afterwards anyways. + * + */ + + void * offset = NULL; + void * addr = (void*)0x80000000; + u32 len = 0x900000; + + void * patch_ptr = 0 ; + void * a = addr; + + while ((char*)a < ((char*)addr + len)) { + if (memcmp(a, &Pattern_MKW, 6 * 4) == 0) { + // Found pattern? + if (memcmp(a - 4, &prefix, 2) == 0) { + if (memcmp(a + 8*4, &prefix, 2) == 0) { + offset = a + 4; + patch_ptr = &patches_MKW; + break; + } + } + } + else if (memcmp(a, &Pattern_NSMB, 6 * 4) == 0) { + // Found pattern? + if (memcmp(a - 4, &prefix, 2) == 0) { + if (memcmp(a + 8*4, &prefix, 2) == 0) { + offset = a + 16; + patch_ptr = &patches_NSMB; + break; + } + } + } + a+= 4; + } + + + + if (offset == 0) { + // offset is still 0, we didn't find the pattern, return + debug_printf("Didn't find offset for 480p patch!\n"); + return; + } + + // If we are here, we found the offset. Lets grab some space + // from the heap for our patch + u32 old_heap_ptr = *(u32*)0x80003110; + *((u32*)0x80003110) = (old_heap_ptr - 0x20); + u32 heap_space = old_heap_ptr-0x20; + debug_printf("Found offset for 480p patch - create branch from 0x%x to heap (0x%x)\n", (u32) offset, (u32) heap_space); + memcpy((void*)heap_space, patch_ptr, 8); + + *((u32*)offset) = 0x48000000 + (((u32)(heap_space) - ((u32)(offset))) & 0x3ffffff); + *((u32*)((u32)heap_space + 8)) = 0x48000000 + (((u32)((u32)offset + 4) - ((u32)(heap_space + 8))) & 0x3ffffff); + return; +} \ No newline at end of file diff --git a/source/patchcode.h b/source/patchcode.h index d9ead49..f16dc64 100644 --- a/source/patchcode.h +++ b/source/patchcode.h @@ -22,6 +22,9 @@ #ifndef __PATCHCODE_H__ #define __PATCHCODE_H__ +#define STR(X) #X +#define QUOTE(X) STR(X) + // Globals extern u32 hooktype; extern int patched; @@ -30,7 +33,7 @@ extern u32 regionfree; extern bool hookpatched; #define APP_NAME "Cfg USB Loader MOD patched" -#define APP_VERSION "70r78.12" +#define APP_VERSION QUOTE(VERSION) #define PRIVSERV_WIIMMFI "wiimmfi.de" // Function prototypes @@ -41,7 +44,7 @@ void patchdebug(void *addr, u32 len); bool PatchReturnTo(void *Address, int Size, u32 id); void WFCPatch(void *addr, u32 len, const char* domain); u32 do_new_wiimmfi(); -u32 do_new_wiimmfi_nonMKWii(); - +u32 do_new_wiimmfi_nonMKWii(); +void PatchFix480p(); #endif // __PATCHCODE_H__ diff --git a/updates-222.txt b/updates-222.txt index 7b74d01..5e2f877 100644 --- a/updates-222.txt +++ b/updates-222.txt @@ -14,6 +14,19 @@ metaxml= metaxml= metaxml= +release = 70r78.13 +size = 2018688 +date = 2024-09-15 +url = http://cfgusbloader.ntd.homelinux.org/binaries/dol/r12/cfg70r78.13-222.dol +-Internals - changed memory start addres to avoid overlaps +-Graphics - added options for 480p Nintendo Revolution SDK bug fix patch +-Graphics - added options for deflickering settings +-Graphics - added options for disabling dithering +-Graphics - added options for framebuffer width patch +-Languages - Updated KO.lang +-Languages - Updated ZH_CN.lang +-Documentation - Moved to README.md + release = 70r78.12 size = 1908544 date = 2024-09-03 diff --git a/updates.txt b/updates.txt index 319a4ce..18ae236 100644 --- a/updates.txt +++ b/updates.txt @@ -14,6 +14,19 @@ metaxml= metaxml= metaxml= +release = 70r78.13 +size = 2018688 +date = 2024-09-15 +url = http://cfgusbloader.ntd.homelinux.org/binaries/dol/r13/cfg70r78.13.dol +-Internals - changed memory start addres to avoid overlaps +-Graphics - added options for 480p Nintendo Revolution SDK bug fix patch +-Graphics - added options for deflickering settings +-Graphics - added options for disabling dithering +-Graphics - added options for framebuffer width patch +-Languages - Updated KO.lang +-Languages - Updated ZH_CN.lang +-Documentation - Moved to README.md + release = 70r78.12 size = 1908512 date = 2024-09-03