Fixed world map rendering

This commit is contained in:
Luke Hubmayer-Werner 2023-07-28 00:06:46 +09:30
parent 36dc124edb
commit 058f436a7d
7 changed files with 34 additions and 34 deletions

View File

@ -34,9 +34,9 @@ I have mostly solved parsing of SNES menus in a sister project, however there ar
- [ ] Vehicle sprites (solved problem, soon™) - [ ] Vehicle sprites (solved problem, soon™)
#### World Maps (Fields?) #### World Maps (Fields?)
- [x] Tiles - [x] Tiles
- [ ] Tilemaps (solved problem, soon™) - [x] Tilemaps
- [ ] Dynamic changes (e.g. meteors, breaking seals, sinking island, pirate cave, voids) (might hardcode these later) - [ ] 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) - [ ] Mode 7 Effects (...might hardcode these later)
#### Dungeon/Town/Zone Maps (idk what accepted terminology is) #### Dungeon/Town/Zone Maps (idk what accepted terminology is)
- [ ] Tiles (solved problem, soon™) - [ ] Tiles (solved problem, soon™)

View File

@ -89,7 +89,7 @@ class WorldMap:
data[y_off + x_off + 1] = self.block_tile_ids[tile_offset+1] 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] = self.block_tile_ids[tile_offset+2]
data[y_off + tile_width + x_off + 1] = self.block_tile_ids[tile_offset+3] 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 return image
var worldmaps = [WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new()] 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]) rom.seek(chunk_addresses[chunk_id])
var chunk_size := 0 var chunk_size := 0
while chunk_size < 256: 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() var b := rom.get_8()
if b >= 0xC0: # RLE if b >= 0xC0: # RLE
var count := b-0xBF var count := b-0xBF

View File

@ -2,6 +2,10 @@ extends Node
var shader_material = load('res://palette_mat.tres') var shader_material = load('res://palette_mat.tres')
# Portability for GLES2 vs GLES3 stuff
const INDEX_FORMAT := Image.FORMAT_L8
# Offsets # Offsets
# Glyphs # Glyphs
@ -122,13 +126,13 @@ func gba_4bpp_to_tile(data: PoolByteArray) -> Image:
tdata[i*2] = data[i] % 16 tdata[i*2] = data[i] % 16
tdata[i*2+1] = data[i] / 16 tdata[i*2+1] = data[i] / 16
var tile := Image.new() 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 return tile
func snes_mode7_to_tile(data: PoolByteArray) -> Image: func snes_mode7_to_tile(data: PoolByteArray) -> Image:
# Easy one, it's just straight data left-to-right, top-to-bottom # Easy one, it's just straight data left-to-right, top-to-bottom
var tile := Image.new() 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 return tile
func snes_mode7_compressed_to_tile(data: PoolByteArray, tile_palette: int = 0) -> Image: 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) 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) 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() 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 return tile
func snes_3plane_to_tile(data: PoolByteArray) -> Image: 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) var x = 7 - (i%8)
tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) | ((data[(i/8)+16] >> x & 1)<<2) tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) | ((data[(i/8)+16] >> x & 1)<<2)
var tile := Image.new() 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 return tile
func snes_2plane_to_tile(data: PoolByteArray) -> Image: 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) var x = 7 - (i%8)
tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1) tdata[i] = (data[j] >> x & 1) | ((data[j+1] >> x & 1)<<1)
var tile := Image.new() 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 return tile
func snes_1plane_to_tile(data: PoolByteArray) -> Image: 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) var x = 7 - (i%8)
tdata[i] = (data[i/8] >> x & 1) tdata[i] = (data[i/8] >> x & 1)
var tile := Image.new() 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 return tile
func snes_get_tile(rom: File, offset: int, length: int) -> Image: 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: func make_tile_atlas(tile_images) -> Image:
var r := Rect2(0, 0, 8, 8) var r := Rect2(0, 0, 8, 8)
var image = Image.new() var image = Image.new()
image.create(128, 128, false, Image.FORMAT_R8) image.create(128, 128, false, INDEX_FORMAT)
var tile = 0 var tile = 0
for y in tile_images.size()/16: for y in tile_images.size()/16:
for x in 16: for x in 16:
@ -240,7 +244,7 @@ func snes_load_worldmap(rom: File):
var block_tile_ids := PoolByteArray() var block_tile_ids := PoolByteArray()
for block in 0xC0: # 192 blocks per world tileset for block in 0xC0: # 192 blocks per world tileset
image = Image.new() image = Image.new()
image.create(16, 16, false, Image.FORMAT_R8) image.create(16, 16, false, INDEX_FORMAT)
for tile in 4: for tile in 4:
rom.seek(block_bank_start + block + (tile * 0xC0)) # Horrible interleaving scheme rom.seek(block_bank_start + block + (tile * 0xC0)) # Horrible interleaving scheme
var src_idx := rom.get_8() var src_idx := rom.get_8()
@ -254,7 +258,7 @@ func snes_load_worldmap(rom: File):
worldmap_block_tile_ids.append(block_tile_ids) worldmap_block_tile_ids.append(block_tile_ids)
# Make block atlas # Make block atlas
image = Image.new() 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: for block in 0xC0:
image.blit_rect(block_images[block], Rect2(0, 0, 16, 16), Vector2((block%16)*16, (block/16)*16)) image.blit_rect(block_images[block], Rect2(0, 0, 16, 16), Vector2((block%16)*16, (block/16)*16))
worldmap_block_atlas_imgs.append(image) worldmap_block_atlas_imgs.append(image)
@ -262,7 +266,7 @@ func snes_load_worldmap(rom: File):
# # DEBUG: Make tile atlas # # DEBUG: Make tile atlas
# image = Image.new() # 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: # for tile in tile_count:
# image.blit_rect(tile_images[tile], Rect2(0, 0, 8, 8), Vector2((tile%16)*8, (tile/16)*8)) # 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)) # 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): for i in range(0, 32*48, 32):
tiles.append(snes_get_tile(rom, offset_Character_Battle_Sprite_Tiles + (strip*32*48) + i, 32)) tiles.append(snes_get_tile(rom, offset_Character_Battle_Sprite_Tiles + (strip*32*48) + i, 32))
var strip_image = Image.new() 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): 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_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) strip_images.append(strip_image)
@ -334,7 +338,7 @@ func load_gba_rom(filename: String):
for i in range(8, 57*32+8, 32): for i in range(8, 57*32+8, 32):
tiles.append(gba_4bpp_to_tile(tiledata.subarray(i, i+32))) tiles.append(gba_4bpp_to_tile(tiledata.subarray(i, i+32)))
var strip_image = Image.new() 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): 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_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) strip_images.append(strip_image)

