1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-01-19 01:29:49 +00:00

Save and load to/from pxo files

This commit is contained in:
Emmanouil Papadeas 2024-11-25 01:44:37 +02:00
parent 64809c64d9
commit 9bd2eb7f0f
5 changed files with 159 additions and 78 deletions

View file

@ -258,6 +258,18 @@ func open_pxo_file(path: String, is_backup := false, replace_empty := true) -> v
new_project.tiles.tile_mask = image
else:
new_project.tiles.reset_mask()
if result.has("tilesets"):
for i in result.tilesets.size():
var tileset_dict: Dictionary = result.tilesets[i]
var tileset := new_project.tilesets[i]
var tile_size := tileset.tile_size
var tile_amount: int = tileset_dict.tile_amount
for j in tile_amount:
var image_data := zip_reader.read_file("tilesets/%s/%s" % [i, j])
var image := Image.create_from_data(
tile_size.x, tile_size.y, false, new_project.get_image_format(), image_data
)
tileset.add_tile(image, 2)
zip_reader.close()
new_project.export_directory_path = path.get_base_dir()
@ -418,6 +430,14 @@ func save_pxo_file(
zip_packer.start_file("image_data/tile_map")
zip_packer.write_file(project.tiles.tile_mask.get_data())
zip_packer.close_file()
for i in project.tilesets.size():
var tileset := project.tilesets[i]
var tileset_path := "tilesets/%s" % i
for j in tileset.tiles.size():
var tile := tileset.tiles[j]
zip_packer.start_file(tileset_path.path_join(str(j)))
zip_packer.write_file(tile.image.get_data())
zip_packer.close_file()
zip_packer.close()
if temp_path != path:

View file

@ -1,7 +1,13 @@
class_name CelTileMap
extends PixelCel
var tileset: TileSetCustom
var tileset: TileSetCustom:
set(value):
tileset = value
if is_instance_valid(tileset):
indices_x = ceili(float(get_image().get_width()) / tileset.tile_size.x)
indices_y = ceili(float(get_image().get_height()) / tileset.tile_size.y)
indices.resize(indices_x * indices_y)
var indices := PackedInt32Array()
var indices_x: int
var indices_y: int
@ -10,9 +16,6 @@ var indices_y: int
func _init(_tileset: TileSetCustom, _image: ImageExtended, _opacity := 1.0) -> void:
super._init(_image, _opacity)
tileset = _tileset
indices_x = ceili(float(get_image().get_width()) / tileset.tile_size.x)
indices_y = ceili(float(get_image().get_height()) / tileset.tile_size.y)
indices.resize(indices_x * indices_y)
func set_index(tile_position: int, index: int) -> void:
@ -23,23 +26,6 @@ func set_index(tile_position: int, index: int) -> void:
Global.canvas.queue_redraw()
func update_texture() -> void:
if TileSetPanel.tile_editing_mode == TileSetPanel.TileEditingMode.MANUAL:
for i in indices.size():
var index := indices[i]
# Prevent from drawing on empty image portions.
if index == 0 and tileset.tiles.size() > 1:
var coords := get_tile_coords(i)
var current_tile := tileset.tiles[index]
var tile_size := current_tile.image.get_size()
image.blit_rect(current_tile.image, Rect2i(Vector2i.ZERO, tile_size), coords)
super.update_texture()
func on_undo_redo(undo: bool) -> void:
update_tileset(undo)
func update_tileset(undo: bool) -> void:
for i in indices.size():
var coords := get_tile_coords(i)
@ -238,5 +224,34 @@ func re_index_all_tiles() -> void:
break
# Overridden Methods:
func update_texture() -> void:
if TileSetPanel.tile_editing_mode == TileSetPanel.TileEditingMode.MANUAL:
for i in indices.size():
var index := indices[i]
# Prevent from drawing on empty image portions.
if index == 0 and tileset.tiles.size() > 1:
var coords := get_tile_coords(i)
var current_tile := tileset.tiles[index]
var tile_size := current_tile.image.get_size()
image.blit_rect(current_tile.image, Rect2i(Vector2i.ZERO, tile_size), coords)
super.update_texture()
func on_undo_redo(undo: bool) -> void:
update_tileset(undo)
func serialize() -> Dictionary:
var dict := super.serialize()
dict["tile_indices"] = indices
return dict
func deserialize(dict: Dictionary) -> void:
super.deserialize(dict)
indices = dict.get("tile_indices")
func get_class_name() -> String:
return "CelTileMap"

View file

@ -12,6 +12,19 @@ func _init(_project: Project, _tileset: TileSetCustom, _name := "") -> void:
# Overridden Methods:
func serialize() -> Dictionary:
var dict := super.serialize()
dict["tileset_index"] = project.tilesets.find(tileset)
return dict
func deserialize(dict: Dictionary) -> void:
super.deserialize(dict)
new_cels_linked = dict.new_cels_linked
var tileset_index = dict.get("tileset_index")
tileset = project.tilesets[tileset_index]
func get_layer_type() -> int:
return Global.LayerTypes.TILEMAP
@ -23,3 +36,9 @@ func new_empty_cel() -> BaseCel:
project.size.x, project.size.y, false, format, is_indexed
)
return CelTileMap.new(tileset, image)
func new_cel_from_image(image: Image) -> PixelCel:
var image_extended := ImageExtended.new()
image_extended.copy_from_custom(image, project.is_indexed())
return CelTileMap.new(tileset, image_extended)

