Skip to content

Instantly share code, notes, and snippets.

@Erotemic
Created November 28, 2022 16:34
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Erotemic/c77b073d8c73a1cd6e355b5543c16f18 to your computer and use it in GitHub Desktop.
Save Erotemic/c77b073d8c73a1cd6e355b5543c16f18 to your computer and use it in GitHub Desktop.
transfer_assets - POC non-copyrighted SM64 generated randomized assets.
"""
make VERSION=us -j16
build/us_pc/sm64.us
SeeAlso:
https://github.com/TechieAndroid/sm64redrawn
"""
import ubelt as ub
import aifc
import kwimage
import os # NOQA
input_dpath = ub.Path('~/code/sm64-port').expand()
output_dpath = ub.Path('~/code/sm64-port-safe').expand()
manifest_fpath = input_dpath / '.assets-local.txt'
manifest_fpath.copy(output_dpath, overwrite=True)
lines = manifest_fpath.read_text().split('\n')
asset_fpaths = [ub.Path(p) for p in lines[2:-1]]
def redo_image(in_fpath, out_fpath):
import numpy as np
data = kwimage.imread(in_fpath)
shape = data.shape
new_data = handle_text(fname, shape)
if new_data is None:
new_data = data.copy()
rand_data = (np.random.rand(*data.shape) * 255).astype(np.uint8)
new_data[:, :, 0:4] = rand_data[:, :, 0:4]
# new_data[:, :, 0:4] = 0
kwimage.imwrite(out_fpath, new_data)
return shape
def build_char_name_map():
"""
# Font Notes:
textures
ipl3_font_00.ia1.png = A
ipl3_font_25.ia1.png = Z
ipl3_font_26.ia1.png = 0
ipl3_font_35.ia1.png = 9
36-49
!"#'*+,-./;=?@
import kwplot
kwplot.autompl()
kwplot.imshow(img)
# In textures/segment2/
Looks like rotated numbers and letters.
segment2.00000.rgba16.png - Big 0
segment2.00200.rgba16.png - Big 1
segment2.00400.rgba16.png - Big 2
"""
ipl_chars = []
for i in range(26):
ipl_chars.append(chr(ord('A') + i))
for i in range(10):
ipl_chars.append(chr(ord('0') + i))
ipl_chars.extend('!"#\'*+,-./;=?@')
name_to_text_lut = {}
for i, c in enumerate(ipl_chars):
n = 'textures/ipl3_raw/ipl3_font_{:02d}.ia1.png'.format(i)
name_to_text_lut[n] = {
'text': c,
'color': 'white',
}
# Big fancy letters
segment_fmt = 'textures/segment2/segment2.{:03X}00.rgba16.png'
for i in range(10):
n = segment_fmt.format(i * 2)
c = str(i)
name_to_text_lut[n] = {
'text': c,
'color': 'orange',
}
for i in range(26):
n = segment_fmt.format(20 + i * 2)
c = chr(ord('A') + i)
name_to_text_lut[n] = {
'text': c,
'color': 'orange',
}
# Sideways italic letters
'font_graphics.05B80.ia4.png'
'font_graphics.05BC0.ia4.png'
fmt = 'textures/segment2/font_graphics.{:05X}.ia4.png'
offset = 0x05B80
inc = 0x05BC0 - offset
for i in range(26):
n = fmt.format(offset + i * inc)
c = chr(ord('A') + i)
name_to_text_lut[n] = {
'text': c,
'color': 'white',
'rot': 1,
'scale': 0.5
}
# Green letters with black background
fmt = 'textures/segment2/segment2.{:05X}.rgba16.png'
offset = 0x06380
inc = 0x06400 - 0x06380
for i in range(26):
n = fmt.format(offset + i * inc)
c = chr(ord('A') + i)
name_to_text_lut[n] = {
'text': c,
'color': 'green',
'scale': 0.5,
'background': 'black',
}
name_to_text_lut['levels/castle_grounds/5.ia8.png'] = {
# fixme
'text': 'Peach',
'color': 'white',
}
# 'levels/menu/main_menu_seg7_us.0AC40.ia8.png': 0
return name_to_text_lut
name_to_text_lut = build_char_name_map()
def handle_text(fname, shape):
import numpy as np
fname = str(fname)
if fname in name_to_text_lut:
info = name_to_text_lut[fname]
c = info['text']
color = info['color']
rot = info.get('rot', 0)
scale = info.get('scale', 1)
bg = np.zeros(shape, dtype=np.uint8)
h, w = shape[1], shape[0]
if rot:
h, w = w, h
org = (w // 2, h // 2)
img = kwimage.draw_text_on_image(
bg, c, fontScale=0.6 * scale, thickness=1, org=org, halign='center',
valign='center', color=color)
if rot:
img = np.rot90(img, k=3)
img = np.flipud(img)
return img
def redo_audio(in_fpath, out_fpath):
file = aifc.open(open(in_fpath, 'rb'), 'rb')
params = file.getparams()
data = file.readframes(params.nframes)
# Random new sound
new_data = os.urandom(len(data))
# Zero out all sounds
# new_data = b'\x00' * len(data)
new_file = aifc.open(open(out_fpath, 'wb'), 'wb')
new_file.setparams(params)
new_file.writeframes(new_data)
return params
ext_to_fpaths = ub.group_items(asset_fpaths, lambda x: x.suffix)
metadata = ub.ddict(list)
for fname in ext_to_fpaths['.aiff']:
in_fpath = input_dpath / fname
out_fpath = output_dpath / fname
if in_fpath.exists():
out_fpath.parent.ensuredir()
params = redo_audio(in_fpath, out_fpath)
metadata['.aiff'].append({
'fname': fname,
'params': params,
})
for fname in ext_to_fpaths['.png']:
in_fpath = input_dpath / fname
out_fpath = output_dpath / fname
if in_fpath.exists():
out_fpath.parent.ensuredir()
shape = redo_image(in_fpath, out_fpath)
metadata['.png'].append({
'fname': fname,
'shape': shape,
})
for fname in ext_to_fpaths['.m64']:
in_fpath = input_dpath / fname
out_fpath = output_dpath / fname
if in_fpath.exists():
out_fpath.parent.ensuredir()
# Figure out how to zero or randomize this
# in_fpath.copy(out_fpath, overwrite=True)
orig = in_fpath.read_bytes()
new = b'\x00' * len(orig)
out_fpath.write_bytes(new)
metadata['.m64'].append({
'fname': fname,
'num': len(orig)
})
for fname in ext_to_fpaths['.bin']:
in_fpath = input_dpath / fname
out_fpath = output_dpath / fname
if in_fpath.exists():
out_fpath.parent.ensuredir()
# Figure out how to zero or randomize this
# in_fpath.copy(out_fpath, overwrite=True)
orig = in_fpath.read_bytes()
new = b'\x00' * len(orig)
out_fpath.write_bytes(new)
metadata['.bin'].append({
'fname': fname,
'num': len(orig)
})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment