WorldMap plumbing
This commit is contained in:
parent
daf4c54cd5
commit
17fd68bbbb
|
@ -45,11 +45,118 @@ extends Node
|
||||||
# Probably going to shader this effect instead of storing hundreds of frames
|
# Probably going to shader this effect instead of storing hundreds of frames
|
||||||
# No palette cycling
|
# No palette cycling
|
||||||
|
|
||||||
|
enum FlagsBlockPathing {
|
||||||
|
PATHABLE_FOOT = 0x001,
|
||||||
|
PATHABLE_CHOCOBO = 0x002,
|
||||||
|
PATHABLE_BLACK_CHOCOBO = 0x004,
|
||||||
|
PATHABLE_HIRYUU = 0x008,
|
||||||
|
PATHABLE_SUBMARINE = 0x010,
|
||||||
|
PATHABLE_SHIP = 0x020,
|
||||||
|
PATHABLE_AIRSHIP = 0x040,
|
||||||
|
SURFACEABLE = 0x080,
|
||||||
|
LANDABLE_CHOCOBO = 0x100,
|
||||||
|
LANDABLE_BLACK_CHOCOBO = 0x200,
|
||||||
|
LANDABLE_HIRYUU = 0x400,
|
||||||
|
LANDABLE_AIRSHIP = 0x800,
|
||||||
|
}
|
||||||
|
|
||||||
|
class WorldMap:
|
||||||
|
const block_width := 256
|
||||||
|
const block_height := 256
|
||||||
|
const tile_width := block_width * 2
|
||||||
|
const tile_height := block_height * 2
|
||||||
|
var blockmap: PoolByteArray
|
||||||
|
var block_tile_ids: PoolByteArray
|
||||||
|
var block_pathing: PoolIntArray
|
||||||
|
|
||||||
|
func get_block_tiles(id: int) -> PoolByteArray:
|
||||||
|
var i = id * 4
|
||||||
|
return self.block_tile_ids.subarray(i, i+4)
|
||||||
|
|
||||||
|
func get_block_pathing_flags(id: int) -> int:
|
||||||
|
return block_pathing[id]
|
||||||
|
|
||||||
|
func make_tile_atlas() -> Image:
|
||||||
|
var image := Image.new()
|
||||||
|
var data := PoolByteArray()
|
||||||
|
data.resize(tile_width*tile_height)
|
||||||
|
var block_tile := 0
|
||||||
|
for y_off in range(0, tile_height*tile_width, tile_width):
|
||||||
|
for x_off in range(0, tile_width, 2):
|
||||||
|
data[y_off + x_off] = self.block_tile_ids[block_tile]
|
||||||
|
block_tile += 1
|
||||||
|
data[y_off + x_off + 1] = self.block_tile_ids[block_tile]
|
||||||
|
block_tile += 1
|
||||||
|
data[y_off + tile_width + x_off] = self.block_tile_ids[block_tile]
|
||||||
|
block_tile += 1
|
||||||
|
data[y_off + tile_width + x_off + 1] = self.block_tile_ids[block_tile]
|
||||||
|
block_tile += 1
|
||||||
|
return image
|
||||||
|
|
||||||
|
var worldmaps = [WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new(), WorldMap.new()]
|
||||||
|
|
||||||
var worldmap_block_properties = []
|
var worldmap_block_properties = []
|
||||||
|
var worldmap_block_pathings = []
|
||||||
func load_worldmap_block_properties(rom: File):
|
func load_worldmap_block_properties(rom: File):
|
||||||
rom.seek(0x0FEA00)
|
rom.seek(0x0FEA00)
|
||||||
for world_ts in 3:
|
for world_ts in 3:
|
||||||
var ts_properties = PoolIntArray()
|
var ts_properties = PoolIntArray()
|
||||||
|
var ts_pathings = PoolIntArray()
|
||||||
for block in 0xC0:
|
for block in 0xC0:
|
||||||
ts_properties.append(rom.get_16() + (rom.get_8() << 16))
|
var properties := rom.get_16() + (rom.get_8() << 16)
|
||||||
|
ts_properties.append(properties)
|
||||||
|
var pathings := properties >> 16 # First 8 pathable flags map directly
|
||||||
|
pathings |= (((properties >> 12) & 0xF) ^ 0xF) << 8 # Next 4 flags (can land) are taken from high bits of second byte and inverted
|
||||||
|
ts_pathings.append(pathings)
|
||||||
worldmap_block_properties.append(ts_properties)
|
worldmap_block_properties.append(ts_properties)
|
||||||
|
worldmap_block_pathings.append(ts_pathings)
|
||||||
|
worldmaps[0].block_pathing = worldmap_block_pathings[0]
|
||||||
|
worldmaps[1].block_pathing = worldmap_block_pathings[1]
|
||||||
|
worldmaps[2].block_pathing = worldmap_block_pathings[0]
|
||||||
|
worldmaps[3].block_pathing = worldmap_block_pathings[2]
|
||||||
|
worldmaps[4].block_pathing = worldmap_block_pathings[2]
|
||||||
|
|
||||||
|
|
||||||
|
func load_worldmaps(rom: File):
|
||||||
|
var chunk_addresses = PoolIntArray()
|
||||||
|
chunk_addresses.resize(0x500) # 5 worldmaps * 256 chunks
|
||||||
|
rom.seek(0x0FE000)
|
||||||
|
for id in range(0, 0x434):
|
||||||
|
chunk_addresses[id] = rom.get_16() + 0x070000
|
||||||
|
for id in range(0x434, 0x500):
|
||||||
|
chunk_addresses[id] = rom.get_16() + 0x080000
|
||||||
|
|
||||||
|
for worldmap_id in 5: # Bartz World, Galuf World, Combined World, Underwater Galuf World, Underwater Combined World
|
||||||
|
# Worldmap chunks have a basic compression.
|
||||||
|
# Repeated blocks along a row are run-length-encoded (RLE)
|
||||||
|
# Certain blocks (mountains) expand to 1x3
|
||||||
|
var blockmap = PoolByteArray()
|
||||||
|
blockmap.resize(WorldMap.block_height * WorldMap.block_width)
|
||||||
|
for chunk_id in range(worldmap_id*0x100, (worldmap_id+1)*0x100):
|
||||||
|
rom.seek(chunk_addresses[chunk_id])
|
||||||
|
while blockmap.size() < 256:
|
||||||
|
var b := rom.get_8()
|
||||||
|
if b >= 0xC0: # RLE
|
||||||
|
var count := b-0xBF
|
||||||
|
var block = rom.get_8()
|
||||||
|
for i in count:
|
||||||
|
blockmap.append(block)
|
||||||
|
else:
|
||||||
|
blockmap.append(b)
|
||||||
|
if b == 0x0C or b == 0x1C or b == 0x2C:
|
||||||
|
# Mountain blocks expand to a 1x3
|
||||||
|
blockmap.append(b+1)
|
||||||
|
blockmap.append(b+2)
|
||||||
|
worldmaps[worldmap_id].blockmap = blockmap
|
||||||
|
|
||||||
|
func update_worldmap_block_tile_ids(worldmap_block_tile_ids: Array):
|
||||||
|
# Called by SpriteLoader
|
||||||
|
worldmaps[0].block_tile_ids = worldmap_block_tile_ids[0]
|
||||||
|
worldmaps[1].block_tile_ids = worldmap_block_tile_ids[1]
|
||||||
|
worldmaps[2].block_tile_ids = worldmap_block_tile_ids[0]
|
||||||
|
worldmaps[3].block_tile_ids = worldmap_block_tile_ids[2]
|
||||||
|
worldmaps[4].block_tile_ids = worldmap_block_tile_ids[2]
|
||||||
|
|
||||||
|
func load_snes_rom(rom: File):
|
||||||
|
load_worldmap_block_properties(rom)
|
||||||
|
load_worldmaps(rom)
|
||||||
|
|
|
@ -10,7 +10,7 @@ func load_snes_rom(filename: String):
|
||||||
var error := rom_snes.open(filename, File.READ)
|
var error := rom_snes.open(filename, File.READ)
|
||||||
if error == OK:
|
if error == OK:
|
||||||
SpriteLoader.load_snes_rom(rom_snes)
|
SpriteLoader.load_snes_rom(rom_snes)
|
||||||
MapLoader.load_worldmap_block_properties(rom_snes)
|
MapLoader.load_snes_rom(rom_snes)
|
||||||
var _thread_error = thread.start(SoundLoader, 'parse_rom', rom_snes)
|
var _thread_error = thread.start(SoundLoader, 'parse_rom', rom_snes)
|
||||||
|
|
||||||
func _ready():
|
func _ready():
|
||||||
|
|
|
@ -33,7 +33,9 @@ const offset_Tiles_Fist := 0x11D710 # 3bpp tile
|
||||||
# Arrays to store sprites in
|
# Arrays to store sprites in
|
||||||
var worldmap_palette_imgs = []
|
var worldmap_palette_imgs = []
|
||||||
var worldmap_palette_textures = []
|
var worldmap_palette_textures = []
|
||||||
var worldmap_tile_imgs = []
|
var worldmap_tile_individual_imgs = []
|
||||||
|
var worldmap_tile_atlas_textures = []
|
||||||
|
var worldmap_block_tile_ids = []
|
||||||
var worldmap_block_individual_imgs = []
|
var worldmap_block_individual_imgs = []
|
||||||
var worldmap_block_individual_textures = []
|
var worldmap_block_individual_textures = []
|
||||||
var worldmap_block_atlas_imgs = []
|
var worldmap_block_atlas_imgs = []
|
||||||
|
@ -193,6 +195,18 @@ func snes_get_tile(rom: File, offset: int, length: int) -> Image:
|
||||||
return snes_1plane_to_tile(data)
|
return snes_1plane_to_tile(data)
|
||||||
|
|
||||||
|
|
||||||
|
func make_tile_atlas(tile_images) -> Image:
|
||||||
|
var r := Rect2(0, 0, 8, 8)
|
||||||
|
var image = Image.new()
|
||||||
|
image.create(256, 256, false, Image.FORMAT_R8)
|
||||||
|
var tile = 0
|
||||||
|
for y in tile_images.size()/16:
|
||||||
|
for x in 16:
|
||||||
|
image.blit_rect(tile_images[tile], r, Vector2(x, y)*8)
|
||||||
|
tile += 1
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
func snes_load_worldmap(rom: File):
|
func snes_load_worldmap(rom: File):
|
||||||
# Load Worldmap Graphics
|
# Load Worldmap Graphics
|
||||||
var worldmap_tile_counts = [256, 256, 128] # Only 128 underwater tiles
|
var worldmap_tile_counts = [256, 256, 128] # Only 128 underwater tiles
|
||||||
|
@ -215,24 +229,29 @@ func snes_load_worldmap(rom: File):
|
||||||
image = snes_mode7_compressed_to_tile(tiledata, tile_palettes[tile])
|
image = snes_mode7_compressed_to_tile(tiledata, tile_palettes[tile])
|
||||||
tile_images.append(image)
|
tile_images.append(image)
|
||||||
# tile_textures.append(texture_from_image(image))
|
# tile_textures.append(texture_from_image(image))
|
||||||
worldmap_tile_imgs.append(tile_images)
|
worldmap_tile_individual_imgs.append(tile_images)
|
||||||
|
worldmap_tile_atlas_textures.append(texture_from_image(make_tile_atlas(tile_images)))
|
||||||
|
|
||||||
|
|
||||||
# Block definitions
|
# Block definitions
|
||||||
var block_images = []
|
var block_images = []
|
||||||
var block_textures = []
|
var block_textures = []
|
||||||
var block_bank_start: int = offset_worldmap_blocks + (world_ts*0x300)
|
var block_bank_start: int = offset_worldmap_blocks + (world_ts*0x300)
|
||||||
|
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, Image.FORMAT_R8)
|
||||||
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()
|
||||||
|
block_tile_ids.append(src_idx)
|
||||||
if src_idx < tile_count:
|
if src_idx < tile_count:
|
||||||
image.blit_rect(tile_images[src_idx], Rect2(0, 0, 8, 8), Vector2((tile%2)*8, (tile/2)*8))
|
image.blit_rect(tile_images[src_idx], Rect2(0, 0, 8, 8), Vector2((tile%2)*8, (tile/2)*8))
|
||||||
block_images.append(image)
|
block_images.append(image)
|
||||||
block_textures.append(texture_from_image(image))
|
block_textures.append(texture_from_image(image))
|
||||||
worldmap_block_individual_imgs.append(block_images)
|
worldmap_block_individual_imgs.append(block_images)
|
||||||
worldmap_block_individual_textures.append(block_textures)
|
worldmap_block_individual_textures.append(block_textures)
|
||||||
|
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, Image.FORMAT_R8)
|
||||||
|
@ -248,8 +267,8 @@ func snes_load_worldmap(rom: File):
|
||||||
# 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))
|
||||||
|
|
||||||
for world_map in 5: # Bartz World, Galuf World, Combined World, Underwater Galuf World, Underwater Combined World
|
MapLoader.update_worldmap_block_tile_ids(worldmap_block_tile_ids)
|
||||||
pass
|
|
||||||
|
|
||||||
func load_snes_rom(rom: File):
|
func load_snes_rom(rom: File):
|
||||||
# Load Battle sprites
|
# Load Battle sprites
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
shader_type canvas_item;
|
||||||
|
uniform sampler2D tiles;
|
||||||
|
uniform sampler2D palette;
|
||||||
|
// uniform float tile_width = 8.0;
|
||||||
|
uniform float tilemap_width = 256.0; // Require square tilemap for now
|
||||||
|
const float index_scale = 255.0 / 16.0;
|
||||||
|
|
||||||
|
|
||||||
|
// This shader maps from tileID texels to Tiles, and then applies palette.
|
||||||
|
// tiles hardcoded to 16x16 tiles for now
|
||||||
|
// palette hardcoded to 16x16 colors for now
|
||||||
|
|
||||||
|
void fragment() {
|
||||||
|
// GLES2
|
||||||
|
float tile_idx = texture(TEXTURE, UV).a * index_scale;
|
||||||
|
vec2 tile_uv = vec2(fract(tile_idx), trunc(tile_idx) / 16.0);
|
||||||
|
vec2 sub_tile_uv = fract(UV / tilemap_width);
|
||||||
|
|
||||||
|
// TODO: add sea HScroll, waterfall VScroll tile UV modulation
|
||||||
|
// TODO: move cycling palette to a sampler2DArray or sampler3D rather than rebinding
|
||||||
|
|
||||||
|
float color_idx = texture(tiles, tile_uv + (sub_tile_uv/16.0)).a * index_scale;
|
||||||
|
float palette_uv = vec2(fract(color_idx), trunc(color_idx) / 16.0);
|
||||||
|
COLOR = texture(palette, palette_uv);
|
||||||
|
|
||||||
|
if (color_idx == 0.0)
|
||||||
|
COLOR.a = 0.0;
|
||||||
|
}
|
Loading…
Reference in New Issue