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 ZH_CN.lang (Thanks kavid)
Documentation - Updated README.md with the new configuration options
This commit is contained in:
unknown 2024-09-15 10:38:50 +02:00
parent c5477d4dae
commit 93014def68
17 changed files with 645 additions and 75 deletions

View File

@ -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) 15-01-2017 cfg 70r78.11 (release)
- GC - updated nintendont config support to version 0x00000006 - GC - updated nintendont config support to version 0x00000006
- GC - if nintendont_config_mode=arg is set nintendont configuration is passed via command line argument - GC - if nintendont_config_mode=arg is set nintendont configuration is passed via command line argument

View File

@ -1,7 +1,7 @@
# Configurable USB Loader ZH-CN By 91wii.com # CFG USB Loader language file template.
# Copyright (C) 2010 91wii.Com THE PACKAGE'S COPYRIGHT HOLDER # Put the translated string in msgstr ""
# This file is distributed under the same license as the PACKAGE package. # Fill in the Last-Translator and Language-Team fields.
# Kavid <kavid@sina.com>, 2010. # Please use utf-8 charset when editing.
# #
#, fuzzy #, fuzzy
msgid "" msgid ""
@ -15,7 +15,18 @@ msgstr ""
"MIME-Version: 2.0\n" "MIME-Version: 2.0\n"
"Content-Type: text/plain; charset=UTF-8\n" "Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\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 #, c-format
msgid "%.1fGB free of %.1fGB" msgid "%.1fGB free of %.1fGB"
@ -74,6 +85,9 @@ msgstr ".dol文件太小"
msgid "1.2+" msgid "1.2+"
msgstr "1.2以上版本" msgstr "1.2以上版本"
msgid "1019 blocks"
msgstr "1019格"
msgid "1st-Person Shooter" msgid "1st-Person Shooter"
msgstr "第一人称射击" msgstr "第一人称射击"
@ -86,6 +100,9 @@ msgstr "2.1以上版本"
msgid "2.2+" msgid "2.2+"
msgstr "2.2以上版本" msgstr "2.2以上版本"
msgid "2043 blocks"
msgstr "2043格"
msgid "3D cover" msgid "3D cover"
msgstr "3D封面" msgstr "3D封面"
@ -216,9 +233,15 @@ msgstr "平衡板游戏"
msgid "Boot Disc" msgid "Boot Disc"
msgstr "启动光盘" msgstr "启动光盘"
msgid "Boot Method:"
msgstr "引导方式:"
msgid "Boot disc" msgid "Boot disc"
msgstr "运行光盘" msgstr "运行光盘"
msgid "Boot method:"
msgstr "引导方式:"
msgid "Booting game, please wait..." msgid "Booting game, please wait..."
msgstr "正在启动游戏,请稍等..." msgstr "正在启动游戏,请稍等..."
@ -367,6 +390,9 @@ msgstr "板球"
msgid "Current Version: %s" msgid "Current Version: %s"
msgstr "当前版本:%s" msgstr "当前版本:%s"
msgid "Custom"
msgstr "自定义"
#, c-format #, c-format
msgid "" msgid ""
"Custom IOS %d could not be found!\n" "Custom IOS %d could not be found!\n"
@ -390,6 +416,9 @@ msgstr "cIOS %s加载成功"
msgid "DEVO" msgid "DEVO"
msgstr "DEVO" msgstr "DEVO"
msgid "DIOS MIOS"
msgstr "DIOS MIOS"
msgid "DISC cover" msgid "DISC cover"
msgstr "光盘封面" msgstr "光盘封面"
@ -411,6 +440,12 @@ msgstr "数据库更新成功。"
msgid "Debug" msgid "Debug"
msgstr "调试" msgstr "调试"
msgid "Default"
msgstr "缺省"
msgid "Default Gamecube Loader:"
msgstr "缺省GameCube启动器"
msgid "Delete Game" msgid "Delete Game"
msgstr "删除游戏" msgstr "删除游戏"
@ -475,6 +510,10 @@ msgstr "下载游戏信息"
msgid "Downloadable Content" msgid "Downloadable Content"
msgstr "支持下载增值内容DLC" msgstr "支持下载增值内容DLC"
#, c-format
msgid "Downloading %s plugin."
msgstr "正在下载 %s 插件。"
msgid "Downloading ALL MISSING covers" msgid "Downloading ALL MISSING covers"
msgstr "正在下载所有缺失的封面" msgstr "正在下载所有缺失的封面"
@ -501,12 +540,6 @@ msgstr "正在下载数据库"
msgid "Downloading devolution." msgid "Downloading devolution."
msgstr "正在下载devolution。" msgstr "正在下载devolution。"
msgid "Downloading mighty plugin."
msgstr "正在下载mighty插件。"
msgid "Downloading neek2o plugin."
msgstr "正在下载neek2o 插件。"
msgid "Downloading titles.txt ..." msgid "Downloading titles.txt ..."
msgstr "正在下载titles.txt文件..." msgstr "正在下载titles.txt文件..."
@ -836,6 +869,9 @@ msgstr "平面封面"
msgid "FULL cover" msgid "FULL cover"
msgstr "完整封面" msgstr "完整封面"
msgid "FWD Emulators"
msgstr "FWD模拟器"
msgid "Fav" msgid "Fav"
msgstr "收藏" msgstr "收藏"
@ -900,9 +936,6 @@ msgstr "飞行模拟"
msgid "Football" msgid "Football"
msgstr "足球" msgstr "足球"
msgid "Force Devolution:"
msgstr "强制Devolution:"
msgid "Force NTSC" msgid "Force NTSC"
msgstr "强制NTSC" msgstr "强制NTSC"
@ -1142,6 +1175,12 @@ msgstr "读取中..."
msgid "Loading..%s\n" msgid "Loading..%s\n"
msgstr "正在读取..%s\n" msgstr "正在读取..%s\n"
msgid "MC size:"
msgstr "MC大小"
msgid "MC size::"
msgstr "MC大小"
msgid "Main" msgid "Main"
msgstr "主菜单" msgstr "主菜单"
@ -1323,9 +1362,19 @@ msgstr "对应Nintendo DS"
msgid "Nintendo DS Connectivity" msgid "Nintendo DS Connectivity"
msgstr "支持与Nintendo DS联动" msgstr "支持与Nintendo DS联动"
msgid "Nintendont"
msgstr "Nintendont"
#, c-format
msgid "Nintendont Ver. %d.%d\n"
msgstr "Nintendont 版本. %d.%d\n"
msgid "No" msgid "No"
msgstr "否" msgstr "否"
msgid "No Speed Limit:"
msgstr "无速度限制:"
#, c-format #, c-format
msgid "No domain part in URL '%s'" msgid "No domain part in URL '%s'"
msgstr "URL'%s'中没有域名部分" msgstr "URL'%s'中没有域名部分"
@ -1345,6 +1394,9 @@ msgstr "未找到更新"
msgid "NoDisc:" msgid "NoDisc:"
msgstr "免光盘:" msgstr "免光盘:"
msgid "NoSSL only"
msgstr "仅用NoSSL"
msgid "None found on disc" msgid "None found on disc"
msgstr "光盘上未找到内容" msgstr "光盘上未找到内容"
@ -1676,6 +1728,9 @@ msgstr "按%s键弹出DVD光盘"
msgid "Priiloader" msgid "Priiloader"
msgstr "Priiloader" msgstr "Priiloader"
msgid "Private server:"
msgstr "私服:"
msgid "Profile:" msgid "Profile:"
msgstr "配置:" msgstr "配置:"
@ -1735,6 +1790,9 @@ msgstr "发售日期"
msgid "Release Notes: (short)" msgid "Release Notes: (short)"
msgstr "发布说明:(简介)" msgstr "发布说明:(简介)"
msgid "Remove Speed Limit:"
msgstr "删除速度限制:"
msgid "Removing game, please wait..." msgid "Removing game, please wait..."
msgstr "正在删除游戏,请稍候..." msgstr "正在删除游戏,请稍候..."
@ -1842,6 +1900,9 @@ msgstr "已选游戏"
msgid "Settings" msgid "Settings"
msgstr "设置" msgstr "设置"
msgid "Shared"
msgstr "已分享"
msgid "Shooter" msgid "Shooter"
msgstr "射击游戏" msgstr "射击游戏"
@ -2317,47 +2378,5 @@ msgstr "无法打开Wii光盘"
msgid "used: %p - %p" msgid "used: %p - %p"
msgstr "已使用: %p - %p" msgstr "已使用: %p - %p"
#~ msgid " Copying files from USB to SD card...(%c)" msgid "wiimmfi.de"
#~ msgstr "正在把文件从USB设备中复制到SD卡中...(%c)" msgstr "wiimmfi.de"
#~ 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金手指"

View File

@ -8,7 +8,7 @@ msgid ""
msgstr "" msgstr ""
"Project-Id-Version: PACKAGE VERSION\n" "Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \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" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n" "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n" "Language-Team: LANGUAGE <LL@li.org>\n"
@ -442,6 +442,12 @@ msgstr ""
msgid "Default Gamecube Loader:" msgid "Default Gamecube Loader:"
msgstr "" msgstr ""
msgid "Defaults"
msgstr ""
msgid "Deflicker Filter:"
msgstr ""
msgid "Delete Game" msgid "Delete Game"
msgstr "" msgstr ""
@ -466,6 +472,9 @@ msgstr ""
msgid "Devolution only accepts clean dumps!\n" msgid "Devolution only accepts clean dumps!\n"
msgstr "" msgstr ""
msgid "Disable Dithering:"
msgstr ""
msgid "Disc" msgid "Disc"
msgstr "" msgstr ""
@ -917,6 +926,9 @@ msgstr ""
msgid "Fitness" msgid "Fitness"
msgstr "" msgstr ""
msgid "Fix 480p:"
msgstr ""
msgid "Fixing EXTEND partition..." msgid "Fixing EXTEND partition..."
msgstr "" msgstr ""
@ -951,6 +963,9 @@ msgstr ""
msgid "Found %s" msgid "Found %s"
msgstr "" msgstr ""
msgid "Framebuffer width:"
msgstr ""
msgid "French" msgid "French"
msgstr "" msgstr ""
@ -1382,12 +1397,27 @@ msgstr ""
msgid "Nunchuk" msgid "Nunchuk"
msgstr "" msgstr ""
msgid "OFF (Extended)"
msgstr ""
msgid "OFF (Safe)"
msgstr ""
msgid "OK" msgid "OK"
msgstr "" msgstr ""
msgid "OK!" msgid "OK!"
msgstr "" msgstr ""
msgid "ON (High)"
msgstr ""
msgid "ON (Low)"
msgstr ""
msgid "ON (Medium)"
msgstr ""
msgid "Ocarina (cheats):" msgid "Ocarina (cheats):"
msgstr "" msgstr ""

