From f19a8c0f50f48391ed017ba529cded56a02027be Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Tue, 25 Jul 2023 16:33:45 +0930 Subject: [PATCH] Rearrange structure --- Node2D.gd | 14 ++-- PC.gd | 2 +- project.godot | 6 +- scripts/loaders/common_gba.gd | 36 +++++++++ scripts/loaders/rom_loader.gd | 16 ++++ scripts/{ => loaders}/sound_loader.gd | 80 +++++++++++++++---- .../sprite_loader.gd} | 56 +++---------- 7 files changed, 136 insertions(+), 74 deletions(-) create mode 100644 scripts/loaders/common_gba.gd create mode 100644 scripts/loaders/rom_loader.gd rename scripts/{ => loaders}/sound_loader.gd (76%) rename scripts/{load_sprites.gd => loaders/sprite_loader.gd} (87%) diff --git a/Node2D.gd b/Node2D.gd index 1d20ce8..1ba9d39 100644 --- a/Node2D.gd +++ b/Node2D.gd @@ -6,28 +6,28 @@ var sfx_buttons = [] func _ready(): Engine.set_target_fps(60) - var strips = len(load_sprites.strip_textures) # * 4 / 5 + var strips = len(SpriteLoader.strip_textures) # * 4 / 5 #var strip_divide = strips * 2 / 5 var strip_divide = strips * 1 / 5 for i in strips: PCs.append(PC.instance()) #PCs[-1].set_position(Vector2((i%strip_divide)*16, (i/strip_divide)*24*11)) PCs[-1].set_position(Vector2((i%strip_divide)*24, (i/strip_divide)*32)) - PCs[-1].material.set_shader_param('palette', load_sprites.character_battle_sprite_palette_textures[i]) - PCs[-1].texture = load_sprites.strip_textures[i] + PCs[-1].material.set_shader_param('palette', SpriteLoader.character_battle_sprite_palette_textures[i]) + PCs[-1].texture = SpriteLoader.strip_textures[i] add_child(PCs[-1]) # PCs.append(PC.instance()) # PCs[-1].set_position(Vector2(0, 2*24*11)) -# PCs[-1].material.set_shader_param('palette', load_sprites.character_battle_sprite_palette_textures[45]) -# PCs[-1].texture = load_sprites.weapon_textures['Fist'] +# PCs[-1].material.set_shader_param('palette', SpriteLoader.character_battle_sprite_palette_textures[45]) +# PCs[-1].texture = SpriteLoader.weapon_textures['Fist'] # add_child(PCs[-1]) for i in SoundLoader.INST_NUM: var btn = Button.new() btn.text = 'Play #%02X' % i btn.align = Button.ALIGN_CENTER - btn.set_position(Vector2((i%8)*40, 200 + (i/8)*16)) + btn.set_position(Vector2((i%8)*36, 200 + (i/8)*12)) btn.set_scale(Vector2(0.5, 0.5)) add_child(btn) btn.connect('pressed', SoundLoader, 'play_sample', [i]) @@ -36,7 +36,7 @@ func _ready(): var btn = Button.new() btn.text = 'SFX #%02X' % i btn.align = Button.ALIGN_CENTER - btn.set_position(Vector2((i%8)*40, 290 + (i/8)*16)) + btn.set_position(Vector2((i%8)*36, 264 + (i/8)*12)) btn.set_scale(Vector2(0.5, 0.5)) add_child(btn) btn.connect('pressed', SoundLoader, 'play_sfx', [i]) diff --git a/PC.gd b/PC.gd index 11e65b4..b1355a7 100644 --- a/PC.gd +++ b/PC.gd @@ -42,7 +42,7 @@ const Animation_Frames = { } func _init(): - material = load_sprites.shader_material.duplicate() + material = SpriteLoader.shader_material.duplicate() # Called every frame. 'delta' is the elapsed time since the previous frame. func _process(_delta): diff --git a/project.godot b/project.godot index bc2519b..a24d9d1 100644 --- a/project.godot +++ b/project.godot @@ -21,8 +21,10 @@ config/icon="res://icon.png" [autoload] globals="*res://globals.gd" -SoundLoader="*res://scripts/sound_loader.gd" -load_sprites="*res://scripts/load_sprites.gd" +CommonGBA="*res://scripts/loaders/common_gba.gd" +SoundLoader="*res://scripts/loaders/sound_loader.gd" +SpriteLoader="*res://scripts/loaders/sprite_loader.gd" +RomLoader="*res://scripts/loaders/rom_loader.gd" [debug] diff --git a/scripts/loaders/common_gba.gd b/scripts/loaders/common_gba.gd new file mode 100644 index 0000000..667d189 --- /dev/null +++ b/scripts/loaders/common_gba.gd @@ -0,0 +1,36 @@ +extends Node + +func ByteArray(size: int) -> PoolByteArray: + var arr := PoolByteArray() + arr.resize(size) + return arr + +func LZ77_decompress(rom: File, address: int) -> PoolByteArray: + rom.seek(address) + var header := rom.get_32() + assert (header & 0x10 == 0x10) + var length := header >> 8 + var output := ByteArray(length) + var ptr := 0 + while ptr < length: + var bitmap := rom.get_8() + for i in range(8): + if (bitmap >> (7-i)) & 1: + # Buffer substitution + var h1 := rom.get_8() + var h2 := rom.get_8() + var copy_len := 3 + (h1 >> 4) + var copy_ptr := ptr - 1 - (((h1 & 0x0F)<<8) + h2) + for j in range(copy_len): + output[ptr] = output[copy_ptr] + copy_ptr += 1 + ptr += 1 + if ptr >= length: + return output + else: + # Literal byte + output[ptr] = rom.get_8() + ptr += 1 + if ptr >= length: + return output + return output diff --git a/scripts/loaders/rom_loader.gd b/scripts/loaders/rom_loader.gd new file mode 100644 index 0000000..46cbbdc --- /dev/null +++ b/scripts/loaders/rom_loader.gd @@ -0,0 +1,16 @@ +extends Node + +var ROM_filename := 'FF5_SCC_WepTweaks_Inus_Dash.sfc' # 'Final Fantasy V (Japan).sfc' +var GBA_filename := '2564 - Final Fantasy V Advance (U)(Independent).gba' + +var rom_snes := File.new() + +func load_snes_rom(filename: String): + var error := rom_snes.open(filename, File.READ) + if error == OK: + SoundLoader.parse_rom(rom_snes) + SpriteLoader.load_snes_rom(rom_snes) + +func _ready(): + load_snes_rom(ROM_filename) + diff --git a/scripts/sound_loader.gd b/scripts/loaders/sound_loader.gd similarity index 76% rename from scripts/sound_loader.gd rename to scripts/loaders/sound_loader.gd index e4bbc43..d04027e 100644 --- a/scripts/sound_loader.gd +++ b/scripts/loaders/sound_loader.gd @@ -1,8 +1,26 @@ extends Node +const BGM_NUM := 70 +const BGM_LOOKUP := 0x043B97 +const INST_NUM := 35 +const INST_BRR_LOOKUP := 0x043C6F +const INST_SR := 0x043CD8 +const INST_LOOP := 0x043D1E +const INST_ADSR := 0x043D64 +const SFX_NUM := 8 +const SFX_BRR_START := 0x041E3F +const SFX_ADSR := 0x041F71 +const SFX_SR := 0x041F83 +var bgm_tracks = [] +var instrument_samples = [] +var sfx_samples = [] + +func read_rom_address(rom: File) -> int: + # Read a 3-byte little-endian address and wrap the bank to ROM space + return rom.get_16() + ((rom.get_8() & 0x3F) << 16) + const MAX_15B = 1 << 15 const MAX_16B = 1 << 16 - func unsigned16_to_signed(unsigned): return (unsigned + MAX_15B) % MAX_16B - MAX_15B @@ -11,7 +29,8 @@ func process_sample(mantissa: int, exponent: int) -> int: # Sign-extend if mantissa >= 8: mantissa |= 0xFFF0 - exponent = min(exponent, 12) + if exponent > 12: + exponent = 12 var unsigned = (mantissa << exponent) & 0xFFFF return unsigned16_to_signed(unsigned) @@ -65,30 +84,18 @@ func make_sample(rom: File, sample_rate: int) -> AudioStreamSample: var audio_data = PoolByteArray() for i in range(2, samples.size()): var b = samples[i] - audio_data.push_back(b & 0xFF) - audio_data.push_back(b >> 8) + audio_data.append(b & 0xFF) + audio_data.append(b >> 8) audio.data = audio_data return audio -const INST_NUM := 35 -const INST_BRR_LOOKUP := 0x043C6F -const INST_SR := 0x043CD8 -const INST_LOOP := 0x043D1E -const INST_ADSR := 0x043D64 -const SFX_NUM := 8 -const SFX_BRR_START := 0x041E3F -const SFX_ADSR := 0x041F71 -const SFX_SR := 0x041F83 -var instrument_samples = [] -var sfx_samples = [] - func get_inst_sample_data(rom: File, id: int) -> AudioStreamSample: rom.seek(INST_SR + (id*2)) var sample_rate := (rom.get_16() * 32000)/4096 var lookup_offset := INST_BRR_LOOKUP + (id*3) rom.seek(lookup_offset) - var brr_offset := rom.get_16() + ((rom.get_8() & 0x3F) << 16) + var brr_offset := read_rom_address(rom) rom.seek(brr_offset) var sample := make_sample(rom, sample_rate) #print_debug('Loaded sample instrument #%02X with lookup offset $%06X, BRR data offset $%06X and length $%04X (%f packets)' % [id, lookup_offset, brr_offset, size, size/9.0]) @@ -112,6 +119,41 @@ func load_samples(rom: File): instrument_samples.append(get_inst_sample_data(rom, i)) load_sfx_samples_data(rom) + + + + +func get_song_data(rom: File, id: int): + var lookup_offset := BGM_LOOKUP + (id*3) + rom.seek(lookup_offset) + var offset := read_rom_address(rom) + var bank := offset & 0xFF0000 + rom.seek(offset) + var _block_size := rom.get_16() # Unused since we pull the individual tracks + var track_ptrs = [] + for i in 10: + var a := bank + rom.get_16() + if a < offset: + a += 0x010000 # Bank shift + track_ptrs.append(a) + + if track_ptrs[0] != track_ptrs[1]: + print('Master is not channel 1, interesting', track_ptrs) + var tracks = [] + for i in range(1, track_ptrs.size()-1): + var length = track_ptrs[i+1] - track_ptrs[i] + tracks.append(rom.get_buffer(length)) + return tracks + +func load_bgms(rom: File): + for i in BGM_NUM: + bgm_tracks.append(get_song_data(rom, i)) + + + + + + var player := AudioStreamPlayer.new() # Make one for each channel, later func play_sample(id: int): print('Playing sample #%02X' % id) @@ -123,6 +165,10 @@ func play_sfx(id: int): player.stream = sfx_samples[id] player.play() +func parse_rom(rom: File): + load_samples(rom) + load_bgms(rom) + func _ready() -> void: add_child(player) diff --git a/scripts/load_sprites.gd b/scripts/loaders/sprite_loader.gd similarity index 87% rename from scripts/load_sprites.gd rename to scripts/loaders/sprite_loader.gd index 4cdeaec..e882b03 100644 --- a/scripts/load_sprites.gd +++ b/scripts/loaders/sprite_loader.gd @@ -2,7 +2,6 @@ extends Node var shader_material = load('res://palette_mat.tres') -var ROM_filename := 'FF5_SCC_WepTweaks_Inus_Dash.sfc' # 'Final Fantasy V (Japan).sfc' const offset_Character_Battle_Sprite_Tiles: int = 0x120000 const offset_Character_Battle_Sprite_Palettes: int = 0x14A3C0 const offset_Character_Battle_Sprite_Layouts: int = 0x14B997 @@ -20,6 +19,11 @@ var character_battle_sprite_palette_disabled_texture: ImageTexture var character_battle_sprite_palette_stone_texture: ImageTexture var weapon_textures = {} +func ByteArray(size: int) -> PoolByteArray: + var arr := PoolByteArray() + arr.resize(size) + return arr + func texture_from_image(image: Image, flags: int = 0) -> ImageTexture: var tex = ImageTexture.new() tex.create_from_image(image, flags) @@ -78,11 +82,6 @@ func generate_palette_rgb5_a1(rom: File, offset: int, length: int = 16) -> Image func generate_palette(rom: File, offset: int, length: int = 16) -> Image: return generate_palette_rgb8(rom, offset, length) -func ByteArray(size: int) -> PoolByteArray: - var arr = PoolByteArray() - arr.resize(size) - return arr - func gba_4bpp_to_tile(data: PoolByteArray) -> Image: var tdata := ByteArray(64) for i in range(32): @@ -146,10 +145,7 @@ func snes_get_tile(rom: File, offset: int, length: int) -> Image: return snes_1plane_to_tile(data) -func load_snes_rom(filename: String): - var rom := File.new() - var _error = rom.open(filename, File.READ) - +func load_snes_rom(rom: File): rom.seek(offset_Character_Battle_Sprite_Layouts) var battle_strip_layouts = rom.get_buffer(num_Character_Battle_Sprite_Layouts * 6) # Character Battle Sprite Tiles @@ -172,39 +168,6 @@ func load_snes_rom(filename: String): weapon_textures['Fist'] = texture_from_image(snes_get_tile(rom, offset_Tiles_Fist, 24)) - SoundLoader.load_samples(rom) - - -func gba_LZ77_decompress(rom: File, address: int) -> PoolByteArray: - rom.seek(address) - var header := rom.get_32() - assert (header & 0x10 == 0x10) - var length := header >> 8 - var output := ByteArray(length) - var ptr := 0 - while ptr < length: - var bitmap := rom.get_8() - for i in range(8): - if (bitmap >> (7-i)) & 1: - # Buffer substitution - var h1 := rom.get_8() - var h2 := rom.get_8() - var copy_len := 3 + (h1 >> 4) - var copy_ptr := ptr - 1 - (((h1 & 0x0F)<<8) + h2) - for j in range(copy_len): - output[ptr] = output[copy_ptr] - copy_ptr += 1 - ptr += 1 - if ptr >= length: - return output - else: - # Literal byte - output[ptr] = rom.get_8() - ptr += 1 - if ptr >= length: - return output - return output - const gba_marker := 'FINAL FANTASY V ADVANCE SYGMAB' const gba_marker_pos_US := 0x12FE10 @@ -238,7 +201,7 @@ func load_gba_rom(filename: String): var tiles = [] rom.seek(offset_marker + gba_offset_battle_sprite_tiles + strip*4) var address = rom.get_32() - 0x08000000 - var tiledata = gba_LZ77_decompress(rom, address) + var tiledata = CommonGBA.LZ77_decompress(rom, address) tiledata.append(0) # Slicing to end of array causes an engine crash. For shame! for i in range(8, 57*32+8, 32): tiles.append(gba_4bpp_to_tile(tiledata.subarray(i, i+32))) @@ -259,6 +222,5 @@ func load_gba_rom(filename: String): var strip_images = [] var strip_textures = [] -func _ready(): - load_snes_rom(ROM_filename) - #load_gba_rom('2564 - Final Fantasy V Advance (U)(Independent).gba') +# func _ready(): + #pass