From c9dcb8a17cf4fef32a26313bd9c2eaaa78656fd4 Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Wed, 16 Aug 2023 22:05:16 +0930 Subject: [PATCH] Add HexStringViewer A test scene for visually scanning for strings within the ROM --- data/SNES_PSX_addresses.tsv | 1 + scripts/loaders/RomLoader.gd | 7 +++-- shaders/hex2font.gdshader | 20 +++++++++++++ test_scene.gd | 14 ++++----- widgets/HexStringViewer.gd | 56 ++++++++++++++++++++++++++++++++++++ widgets/HexStringViewer.tscn | 8 ++++++ 6 files changed, 95 insertions(+), 11 deletions(-) create mode 100644 shaders/hex2font.gdshader create mode 100644 widgets/HexStringViewer.gd create mode 100644 widgets/HexStringViewer.tscn diff --git a/data/SNES_PSX_addresses.tsv b/data/SNES_PSX_addresses.tsv index 30bd1f8..e1d5e52 100644 --- a/data/SNES_PSX_addresses.tsv +++ b/data/SNES_PSX_addresses.tsv @@ -74,3 +74,4 @@ worldmap_tiles.1 0x1BA000 /nar/ff5_bin3.bin 0x039B00 256 of TileSNESMode7c Add t worldmap_tiles.2 0x1BC000 /nar/ff5_bin3.bin 0x039B00 128 of TileSNESMode7c Add the biases font_glyphs_kanji 0x1BD000 426 of SNESTritile length of 0x27F0 ? 0x1BF800 +RPGe_font_character_widths 0x203225 512 of u8 RPGe only, Includes the 1px spacing diff --git a/scripts/loaders/RomLoader.gd b/scripts/loaders/RomLoader.gd index 3a41483..62a656f 100644 --- a/scripts/loaders/RomLoader.gd +++ b/scripts/loaders/RomLoader.gd @@ -17,6 +17,7 @@ var GBA_filename := '2564 - Final Fantasy V Advance (U)(Independent).gba' var rom_snes := File.new() var snes_data := {} +var snes_bytes: PoolByteArray var thread := Thread.new() func load_snes_rom(filename: String): @@ -24,7 +25,9 @@ func load_snes_rom(filename: String): if error == OK: # Copy entire SNES ROM to a buffer for StreamPeerBuffer usage. # Unfortunately, the File API is different and slightly worse than the StreamPeer API. - var bytes := rom_snes.get_buffer(rom_snes.get_len()) + var rom_size := rom_snes.get_len() + var bytes := rom_snes.get_buffer(rom_size) + self.snes_bytes = bytes var buffer = StreamPeerBuffer.new() buffer.data_array = bytes # SpriteLoader.load_snes_rom(rom_snes) @@ -35,7 +38,7 @@ func load_snes_rom(filename: String): # Can concurrently work with the preloaded StreamPeerBuffer though for key in Common.SNES_PSX_addresses: var d = Common.SNES_PSX_addresses[key] - if d.format: + if d.format and (d.SNES < rom_size): # Don't try to grab RPGe bank E0-E7 stuff from a smaller JP ROM var s: STRUCT.StructType if d.format in structdefs: s = structdefs[d.format] diff --git a/shaders/hex2font.gdshader b/shaders/hex2font.gdshader new file mode 100644 index 0000000..5cbb50a --- /dev/null +++ b/shaders/hex2font.gdshader @@ -0,0 +1,20 @@ +shader_type canvas_item; +uniform sampler2D glyph_atlas : hint_normal; +uniform vec2 tilemap_size = vec2(32.0, 20.0); // Update this to match the texture size + +// tile_atlas hardcoded to 64x4 tiles for now + +void fragment() { + // GLES2 + vec2 xy = UV * tilemap_size; // Texel-space coord of our texture + float t = texture(TEXTURE, UV).r; + int tile_idx = int(t * 255.0); // Luminosity channel (any RGB channel works) + // Convert tile_idx to a texel coordinate, then to a UV coordinate + ivec2 tile_xy = ivec2(tile_idx%64, tile_idx/64); + vec2 tile_uv = vec2(tile_xy)/64.0; + // Get sub-tile UV + vec2 sub_tile_uv = fract(xy); + vec2 uv = tile_uv + (sub_tile_uv/64.0); + + COLOR = texture(glyph_atlas, uv); +} diff --git a/test_scene.gd b/test_scene.gd index 7fc82dd..dd00b0d 100644 --- a/test_scene.gd +++ b/test_scene.gd @@ -35,12 +35,6 @@ func _ready(): t.material.set_shader_param('palette', mon.palette) monster_box.add_child(t) - #var battle_bg := OptionButton.new() - #for i in len(SpriteLoader.battle_backgrounds): - # battle_bg.add_item('BG %d' % i) - #battle_bg.connect('item_focused', $BattleScene, 'set_bg') - #battle_bg.connect('item_selected', $BattleScene, 'set_bg') - #add_child(battle_bg) var bbg := SpinBox.new() bbg.max_value = len(SpriteLoader.battle_backgrounds) - 1 bbg.connect('value_changed', $BattleScene, 'set_bg') @@ -49,9 +43,9 @@ func _ready(): bbg.align = LineEdit.ALIGN_RIGHT add_child(bbg) - var fontbox := TextureRect.new() - fontbox.texture = SpriteLoader.font_atlas_texture - add_child(fontbox) +# var fontbox := TextureRect.new() +# fontbox.texture = SpriteLoader.font_atlas_texture +# add_child(fontbox) # var lbl = Label.new() # for i in 22: @@ -61,3 +55,5 @@ func _ready(): # for i in range(128, 161): # lbl.text = lbl.text + '\n%s - %s' % [StringLoader.get_ability_name(i), StringLoader.get_ability_desc(i)] # add_child(lbl) + + diff --git a/widgets/HexStringViewer.gd b/widgets/HexStringViewer.gd new file mode 100644 index 0000000..e304eaf --- /dev/null +++ b/widgets/HexStringViewer.gd @@ -0,0 +1,56 @@ +extends Control +const hex2font_shader := preload('res://shaders/hex2font.gdshader') + +var hexbox: TextureRect +var hexbox_rows: int +var hexbox_cols: int + +func make_hexview(data: PoolByteArray, width: int = 256): + var hex2font_mat := ShaderMaterial.new() + hex2font_mat.shader = hex2font_shader + hex2font_mat.set_shader_param('glyph_atlas', SpriteLoader.font_atlas_texture) + var hex_img := Image.new() + + var l := len(RomLoader.snes_bytes) + self.hexbox_cols = width + self.hexbox_rows = l / self.hexbox_cols + var remainder = l % self.hexbox_cols + if remainder: + self.hexbox_rows += 1 + var padding = PoolByteArray() + padding.resize(self.hexbox_cols - remainder) + padding.fill(0) + data = data + padding + hex2font_mat.set_shader_param('tilemap_size', Vector2(self.hexbox_cols, self.hexbox_rows)) + hex_img.create_from_data(self.hexbox_cols, self.hexbox_rows, false, Image.FORMAT_L8, data) + hexbox = TextureRect.new() + hexbox.texture = SpriteLoader.texture_from_image(hex_img) + hexbox.material = hex2font_mat + hexbox.rect_scale *= 4 + add_child(hexbox) + +func _ready() -> void: + ProjectSettings.set_setting('display/window/size/snap_to_integer', false) + make_hexview(RomLoader.snes_bytes, 480) + +func scroll_hexview(rows: int): + var current_row: int = (-hexbox.rect_position.y)/4 + var next_row = current_row + rows + if next_row > (hexbox_rows - 270): + next_row = hexbox_rows - 270 + if next_row < 0: + next_row = 0 + hexbox.rect_position.y = -next_row * 4 + +func _input(event: InputEvent) -> void: + if event is InputEventMouseButton: + match event.button_index: + BUTTON_WHEEL_DOWN: + scroll_hexview(16) + BUTTON_WHEEL_UP: + scroll_hexview(-16) + elif event is InputEventMouseMotion: + var row: int = (event.position.y - hexbox.rect_position.y) / 4 + var col: int = event.position.x / 4 + var address: int = col + (row * 480) + hexbox.set_tooltip('0x%06X' % address) diff --git a/widgets/HexStringViewer.tscn b/widgets/HexStringViewer.tscn new file mode 100644 index 0000000..5aa16c4 --- /dev/null +++ b/widgets/HexStringViewer.tscn @@ -0,0 +1,8 @@ +[gd_scene load_steps=2 format=2] + +[ext_resource path="res://widgets/HexStringViewer.gd" type="Script" id=1] + +[node name="HexStringViewer" type="Control"] +anchor_right = 1.0 +anchor_bottom = 1.0 +script = ExtResource( 1 )