View File

@ -15,7 +15,7 @@ include $(DEVKITPPC)/wii_rules
# SOURCES is a list of directories containing source code # SOURCES is a list of directories containing source code
# INCLUDES is a list of directories containing extra header files # INCLUDES is a list of directories containing extra header files
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
VERSION := 70r78.12 VERSION := 70r78.13
RELEASE := release RELEASE := release
# to override RELEASE use: make announce RELEASE=beta # to override RELEASE use: make announce RELEASE=beta
ifeq ($(findstring compat,$(VERSION)),compat) ifeq ($(findstring compat,$(VERSION)),compat)
@ -63,8 +63,16 @@ BUILD_DEBUG := 0
ifeq ($(BUILD_DEBUG),1) ifeq ($(BUILD_DEBUG),1)
BUILD := build_dbg BUILD := build_dbg
TARGET := $(BINBASE)-dbg TARGET := $(BINBASE)-dbg
BUILD_DBG_FLAG := -DBUILD_DBG=3 BUILD_DBG_FLAG := -DBUILD_DBG=3 -DDEBUG_PATCH=1
endif 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 #"-g" tells the compiler to include support for the debugger
#"-Wall" tells it to warn us about all suspicious-looking code #"-Wall" tells it to warn us about all suspicious-looking code
DEBUG_OPT = -Os DEBUG_OPT = -Os
@ -79,7 +87,8 @@ CXXFLAGS = $(CFLAGS)
# cfg 33-36: 0x80c00000 # cfg 33-36: 0x80c00000
# cfg 37-49: 0x80b00000 # cfg 37-49: 0x80b00000
# cfg 50-..: 0x80a80000 # cfg 50-..: 0x80a80000
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map,--section-start,.init=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 # any extra libraries we wish to link with the project
@ -168,6 +177,9 @@ $(BUILD):
debug: debug:
@$(MAKE) --no-print-directory BUILD_DEBUG=1 @$(MAKE) --no-print-directory BUILD_DEBUG=1
debug_patch:
@$(MAKE) --no-print-directory BUILD_DEBUG_PATCH=1
#--------------------------------------------------------------------------------- #---------------------------------------------------------------------------------
lang: lang:
@[ -d Languages ] || mkdir -p Languages @[ -d Languages ] || mkdir -p Languages
@ -188,6 +200,7 @@ clean:
@rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol @rm -fr $(BUILD) $(OUTPUT).elf $(OUTPUT).dol
@rm -fr $(BUILD)_222 $(OUTPUT)-222.elf $(OUTPUT)-222.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 $(OUTPUT)-dbg.elf $(OUTPUT)-dbg.dol
@rm -fr $(BUILD)_dbg_patch $(OUTPUT)-dbg-patch.elf $(OUTPUT)-dbg-patch.dol
cleanall: clean cleanall: clean
@rm -fr *.dol *.elf @rm -fr *.dol *.elf

View File

@ -1100,6 +1100,24 @@ Example:
# 2 = wiimmfi.de # 2 = wiimmfi.de
# 3 = Custom string from "custom_private_server" # 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: # Profile Options:
# ================ # ================
# #

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 120 KiB

View File

@ -17,6 +17,7 @@
#include "gettext.h" #include "gettext.h"
#include "menu.h" #include "menu.h"
#include "dolmenu.h" #include "dolmenu.h"
#include "deflicker.h"
/* Apploader function pointers */ /* Apploader function pointers */
typedef int (*app_main)(void **dst, int *size, int *offset); typedef int (*app_main)(void **dst, int *size, int *offset);
@ -291,8 +292,7 @@ s32 Apploader_Run(entry_point *entry)
TIME.size += appldr_len; TIME.size += appldr_len;
// used mem range by the loader // used mem range by the loader
//void *mem_start = (void*)0x80b00000; // as set in Makefile void *mem_start = (void*)0x80a50000; // as set in Makefile
void *mem_start = (void*)0x80a80000; // as set in Makefile
void *mem_end = memalign(32,32); void *mem_end = memalign(32,32);
//printf("malloc = %p sta = %p\n", mem, &ret); //printf("malloc = %p sta = %p\n", mem, &ret);
@ -753,6 +753,54 @@ void maindolpatches(void *dst, int len)
if (!CFG.disable_pop_patch) { if (!CFG.disable_pop_patch) {
PrinceOfPersiaPatch(); 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 // Nintendo Wi-Fi Connection (WFC) patch
if (CFG.game.private_server) { if (CFG.game.private_server) {
NoSSLPatch(dst, len); NoSSLPatch(dst, len);

View File

@ -484,6 +484,17 @@ struct TextMap map_private_server[] =
{ NULL, -1 } { 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 { struct playStat {
char id[7]; char id[7];
s32 playCount; s32 playCount;
@ -1423,6 +1434,10 @@ void CFG_Default()
CFG.game.alt_controller_cfg = 0; CFG.game.alt_controller_cfg = 0;
CFG.game.rem_speed_limit = 0; CFG.game.rem_speed_limit = 0;
CFG.game.private_server = 0; //off 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); cfg_ios_set_idx(DEFAULT_IOS_IDX);
// all other game settings are 0 (memset(0) above) // all other game settings are 0 (memset(0) above)
STRCOPY(CFG.sort_ignore, "A,An,The"); 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_map_auto("hooktype", map_hook, &game_cfg->hooktype);
cfg_int_max("write_playlog", &game_cfg->write_playlog, 3); cfg_int_max("write_playlog", &game_cfg->write_playlog, 3);
cfg_int_max("private_server", &game_cfg->private_server, 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(alt_controller_cfg);
SAVE_BOOL(rem_speed_limit); SAVE_BOOL(rem_speed_limit);
SAVE_NUM(private_server); 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) { if (game_cfg->clean == CFG_CLEAN_OFF) {
SAVE_STR("clear_patches", "0"); SAVE_STR("clear_patches", "0");
} else if (game_cfg->clean == CFG_CLEAN_ON) { } else if (game_cfg->clean == CFG_CLEAN_ON) {

View File

@ -269,6 +269,10 @@ struct Game_CFG
int alt_controller_cfg; int alt_controller_cfg;
int rem_speed_limit; int rem_speed_limit;
int private_server; int private_server;
int deflicker;
int fix_480p;
int dithering;
int fix_fb;
}; };
struct Game_CFG_2 struct Game_CFG_2
@ -750,6 +754,7 @@ extern struct TextMap map_channel_boot[];
extern struct TextMap map_gc_boot[]; extern struct TextMap map_gc_boot[];
extern struct TextMap map_mem_card_size[]; extern struct TextMap map_mem_card_size[];
extern struct TextMap map_private_server[]; extern struct TextMap map_private_server[];
extern struct TextMap map_deflicker[];
extern char *names_vpatch[CFG_VIDEO_PATCH_NUM]; extern char *names_vpatch[CFG_VIDEO_PATCH_NUM];
extern u8 cIOS_base[]; extern u8 cIOS_base[];

184
source/deflicker.c Normal file
View File

@ -0,0 +1,184 @@
/*
* Deflicker filter patching by wiidev (blackb0x @ GBAtemp)
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <gccore.h>
#include <sys/unistd.h>
#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;
}
}

24
source/deflicker.h Normal file
View File

@ -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);

View File

@ -478,6 +478,10 @@ struct W_GameCfg
Widget *alt_controller_cfg; Widget *alt_controller_cfg;
Widget *rem_speed_limit; Widget *rem_speed_limit;
Widget *private_server; Widget *private_server;
Widget *deflicker;
Widget *fix_480p;
Widget *dithering;
Widget *fix_fb;
} wgame; } wgame;
@ -1160,6 +1164,10 @@ void InitGameOptionsPage(Widget *pp, int bh)
char *names_private_server[num_private_server]; char *names_private_server[num_private_server];
num_private_server = map_to_list(map_private_server, num_private_server, names_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); ww = wgui_add_game_opt(op, gt("Language:"), CFG_LANG_NUM, languages);
BIND_OPT(language); BIND_OPT(language);
@ -1219,6 +1227,18 @@ void InitGameOptionsPage(Widget *pp, int bh)
ww = wgui_add_game_opt(op, gt("Private server:"), num_private_server, names_private_server); ww = wgui_add_game_opt(op, gt("Private server:"), num_private_server, names_private_server);
BIND_OPT(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_move_to(pp, PAD0, -bh);
pos_pad(pp, PAD0); pos_pad(pp, PAD0);
pos_columns(pp, 4, SIZE_FULL); pos_columns(pp, 4, SIZE_FULL);

View File

@ -212,6 +212,16 @@ char *str_private_server[4] =
gts("Custom") 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_Global_Options();
int Menu_Game_Options(); int Menu_Game_Options();
void Switch_Favorites(bool enable); void Switch_Favorites(bool enable);
@ -1836,7 +1846,7 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) {
int opt_saved; int opt_saved;
//int opt_ios_reload; //int opt_ios_reload;
int opt_language, opt_video, opt_video_patch, opt_vidtv, opt_padhook, opt_nand_emu; 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; f32 size = 0.0;
int redraw_cover = 0; int redraw_cover = 0;
int i; int i;
@ -1882,7 +1892,7 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) {
game_cfg = &game_cfg2->curr; game_cfg = &game_cfg2->curr;
struct Menu menu; struct Menu menu;
int NUM_OPT = 20; int NUM_OPT = 24;
if (header->magic == GC_GAME_ON_DRIVE) NUM_OPT = 18; if (header->magic == GC_GAME_ON_DRIVE) NUM_OPT = 18;
if (header->magic == CHANNEL_MAGIC) NUM_OPT = 19; if (header->magic == CHANNEL_MAGIC) NUM_OPT = 19;
char active[NUM_OPT]; 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_ntsc_j_patch = game_cfg->ntsc_j_patch;
opt_nand_emu = game_cfg->nand_emu; opt_nand_emu = game_cfg->nand_emu;
opt_private_server = game_cfg->private_server; 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) { if (game_cfg->clean == CFG_CLEAN_ALL) {
opt_language = CFG_LANG_CONSOLE; opt_language = CFG_LANG_CONSOLE;
@ -1943,6 +1957,10 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) {
opt_nodisc = 0; opt_nodisc = 0;
opt_screenshot = 0; opt_screenshot = 0;
opt_private_server = 0; opt_private_server = 0;
opt_deflicker = 0;
opt_fix_480p = 0;
opt_dithering = 0;
opt_fix_fb = 0;
active[1] = 0; // language active[1] = 0; // language
active[2] = 0; // video active[2] = 0; // video
active[3] = 0; // video_patch 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")); PRINT_OPT_A(gt("Savegame:"), gt("Dump savegame"));
if (menu_window_mark(&menu)) if (menu_window_mark(&menu))
PRINT_OPT_A(gt("Private server:"), gt(str_private_server[opt_private_server])); 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(); DefaultColor();
@ -2445,6 +2471,18 @@ int Menu_Boot_Options(struct discHdr *header, bool disc) {
case 19: case 19:
CHANGE(game_cfg->private_server, 3); CHANGE(game_cfg->private_server, 3);
break; 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) { if (buttons & CFG.button_confirm.mask) {

View File

@ -12,7 +12,12 @@
//#include "fwrite_patch.h" //#include "fwrite_patch.h"
//#include "fwrite_patch_slota.h" //#include "fwrite_patch_slota.h"
//#include "main.h" //#include "main.h"
#ifdef DEBUG_PATCH
#define debug_printf(fmt, args...) \
printf(fmt, ##args)
#else
#define debug_printf(fmt, args...) #define debug_printf(fmt, args...)
#endif
bool hookpatched = false; 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. // returns 0 when all patching is done and game is ready to be booted.
return 0; 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;
}

View File

@ -22,6 +22,9 @@
#ifndef __PATCHCODE_H__ #ifndef __PATCHCODE_H__
#define __PATCHCODE_H__ #define __PATCHCODE_H__
#define STR(X) #X
#define QUOTE(X) STR(X)
// Globals // Globals
extern u32 hooktype; extern u32 hooktype;
extern int patched; extern int patched;
@ -30,7 +33,7 @@ extern u32 regionfree;
extern bool hookpatched; extern bool hookpatched;
#define APP_NAME "Cfg USB Loader MOD patched" #define APP_NAME "Cfg USB Loader MOD patched"
#define APP_VERSION "70r78.12" #define APP_VERSION QUOTE(VERSION)
#define PRIVSERV_WIIMMFI "wiimmfi.de" #define PRIVSERV_WIIMMFI "wiimmfi.de"
// Function prototypes // Function prototypes
@ -42,6 +45,6 @@ bool PatchReturnTo(void *Address, int Size, u32 id);
void WFCPatch(void *addr, u32 len, const char* domain); void WFCPatch(void *addr, u32 len, const char* domain);
u32 do_new_wiimmfi(); u32 do_new_wiimmfi();
u32 do_new_wiimmfi_nonMKWii(); u32 do_new_wiimmfi_nonMKWii();
void PatchFix480p();
#endif // __PATCHCODE_H__ #endif // __PATCHCODE_H__

View File

@ -14,6 +14,19 @@ metaxml=</long_description>
metaxml=<ahb_access/> metaxml=<ahb_access/>
metaxml=</app> metaxml=</app>
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 release = 70r78.12
size = 1908544 size = 1908544
date = 2024-09-03 date = 2024-09-03

View File

@ -14,6 +14,19 @@ metaxml=</long_description>
metaxml=<ahb_access/> metaxml=<ahb_access/>
metaxml=</app> metaxml=</app>
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 release = 70r78.12
size = 1908512 size = 1908512
date = 2024-09-03 date = 2024-09-03