mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-19 09:39:48 +00:00
Save and load to/from pxo files
This commit is contained in:
parent
64809c64d9
commit
9bd2eb7f0f
|
@ -258,6 +258,18 @@ func open_pxo_file(path: String, is_backup := false, replace_empty := true) -> v
|
||||||
new_project.tiles.tile_mask = image
|
new_project.tiles.tile_mask = image
|
||||||
else:
|
else:
|
||||||
new_project.tiles.reset_mask()
|
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()
|
zip_reader.close()
|
||||||
new_project.export_directory_path = path.get_base_dir()
|
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.start_file("image_data/tile_map")
|
||||||
zip_packer.write_file(project.tiles.tile_mask.get_data())
|
zip_packer.write_file(project.tiles.tile_mask.get_data())
|
||||||
zip_packer.close_file()
|
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()
|
zip_packer.close()
|
||||||
|
|
||||||
if temp_path != path:
|
if temp_path != path:
|
||||||
|
|
|
@ -1,7 +1,13 @@
|
||||||
class_name CelTileMap
|
class_name CelTileMap
|
||||||
extends PixelCel
|
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 := PackedInt32Array()
|
||||||
var indices_x: int
|
var indices_x: int
|
||||||
var indices_y: int
|
var indices_y: int
|
||||||
|
@ -10,9 +16,6 @@ var indices_y: int
|
||||||
func _init(_tileset: TileSetCustom, _image: ImageExtended, _opacity := 1.0) -> void:
|
func _init(_tileset: TileSetCustom, _image: ImageExtended, _opacity := 1.0) -> void:
|
||||||
super._init(_image, _opacity)
|
super._init(_image, _opacity)
|
||||||
tileset = _tileset
|
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:
|
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()
|
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:
|
func update_tileset(undo: bool) -> void:
|
||||||
for i in indices.size():
|
for i in indices.size():
|
||||||
var coords := get_tile_coords(i)
|
var coords := get_tile_coords(i)
|
||||||
|
@ -238,5 +224,34 @@ func re_index_all_tiles() -> void:
|
||||||
break
|
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:
|
func get_class_name() -> String:
|
||||||
return "CelTileMap"
|
return "CelTileMap"
|
||||||
|
|
|
@ -12,6 +12,19 @@ func _init(_project: Project, _tileset: TileSetCustom, _name := "") -> void:
|
||||||
|
|
||||||
|
|
||||||
# Overridden Methods:
|
# 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:
|
func get_layer_type() -> int:
|
||||||
return Global.LayerTypes.TILEMAP
|
return Global.LayerTypes.TILEMAP
|
||||||
|
|
||||||
|
@ -23,3 +36,9 @@ func new_empty_cel() -> BaseCel:
|
||||||
project.size.x, project.size.y, false, format, is_indexed
|
project.size.x, project.size.y, false, format, is_indexed
|
||||||
)
|
)
|
||||||
return CelTileMap.new(tileset, image)
|
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)
|
||||||
|
|
|
@ -296,6 +296,9 @@ func serialize() -> Dictionary:
|
||||||
var reference_image_data := []
|
var reference_image_data := []
|
||||||
for reference_image in reference_images:
|
for reference_image in reference_images:
|
||||||
reference_image_data.append(reference_image.serialize())
|
reference_image_data.append(reference_image.serialize())
|
||||||
|
var tileset_data := []
|
||||||
|
for tileset in tilesets:
|
||||||
|
tileset_data.append(tileset.serialize())
|
||||||
|
|
||||||
var metadata := _serialize_metadata(self)
|
var metadata := _serialize_metadata(self)
|
||||||
|
|
||||||
|
@ -316,6 +319,7 @@ func serialize() -> Dictionary:
|
||||||
"frames": frame_data,
|
"frames": frame_data,
|
||||||
"brushes": brush_data,
|
"brushes": brush_data,
|
||||||
"reference_images": reference_image_data,
|
"reference_images": reference_image_data,
|
||||||
|
"tilesets": tileset_data,
|
||||||
"vanishing_points": vanishing_points,
|
"vanishing_points": vanishing_points,
|
||||||
"export_file_name": file_name,
|
"export_file_name": file_name,
|
||||||
"export_file_format": file_format,
|
"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"):
|
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.x = dict.tile_mode_y_basis_x
|
||||||
tiles.y_basis.y = dict.tile_mode_y_basis_y
|
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"):
|
if dict.has("frames") and dict.has("layers"):
|
||||||
for saved_layer in dict.layers:
|
for saved_layer in dict.layers:
|
||||||
match int(saved_layer.get("type", Global.LayerTypes.PIXEL)):
|
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))
|
layers.append(GroupLayer.new(self))
|
||||||
Global.LayerTypes.THREE_D:
|
Global.LayerTypes.THREE_D:
|
||||||
layers.append(Layer3D.new(self))
|
layers.append(Layer3D.new(self))
|
||||||
|
Global.LayerTypes.TILEMAP:
|
||||||
var frame_i := 0
|
layers.append(LayerTileMap.new(self, null))
|
||||||
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
|
|
||||||
|
|
||||||
# Parent references to other layers are created when deserializing
|
# Parent references to other layers are created when deserializing
|
||||||
# a layer, so loop again after creating them:
|
# 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
|
layer_dict["blend_mode"] = blend_mode
|
||||||
layers[layer_i].deserialize(layer_dict)
|
layers[layer_i].deserialize(layer_dict)
|
||||||
_deserialize_metadata(layers[layer_i], dict.layers[layer_i])
|
_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"):
|
if dict.has("tags"):
|
||||||
for tag in dict.tags:
|
for tag in dict.tags:
|
||||||
var new_tag := AnimationTag.new(tag.name, Color(tag.color), tag.from, tag.to)
|
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])
|
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:
|
func _size_changed(value: Vector2i) -> void:
|
||||||
if not is_instance_valid(tiles):
|
if not is_instance_valid(tiles):
|
||||||
size = value
|
size = value
|
||||||
|
|
|
@ -82,3 +82,12 @@ func remove_unused_tiles() -> bool:
|
||||||
remove_tile_at_index(i)
|
remove_tile_at_index(i)
|
||||||
tile_removed = true
|
tile_removed = true
|
||||||
return tile_removed
|
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"))
|
||||||
|
|
Loading…
Reference in a new issue