From 058f436a7daca93057b26619426037dad26a600d Mon Sep 17 00:00:00 2001 From: Luke Hubmayer-Werner Date: Fri, 28 Jul 2023 00:06:46 +0930 Subject: [PATCH] Fixed world map rendering --- README.md | 4 ++-- scripts/loaders/map_loader.gd | 3 ++- scripts/loaders/sprite_loader.gd | 28 ++++++++++++++++------------ shaders/palette_shader.gdshader | 9 ++++----- shaders/worldmap_shader.gdshader | 21 ++++++++------------- test/worldmap_system.gd | 1 + worldmap_palette_mat.tres | 2 +- 7 files changed, 34 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 83a3065..b1add73 100644 --- a/README.md +++ b/README.md @@ -34,9 +34,9 @@ I have mostly solved parsing of SNES menus in a sister project, however there ar - [ ] Vehicle sprites (solved problem, soon™) #### World Maps (Fields?) - [x] Tiles -- [ ] Tilemaps (solved problem, soon™) +- [x] Tilemaps - [ ] Dynamic changes (e.g. meteors, breaking seals, sinking island, pirate cave, voids) (might hardcode these later) -- [ ] Pathing (I have vague recollections about this) +- [ ] Pathing (Data is in place, just needs moving around with collisions) - [ ] Mode 7 Effects (...might hardcode these later) #### Dungeon/Town/Zone Maps (idk what accepted terminology is) - [ ] Tiles (solved problem, soon™) diff --git a/scripts/loaders/map_loader.gd b/scripts/loaders/map_loader.gd index 910d343..59c3eb5 100644 --- a/scripts/loaders/map_loader.gd +++ b/scripts/loaders/map_loader.gd @@ -89,7 +89,7 @@ class WorldMap: data[y_off + x_off + 1] = self.block_tile_ids[tile_offset+1] data[y_off + tile_width + x_off] = self.block_tile_ids[tile_offset+2] data[y_off + tile_width + x_off + 1] = self.block_tile_ids[tile_offset+3] - image.create_from_data(tile_width, tile_height, false, Image.FORMAT_R8, data) + image.create_from_data(tile_width, tile_height, false, SpriteLoader.INDEX_FORMAT, data) return image var worldmaps = [WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new()] @@ -135,6 +135,7 @@ func load_worldmaps(rom: File): rom.seek(chunk_addresses[chunk_id]) var chunk_size := 0 while chunk_size < 256: + # var b: int = (blockmap.size() % 16) + (16 * (chunk_id % 12)); # For debugging the map shader against blocks var b := rom.get_8() if b >= 0xC0: # RLE var count := b-0xBF diff --git a/scripts/loaders/sprite_loader.gd b/scripts/loaders/sprite_loader.gd index 64f0d21..f67f280 100644 --- a/scripts/loaders/sprite_loader.gd +++ b/scripts/loaders/sprite_loader.gd @@ -2,6 +2,10 @@ extends Node var shader_material = load('res://palette_mat.tres') +# Portability for GLES2 vs GLES3 stuff +const INDEX_FORMAT := Image.FORMAT_L8 + + # Offsets # Glyphs @@ -122,13 +126,13 @@ func gba_4bpp_to_tile(data: PoolByteArray) -> Image: tdata[i*2] = data[i] % 16 tdata[i*2+1] = data[i] / 16 var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, tdata) + tile.create_from_data(8, 8, false, INDEX_FORMAT, tdata) return tile func snes_mode7_to_tile(data: PoolByteArray) -> Image: # Easy one, it's just straight data left-to-right, top-to-bottom var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, data) + tile.create_from_data(8, 8, false, INDEX_FORMAT, data) return tile func snes_mode7_compressed_to_tile(data: PoolByteArray, tile_palette: int = 0) -> Image: @@ -148,7 +152,7 @@ func snes_4plane_to_tile(data: PoolByteArray) -> Image: var x = 7 - (i%8) tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) | ((data[j+16] >> x & 1)<<2) | ((data[j+17] >> x & 1)<<3) var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, tdata) + tile.create_from_data(8, 8, false, INDEX_FORMAT, tdata) return tile func snes_3plane_to_tile(data: PoolByteArray) -> Image: @@ -158,7 +162,7 @@ func snes_3plane_to_tile(data: PoolByteArray) -> Image: var x = 7 - (i%8) tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) | ((data[(i/8)+16] >> x & 1)<<2) var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, tdata) + tile.create_from_data(8, 8, false, INDEX_FORMAT, tdata) return tile func snes_2plane_to_tile(data: PoolByteArray) -> Image: @@ -168,7 +172,7 @@ func snes_2plane_to_tile(data: PoolByteArray) -> Image: var x = 7 - (i%8) tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, tdata) + tile.create_from_data(8, 8, false, INDEX_FORMAT, tdata) return tile func snes_1plane_to_tile(data: PoolByteArray) -> Image: @@ -177,7 +181,7 @@ func snes_1plane_to_tile(data: PoolByteArray) -> Image: var x = 7 - (i%8) tdata[i] = (data[i/8] >> x & 1) var tile := Image.new() - tile.create_from_data(8, 8, false, Image.FORMAT_R8, tdata) + tile.create_from_data(8, 8, false, INDEX_FORMAT, tdata) return tile func snes_get_tile(rom: File, offset: int, length: int) -> Image: @@ -198,7 +202,7 @@ func snes_get_tile(rom: File, offset: int, length: int) -> Image: func make_tile_atlas(tile_images) -> Image: var r := Rect2(0, 0, 8, 8) var image = Image.new() - image.create(128, 128, false, Image.FORMAT_R8) + image.create(128, 128, false, INDEX_FORMAT) var tile = 0 for y in tile_images.size()/16: for x in 16: @@ -240,7 +244,7 @@ func snes_load_worldmap(rom: File): var block_tile_ids := PoolByteArray() for block in 0xC0: # 192 blocks per world tileset image = Image.new() - image.create(16, 16, false, Image.FORMAT_R8) + image.create(16, 16, false, INDEX_FORMAT) for tile in 4: rom.seek(block_bank_start + block + (tile * 0xC0)) # Horrible interleaving scheme var src_idx := rom.get_8() @@ -254,7 +258,7 @@ func snes_load_worldmap(rom: File): worldmap_block_tile_ids.append(block_tile_ids) # Make block atlas image = Image.new() - image.create(16*16, 16*12, false, Image.FORMAT_R8) + image.create(16*16, 16*12, false, INDEX_FORMAT) for block in 0xC0: image.blit_rect(block_images[block], Rect2(0, 0, 16, 16), Vector2((block%16)*16, (block/16)*16)) worldmap_block_atlas_imgs.append(image) @@ -262,7 +266,7 @@ func snes_load_worldmap(rom: File): # # DEBUG: Make tile atlas # image = Image.new() - # image.create(16*8, (tile_count/16)*8, false, Image.FORMAT_R8) + # image.create(16*8, (tile_count/16)*8, false, INDEX_FORMAT) # for tile in tile_count: # image.blit_rect(tile_images[tile], Rect2(0, 0, 8, 8), Vector2((tile%16)*8, (tile/16)*8)) # worldmap_tile_atlas_textures.append(texture_from_image(image)) @@ -280,7 +284,7 @@ func load_snes_rom(rom: File): for i in range(0, 32*48, 32): tiles.append(snes_get_tile(rom, offset_Character_Battle_Sprite_Tiles + (strip*32*48) + i, 32)) var strip_image = Image.new() - strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, Image.FORMAT_R8) + strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, INDEX_FORMAT) for i in range(6 * num_Character_Battle_Sprite_Layouts): strip_image.blit_rect(tiles[battle_strip_layouts[i]], Rect2(0, 0, 8, 8), Vector2((i%2) * 8, (i/2) * 8)) strip_images.append(strip_image) @@ -334,7 +338,7 @@ func load_gba_rom(filename: String): for i in range(8, 57*32+8, 32): tiles.append(gba_4bpp_to_tile(tiledata.subarray(i, i+32))) var strip_image = Image.new() - strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, Image.FORMAT_R8) + strip_image.create(16, 24 * num_Character_Battle_Sprite_Layouts, false, INDEX_FORMAT) for i in range(6 * num_Character_Battle_Sprite_Layouts): strip_image.blit_rect(tiles[battle_strip_layouts[i]], Rect2(0, 0, 8, 8), Vector2((i%2) * 8, (i/2) * 8)) strip_images.append(strip_image) diff --git a/shaders/palette_shader.gdshader b/shaders/palette_shader.gdshader index 096abfb..e897c9e 100644 --- a/shaders/palette_shader.gdshader +++ b/shaders/palette_shader.gdshader @@ -10,10 +10,9 @@ void fragment() { if (color_idx == uint(0)) COLOR.a = 0.0;*/ // GLES2 - float color_idx = texture(TEXTURE, UV).a * index_scale; - float row = trunc(color_idx) / 16.0; - float col = fract(color_idx); + float color_idx16 = texture(TEXTURE, UV).r * index_scale; + float row = trunc(color_idx16) / 16.0; + float col = fract(color_idx16); COLOR = texture(palette, vec2(col, row)); - if (color_idx == 0.0) - COLOR.a = 0.0; + COLOR.a = step(0.000001, color_idx16); // Branchless transparency } diff --git a/shaders/worldmap_shader.gdshader b/shaders/worldmap_shader.gdshader index 7e34eaf..8184cd7 100644 --- a/shaders/worldmap_shader.gdshader +++ b/shaders/worldmap_shader.gdshader @@ -15,33 +15,28 @@ vec2 get_tile_atlas_uv(float tile_id, vec2 uv) { float tile_row = trunc(tile_idx16) / 16.0; float tile_col = fract(tile_idx16); vec2 tile_uv = vec2(tile_col, tile_row); // Convert 15.9375 to vec2(0.9375==15/16, (15)/16), this should result in integer coordinates in [0,15] scaled to [0,15/16] for UV - vec2 sub_tile_uv = fract(uv * tilemap_width); + vec2 sub_tile_uv = fract(uv * tilemap_width) / 16.0; // TODO: add sea HScroll, waterfall VScroll tile UV modulation - return tile_uv + (sub_tile_uv/16.0); + return tile_uv + sub_tile_uv; + // return sub_tile_uv + vec2(0.0, 0.5); } void fragment() { // GLES2 - float s = texture(TEXTURE, UV).a; - // float tile_idx = texture(TEXTURE, UV).a * index_scale; // Rescale from [0.0, 1.0] to [0, 255] to [0, 15.9375 (15+15/16)] - // float tile_row = trunc(tile_idx) / 16.0; - // float tile_col = fract(tile_idx); - // vec2 tile_uv = vec2(tile_col, tile_row); // Convert 15.9375 to vec2(0.9375==15/16, (15)/16), this should result in integer coordinates in [0,15] scaled to [0,15/16] for UV - // vec2 sub_tile_uv = vec2(0.5, 0.5); //fract(UV * tilemap_width); + // vec2 uv_tile = trunc(UV * tilemap_width) / tilemap_width; + vec2 uv_tile = UV; + float s = texture(TEXTURE, uv_tile).r; // TODO: move cycling palette to a sampler2DArray or sampler3D rather than rebinding vec2 lut_uv = get_tile_atlas_uv(s, UV); - // vec2 lut_uv = tile_uv; - float color_id = texture(tile_atlas, lut_uv).a; + float color_id = texture(tile_atlas, lut_uv).r; float color_idx16 = color_id * index_scale; float pal_row = trunc(color_idx16) / 16.0; float pal_col = fract(color_idx16); vec2 palette_uv = vec2(pal_col, pal_row); COLOR = texture(palette, palette_uv); - // if (color_idx16 == 0.0) - // COLOR.a = 0.0; - COLOR.a = 1.0; + COLOR.a = step(0.000001, color_idx16); // Branchless transparency } diff --git a/test/worldmap_system.gd b/test/worldmap_system.gd index 8444260..e4bb408 100644 --- a/test/worldmap_system.gd +++ b/test/worldmap_system.gd @@ -54,6 +54,7 @@ func _create_worldmap_texrects() -> void: func _ready() -> void: # Only create this after MapLoader and SpriteLoader have loaded! _create_worldmap_texrects() + # _create_palette_and_atlas_texrects() # Called every frame. 'delta' is the elapsed time since the previous frame. diff --git a/worldmap_palette_mat.tres b/worldmap_palette_mat.tres index 2beb8e9..e472356 100644 --- a/worldmap_palette_mat.tres +++ b/worldmap_palette_mat.tres @@ -4,4 +4,4 @@ [resource] shader = ExtResource( 1 ) -shader_param/tilemap_width = 256.0 +shader_param/tilemap_width = 512.0