View File

@ -10,10 +10,9 @@ void fragment() {
if (color_idx == uint(0)) if (color_idx == uint(0))
COLOR.a = 0.0;*/ COLOR.a = 0.0;*/
// GLES2 // GLES2
float color_idx = texture(TEXTURE, UV).a * index_scale; float color_idx16 = texture(TEXTURE, UV).r * index_scale;
float row = trunc(color_idx) / 16.0; float row = trunc(color_idx16) / 16.0;
float col = fract(color_idx); float col = fract(color_idx16);
COLOR = texture(palette, vec2(col, row)); COLOR = texture(palette, vec2(col, row));
if (color_idx == 0.0) COLOR.a = step(0.000001, color_idx16); // Branchless transparency
COLOR.a = 0.0;
} }

View File

@ -15,33 +15,28 @@ vec2 get_tile_atlas_uv(float tile_id, vec2 uv) {
float tile_row = trunc(tile_idx16) / 16.0; float tile_row = trunc(tile_idx16) / 16.0;
float tile_col = fract(tile_idx16); 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 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 // 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() { void fragment() {
// GLES2 // GLES2
float s = texture(TEXTURE, UV).a; // vec2 uv_tile = trunc(UV * tilemap_width) / tilemap_width;
// 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)] vec2 uv_tile = UV;
// float tile_row = trunc(tile_idx) / 16.0; float s = texture(TEXTURE, uv_tile).r;
// 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);
// TODO: move cycling palette to a sampler2DArray or sampler3D rather than rebinding // TODO: move cycling palette to a sampler2DArray or sampler3D rather than rebinding
vec2 lut_uv = get_tile_atlas_uv(s, UV); vec2 lut_uv = get_tile_atlas_uv(s, UV);
// vec2 lut_uv = tile_uv; float color_id = texture(tile_atlas, lut_uv).r;
float color_id = texture(tile_atlas, lut_uv).a;
float color_idx16 = color_id * index_scale; float color_idx16 = color_id * index_scale;
float pal_row = trunc(color_idx16) / 16.0; float pal_row = trunc(color_idx16) / 16.0;
float pal_col = fract(color_idx16); float pal_col = fract(color_idx16);
vec2 palette_uv = vec2(pal_col, pal_row); vec2 palette_uv = vec2(pal_col, pal_row);
COLOR = texture(palette, palette_uv); COLOR = texture(palette, palette_uv);
// if (color_idx16 == 0.0) COLOR.a = step(0.000001, color_idx16); // Branchless transparency
// COLOR.a = 0.0;
COLOR.a = 1.0;
} }

View File

@ -54,6 +54,7 @@ func _create_worldmap_texrects() -> void:
func _ready() -> void: func _ready() -> void:
# Only create this after MapLoader and SpriteLoader have loaded! # Only create this after MapLoader and SpriteLoader have loaded!
_create_worldmap_texrects() _create_worldmap_texrects()
# _create_palette_and_atlas_texrects()
# Called every frame. 'delta' is the elapsed time since the previous frame. # Called every frame. 'delta' is the elapsed time since the previous frame.

View File

@ -4,4 +4,4 @@
[resource] [resource]
shader = ExtResource( 1 ) shader = ExtResource( 1 )
shader_param/tilemap_width = 256.0 shader_param/tilemap_width = 512.0