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
|
||||
# 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_pathings = []
|
||||
func load_worldmap_block_properties(rom: File):
|
||||
rom.seek(0x0FEA00)
|
||||
for world_ts in 3:
|
||||
var ts_properties = PoolIntArray()
|
||||
var ts_pathings = PoolIntArray()
|
||||
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_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)
|
||||
if error == OK:
|
||||
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)
|
||||
|
||||
func _ready():
|
||||
|
|
|
@ -33,7 +33,9 @@ const offset_Tiles_Fist := 0x11D710 # 3bpp tile
|
|||
# Arrays to store sprites in
|
||||
var worldmap_palette_imgs = []
|
||||
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_textures = []
|
||||
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)
|
||||
|
||||
|
||||
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):
|
||||
# Load Worldmap Graphics
|
||||
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])
|
||||
tile_images.append(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
|
||||
var block_images = []
|
||||
var block_textures = []
|
||||
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
|
||||
image = Image.new()
|
||||
image.create(16, 16, false, Image.FORMAT_R8)
|
||||
for tile in 4:
|
||||
rom.seek(block_bank_start + block + (tile * 0xC0)) # Horrible interleaving scheme
|
||||
var src_idx := rom.get_8()
|
||||
block_tile_ids.append(src_idx)
|
||||
if src_idx < tile_count:
|
||||
image.blit_rect(tile_images[src_idx], Rect2(0, 0, 8, 8), Vector2((tile%2)*8, (tile/2)*8))
|
||||
block_images.append(image)
|
||||
block_textures.append(texture_from_image(image))
|
||||
worldmap_block_individual_imgs.append(block_images)
|
||||
worldmap_block_individual_textures.append(block_textures)
|
||||
worldmap_block_tile_ids.append(block_tile_ids)
|
||||
# Make block atlas
|
||||
image = Image.new()
|
||||
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))
|
||||
# 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
|
||||
pass
|
||||
MapLoader.update_worldmap_block_tile_ids(worldmap_block_tile_ids)
|
||||
|
||||
|
||||
func load_snes_rom(rom: File):
|
||||
# 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