View file

@ -296,6 +296,9 @@ func serialize() -> Dictionary:
var reference_image_data := []
for reference_image in reference_images:
reference_image_data.append(reference_image.serialize())
var tileset_data := []
for tileset in tilesets:
tileset_data.append(tileset.serialize())
var metadata := _serialize_metadata(self)
@ -316,6 +319,7 @@ func serialize() -> Dictionary:
"frames": frame_data,
"brushes": brush_data,
"reference_images": reference_image_data,
"tilesets": tileset_data,
"vanishing_points": vanishing_points,
"export_file_name": file_name,
"export_file_format": file_format,
@ -345,6 +349,12 @@ func deserialize(dict: Dictionary, zip_reader: ZIPReader = null, file: FileAcces
if dict.has("tile_mode_y_basis_x") and dict.has("tile_mode_y_basis_y"):
tiles.y_basis.x = dict.tile_mode_y_basis_x
tiles.y_basis.y = dict.tile_mode_y_basis_y
if dict.has("tilesets"):
for saved_tileset in dict["tilesets"]:
var tile_size = str_to_var("Vector2i" + saved_tileset.get("tile_size"))
var tileset := TileSetCustom.new(tile_size, self)
tileset.deserialize(saved_tileset)
tilesets.append(tileset)
if dict.has("frames") and dict.has("layers"):
for saved_layer in dict.layers:
match int(saved_layer.get("type", Global.LayerTypes.PIXEL)):
@ -354,63 +364,8 @@ func deserialize(dict: Dictionary, zip_reader: ZIPReader = null, file: FileAcces
layers.append(GroupLayer.new(self))
Global.LayerTypes.THREE_D:
layers.append(Layer3D.new(self))
var frame_i := 0
for frame in dict.frames:
var cels: Array[BaseCel] = []
var cel_i := 0
for cel in frame.cels:
match int(dict.layers[cel_i].get("type", Global.LayerTypes.PIXEL)):
Global.LayerTypes.PIXEL:
var image: Image
var indices_data := PackedByteArray()
if is_instance_valid(zip_reader): # For pxo files saved in 1.0+
var path := "image_data/frames/%s/layer_%s" % [frame_i + 1, cel_i + 1]
var image_data := zip_reader.read_file(path)
image = Image.create_from_data(
size.x, size.y, false, get_image_format(), image_data
)
var indices_path := (
"image_data/frames/%s/indices_layer_%s" % [frame_i + 1, cel_i + 1]
)
if zip_reader.file_exists(indices_path):
indices_data = zip_reader.read_file(indices_path)
elif is_instance_valid(file): # For pxo files saved in 0.x
var buffer := file.get_buffer(size.x * size.y * 4)
image = Image.create_from_data(
size.x, size.y, false, get_image_format(), buffer
)
var pixelorama_image := ImageExtended.new()
pixelorama_image.is_indexed = is_indexed()
if not indices_data.is_empty() and is_indexed():
pixelorama_image.indices_image = Image.create_from_data(
size.x, size.y, false, Image.FORMAT_R8, indices_data
)
pixelorama_image.copy_from(image)
pixelorama_image.select_palette("", true)
cels.append(PixelCel.new(pixelorama_image))
Global.LayerTypes.GROUP:
cels.append(GroupCel.new())
Global.LayerTypes.THREE_D:
if is_instance_valid(file): # For pxo files saved in 0.x
# Don't do anything with it, just read it so that the file can move on
file.get_buffer(size.x * size.y * 4)
cels.append(Cel3D.new(size, true))
cel["pxo_version"] = pxo_version
cels[cel_i].deserialize(cel)
_deserialize_metadata(cels[cel_i], cel)
cel_i += 1
var duration := 1.0
if frame.has("duration"):
duration = frame.duration
elif dict.has("frame_duration"):
duration = dict.frame_duration[frame_i]
var frame_class := Frame.new(cels, duration)
frame_class.user_data = frame.get("user_data", "")
_deserialize_metadata(frame_class, frame)
frames.append(frame_class)
frame_i += 1
Global.LayerTypes.TILEMAP:
layers.append(LayerTileMap.new(self, null))
# Parent references to other layers are created when deserializing
# a layer, so loop again after creating them:
@ -426,6 +381,43 @@ func deserialize(dict: Dictionary, zip_reader: ZIPReader = null, file: FileAcces
layer_dict["blend_mode"] = blend_mode
layers[layer_i].deserialize(layer_dict)
_deserialize_metadata(layers[layer_i], dict.layers[layer_i])
var frame_i := 0
for frame in dict.frames:
var cels: Array[BaseCel] = []
var cel_i := 0
for cel in frame.cels:
var layer := layers[cel_i]
match layer.get_layer_type():
Global.LayerTypes.PIXEL:
var image := _load_image_from_pxo(frame_i, cel_i, zip_reader, file)
cels.append(PixelCel.new(image))
Global.LayerTypes.GROUP:
cels.append(GroupCel.new())
Global.LayerTypes.THREE_D:
if is_instance_valid(file): # For pxo files saved in 0.x
# Don't do anything with it, just read it so that the file can move on
file.get_buffer(size.x * size.y * 4)
cels.append(Cel3D.new(size, true))
Global.LayerTypes.TILEMAP:
var image := _load_image_from_pxo(frame_i, cel_i, zip_reader, file)
var new_cel := (layer as LayerTileMap).new_cel_from_image(image)
cels.append(new_cel)
cel["pxo_version"] = pxo_version
cels[cel_i].deserialize(cel)
_deserialize_metadata(cels[cel_i], cel)
cel_i += 1
var duration := 1.0
if frame.has("duration"):
duration = frame.duration
elif dict.has("frame_duration"):
duration = dict.frame_duration[frame_i]
var frame_class := Frame.new(cels, duration)
frame_class.user_data = frame.get("user_data", "")
_deserialize_metadata(frame_class, frame)
frames.append(frame_class)
frame_i += 1
if dict.has("tags"):
for tag in dict.tags:
var new_tag := AnimationTag.new(tag.name, Color(tag.color), tag.from, tag.to)
@ -484,6 +476,32 @@ func _deserialize_metadata(object: Object, dict: Dictionary) -> void:
object.set_meta(meta, metadata[meta])
func _load_image_from_pxo(
frame_i: int, cel_i: int, zip_reader: ZIPReader, file: FileAccess
) -> ImageExtended:
var image: Image
var indices_data := PackedByteArray()
if is_instance_valid(zip_reader): # For pxo files saved in 1.0+
var path := "image_data/frames/%s/layer_%s" % [frame_i + 1, cel_i + 1]
var image_data := zip_reader.read_file(path)
image = Image.create_from_data(size.x, size.y, false, get_image_format(), image_data)
var indices_path := "image_data/frames/%s/indices_layer_%s" % [frame_i + 1, cel_i + 1]
if zip_reader.file_exists(indices_path):
indices_data = zip_reader.read_file(indices_path)
elif is_instance_valid(file): # For pxo files saved in 0.x
var buffer := file.get_buffer(size.x * size.y * 4)
image = Image.create_from_data(size.x, size.y, false, get_image_format(), buffer)
var pixelorama_image := ImageExtended.new()
pixelorama_image.is_indexed = is_indexed()
if not indices_data.is_empty() and is_indexed():
pixelorama_image.indices_image = Image.create_from_data(
size.x, size.y, false, Image.FORMAT_R8, indices_data
)
pixelorama_image.copy_from(image)
pixelorama_image.select_palette("", true)
return pixelorama_image
func _size_changed(value: Vector2i) -> void:
if not is_instance_valid(tiles):
size = value

View file

@ -82,3 +82,12 @@ func remove_unused_tiles() -> bool:
remove_tile_at_index(i)
tile_removed = true
return tile_removed
func serialize() -> Dictionary:
return {"name": name, "tile_size": tile_size, "tile_amount": tiles.size()}
func deserialize(dict: Dictionary) -> void:
name = dict.get("name", name)
tile_size = str_to_var("Vector2i" + dict.get("tile_size"))