Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bfn file of Twilight Princess #2

Open
link8023 opened this issue Jan 27, 2023 · 9 comments
Open

Bfn file of Twilight Princess #2

link8023 opened this issue Jan 27, 2023 · 9 comments

Comments

@link8023
Copy link

Can you ask the commands used by bfn's py script

@impiaaa
Copy link
Owner

impiaaa commented Jan 27, 2023

Can you send an example?

@link8023
Copy link
Author

How can I use these scripts?
How can I use bfn.py to extract files?
My English is not very good.

@impiaaa
Copy link
Owner

impiaaa commented Jan 27, 2023

In a command-line terminal, run python3 bfn.py <path-to-bfn-file>. It will print information about the font to the terminal window, and export a PNG file of the character map, next to the BFN file. You will need to have Python 3 and Pillow installed.

@Darth-Koopa
Copy link

Darth-Koopa commented Jan 28, 2023

Can you send an example?

Our goal is to port the Chinese font and text of Twilight Princess Nvidia Shield Version to the GameCube/Wii U version (currently we chose the Japanese version since a fan-translated version is also based on it).
The issue is the NS version is encoded in UTF-16 BE which is multi-byte and the Japanese version is encoded in Shift-JIS which is single-byte.
Here are some examples as references.
BFN.zip

@impiaaa
Copy link
Owner

impiaaa commented Jan 28, 2023

I pushed a small fix to bfn.py due to an array size error, but otherwise all of the examples work fine. I also added some information which might be interesting to you: the field I called fontType in the INF1 chunk determines the type of text encoding. 0 is for single-byte encodings, like ASCII. 1 is for 2-byte encodings, like UTF-16. 2 is for Shift-JIS, which is 2 bytes per character when the first byte is between 0x81 and 0xfc, and 1 byte otherwise. The Japanese and fan-translated examples use type 2, and the Nvidia Shield example uses type 1. Unless they removed the code for type 1, you should just be able to use the Nvidia Shield font as-is, with UTF-16 text.

@Darth-Koopa
Copy link

Darth-Koopa commented Jan 29, 2023

I pushed a small fix to bfn.py due to an array size error, but otherwise all of the examples work fine. I also added some information which might be interesting to you: the field I called fontType in the INF1 chunk determines the type of text encoding. 0 is for single-byte encodings, like ASCII. 1 is for 2-byte encodings, like UTF-16. 2 is for Shift-JIS, which is 2 bytes per character when the first byte is between 0x81 and 0xfc, and 1 byte otherwise. The Japanese and fan-translated examples use type 2, and the Nvidia Shield example uses type 1. Unless they removed the code for type 1, you should just be able to use the Nvidia Shield font as-is, with UTF-16 text.

Copy the Nvidia Shield font and text to the Japanese/English game will result in disorder codes. If anyone can hack the game and make it read UTF-16, it will resolve everything. As far as I know, only the Korean Wii version and the Nvidia Shield version supports UTF-16, but those two versions have their own defects. So hacking the Japanese font file is the only choice left for link8023, unless another hacker is willing for help.

@impiaaa
Copy link
Owner

impiaaa commented Jan 29, 2023

Here's a version of the font from NVIDIA Shield version, modified to use Shift_JIS-2004: nvidia shield shift jis.zip. That means that a number of characters, that don't exist in Shift_JIS-2004, are not included. Here's the code I used to make it:

fin = open("Nvidia Shield.bfn", 'rb')
bfn = BFont()
bfn.read(fin)
fin.close()
newSpans = []
for charCode, glyph in zip(bfn.map1.spans[::2], bfn.map1.spans[1::2]):
    ch = chr(charCode)
    try:
        enc = ch.encode('shift_jis_2004')
    except UnicodeEncodeError:
        continue
    newCode, = struct.unpack('>H', enc)
    newSpans.append((newCode, glyph))

newSpans.sort(key=lambda a: a[0])
newSpans = [n for p in newSpans for n in p]
bfn.map1.spans = array.array('H')
bfn.map1.spans.fromlist(newSpans)
bfn.inf1.fontType = 2
bfn.write(open('nvidia shield shift-jis.bfn', 'wb'))

I think it would be much better to figure out why UTF-16 fonts don't work in the Japanese and English versions, so that you can use all of the available characters. From my reading of the Super Mario Sunshine code, it should work there. The function pointer for JUTResFont::isLeadByte is set in JUTResFont::setBlock to either isLeadByte_1Byte, isLeadByte_2Byte, or isLeadByte_ShiftJIS depending on the field in the INF1 chunk. It's possible that this code to support 2-bytes-per-character fonts was removed from Twilight Princess, but it shouldn't be hard to patch back in. I would also be cautious of encoding errors. I have heard that the NVIDIA Shield releases sometimes byte-swap resources back to little-endian. Also, fontType 1 only works with exactly 2 bytes per character, so it will break with any ASCII text or any characters with code point above U+FFFF.

@Darth-Koopa
Copy link

Can you give me your email for further coorperation?

@impiaaa
Copy link
Owner

impiaaa commented Jan 30, 2023

My contact information is on my website. I can't help you with patching Twilight Princess.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants