1
0
Fork 0
mirror of https://github.com/Orama-Interactive/Pixelorama.git synced 2025-02-15 10:13:07 +00:00

Compare commits

...

26 commits

Author SHA1 Message Date
Variable
d9fafcfd5a
Merge e078a6c1e6 into 6459151549 2024-11-24 18:20:21 +01:00
Vovkiv
6459151549
[skip ci] [linux] Enhancements for desktop file. (#1140)
Co-authored-by: volkov <volkovissocool@gmail.com>
2024-11-24 14:38:55 +02:00
Variable
fe6efb0f1d
fixed recorder label not updating when project is changed (#1139) 2024-11-24 14:37:02 +02:00
Emmanouil Papadeas
8b1367494d Ensure that the swatches get deleted when the user removes all palettes 2024-11-23 17:54:28 +02:00
Emmanouil Papadeas
01b55aca07 Fix crash when using indexed mode without a palette 2024-11-23 14:17:41 +02:00
Emmanouil Papadeas
5f53a3eb7b Fix crash when Pixelorama starts without a palette 2024-11-23 14:17:27 +02:00
Emmanouil Papadeas
658477ed4b Sort system font names by alphabetical order 2024-11-23 01:21:22 +02:00
Emmanouil Papadeas
3fb8484ac5 Use Control + mouse wheel to increase the size of the text tool 2024-11-23 01:00:49 +02:00
Emmanouil Papadeas
0484b1012f Fix Delete button and fill selection mode of the bucket tool not working with indexed mode 2024-11-23 00:58:34 +02:00
Emmanouil Papadeas
b87a8e2ab8 Fix cel copying not working with indexed mode 2024-11-22 21:00:38 +02:00
Emmanouil Papadeas
e6c4a72158 Fix crash when using indexed mode and the palette has empty swatches between colors 2024-11-22 20:47:38 +02:00
Emmanouil Papadeas
1dcb696c35 Use texelFetch instead of texture for indexed mode shaders
Fixes various weird issues when palettes have empty slots, and removes unnecessary calculations.
2024-11-22 20:47:05 +02:00
Emmanouil Papadeas
d580523c6e Revert "Slightly optimize IndexedToRGB.gdshader"
This reverts commit 7cf87ac142.
2024-11-22 18:29:27 +02:00
Emmanouil Papadeas
11da07b9ac Hide the color mode submenu when selecting an item 2024-11-22 18:02:36 +02:00
Emmanouil Papadeas
7cf87ac142 Slightly optimize IndexedToRGB.gdshader
Multiply the index by 255.0 only once, instead of dividing and multiplying it again
2024-11-22 18:01:29 +02:00
Emmanouil Papadeas
bd7d3b19cc Add a crop_image boolean parameter to Palette.convert_to_image()
Fixes some issues with the Palettize effect where the output would be different if the palette size changed and empty swatches were added, even if the colors themselves stayed the same.
2024-11-22 17:56:39 +02:00
Emmanouil Papadeas
996a234d0d Call Palettes.current_palette_set_color() immediately when changing the color of a swatch 2024-11-22 15:26:30 +02:00
Emmanouil Papadeas
77f6bcf07b Fix Palette.convert_to_image() storing wrong colors in the image
Similar fix to #1108.
2024-11-22 15:07:16 +02:00
Emmanouil Papadeas
fede2d8e6f Fix undo/redo not working if the cursor is over the timeline 2024-11-22 02:56:57 +02:00
Emmanouil Papadeas
d0ecf3b03d Center diagonal symmetry guides when initializing a new project
The guides appear centered, but the symmetry itself is not working properly yet
2024-11-21 16:33:19 +02:00
Emmanouil Papadeas
3d65e48c92 Add backend for diagonal mirror buttons
The buttons are not yet visible
2024-11-21 12:48:52 +02:00
Variable
e078a6c1e6
Merge branch 'Orama-Interactive:master' into Achievements 2024-11-18 17:00:24 +05:00
Variable
d78414f098 Merge branch 'Achievements' of github.com:Variable-ind/Pixelorama into Achievements 2024-08-14 21:00:34 +05:00
Variable
566944cfce Typo 2024-08-14 20:59:00 +05:00
Variable
a3ab62d53a
Merge branch 'Orama-Interactive:master' into Achievements 2024-08-14 20:52:30 +05:00
Variable
6e62361b24 Add more achievements 2024-08-14 20:50:31 +05:00
39 changed files with 437 additions and 102 deletions

View file

@ -3,16 +3,23 @@ Name=Pixelorama
GenericName=2D sprite editor GenericName=2D sprite editor
GenericName[el]=Επεξεργαστής δισδιάστατων εικόνων GenericName[el]=Επεξεργαστής δισδιάστατων εικόνων
GenericName[fr]=Éditeur de sprites 2D GenericName[fr]=Éditeur de sprites 2D
GenericName[ru]=2Д редактор спрайтов
GenericName[pt_BR]=Editor de sprites 2D GenericName[pt_BR]=Editor de sprites 2D
GenericName[uk]=2Д редактор спрайтів
GenericName[zh_CN]=2D GenericName[zh_CN]=2D
Comment=Create and edit static or animated 2D sprites Comment=Create and edit static or animated 2D sprites
Comment[el]=Δημιουργήστε και επεξεργαστείτε στατικές ή κινούμενες δισδιάστατες εικόνες Comment[el]=Δημιουργήστε και επεξεργαστείτε στατικές ή κινούμενες δισδιάστατες εικόνες
Comment[fr]=Créez et modifiez des sprites 2D statiques ou animées Comment[fr]=Créez et modifiez des sprites 2D statiques ou animées
Comment[ru]=Создавайте и редактируйте статичные и анимированные 2Д спрайты
Comment[pt_BR]=Crie e edite sprites 2D estáticos ou animados Comment[pt_BR]=Crie e edite sprites 2D estáticos ou animados
Comment[uk]=Створюйте та редагуйте статичні та анімовані 2Д спрайти
Comment[zh_CN]= 2D Comment[zh_CN]= 2D
Exec=pixelorama Exec=pixelorama
Icon=pixelorama Icon=pixelorama
Terminal=false Terminal=false
Type=Application Type=Application
Categories=Graphics;2DGraphics;RasterGraphics; Categories=Graphics;2DGraphics;RasterGraphics;
Keywords=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;
Keywords[ru]=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;пиксель;ретро;анимация;арт;изображение;2д;спрайт;графика;рисование;редактор;
Keywords[uk]=pixel;retro;animation;art;image;2d;sprite;graphics;drawing;editor;піксель;ретро;анімація;арт;зображення;2д;спрайт;графіка;малювання;редактор;
MimeType=image/pxo;image/png;image/bmp;image/vnd.radiance;image/jpeg;image/svg+xml;image/x-tga;image/webp; MimeType=image/pxo;image/png;image/bmp;image/vnd.radiance;image/jpeg;image/svg+xml;image/x-tga;image/webp;

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://1kj5gcswa3t2"
path="res://.godot/imported/x_minus_y_mirror_off.png-da237e3b5b7ad1dfef1c935385f53dc5.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/graphics/misc/x_minus_y_mirror_off.png"
dest_files=["res://.godot/imported/x_minus_y_mirror_off.png-da237e3b5b7ad1dfef1c935385f53dc5.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dn14bkxwdqsfk"
path="res://.godot/imported/x_minus_y_mirror_on.png-0e9186904d8241facc4a0c1190f32c53.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/graphics/misc/x_minus_y_mirror_on.png"
dest_files=["res://.godot/imported/x_minus_y_mirror_on.png-0e9186904d8241facc4a0c1190f32c53.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 183 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://dlxhm0ronna25"
path="res://.godot/imported/xy_mirror_off.png-8d2fd9ebdf350f0cd384fdf39fed4ec1.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/graphics/misc/xy_mirror_off.png"
dest_files=["res://.godot/imported/xy_mirror_off.png-8d2fd9ebdf350f0cd384fdf39fed4ec1.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 B

View file

@ -0,0 +1,34 @@
[remap]
importer="texture"
type="CompressedTexture2D"
uid="uid://cu2uqp5oupt80"
path="res://.godot/imported/xy_mirror_on.png-95d443df3b6d17add41283bdd720ea7e.ctex"
metadata={
"vram_texture": false
}
[deps]
source_file="res://assets/graphics/misc/xy_mirror_on.png"
dest_files=["res://.godot/imported/xy_mirror_on.png-95d443df3b6d17add41283bdd720ea7e.ctex"]
[params]
compress/mode=0
compress/high_quality=false
compress/lossy_quality=0.7
compress/hdr_compression=1
compress/normal_map=0
compress/channel_pack=0
mipmaps/generate=false
mipmaps/limit=-1
roughness/mode=0
roughness/src_normal=""
process/fix_alpha_border=true
process/premult_alpha=false
process/normal_map_invert_y=false
process/hdr_as_srgb=false
process/hdr_clamp_exposure=false
process/size_limit=0
detect_3d/compress_to=1

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 162 B

After

Width:  |  Height:  |  Size: 136 B

View file

@ -184,7 +184,7 @@ var show_x_symmetry_axis := false
## If true, the y symmetry guide ( | ) is visible. ## If true, the y symmetry guide ( | ) is visible.
var show_y_symmetry_axis := false var show_y_symmetry_axis := false
## If true, the x=y symmetry guide ( / ) is visible. ## If true, the x=y symmetry guide ( / ) is visible.
var show_x_y_symmetry_axis := false var show_xy_symmetry_axis := false
## If true, the x==y symmetry guide ( \ ) is visible. ## If true, the x==y symmetry guide ( \ ) is visible.
var show_x_minus_y_symmetry_axis := false var show_x_minus_y_symmetry_axis := false
@ -1066,7 +1066,9 @@ func get_available_font_names() -> PackedStringArray:
if font_name in font_names: if font_name in font_names:
continue continue
font_names.append(font_name) font_names.append(font_name)
for system_font_name in OS.get_system_fonts(): var system_fonts := OS.get_system_fonts()
system_fonts.sort()
for system_font_name in system_fonts:
if system_font_name in font_names: if system_font_name in font_names:
continue continue
font_names.append(system_font_name) font_names.append(system_font_name)

View file

@ -36,9 +36,10 @@ func does_palette_exist(palette_name: String) -> bool:
func select_palette(palette_name: String) -> void: func select_palette(palette_name: String) -> void:
current_palette = palettes.get(palette_name) current_palette = palettes.get(palette_name, null)
_clear_selected_colors() _clear_selected_colors()
Global.config_cache.set_value("data", "last_palette", current_palette.name) if is_instance_valid(current_palette):
Global.config_cache.set_value("data", "last_palette", current_palette.name)
palette_selected.emit(palette_name) palette_selected.emit(palette_name)
@ -224,6 +225,7 @@ func current_palete_delete(permanent := true) -> void:
select_palette(palettes.keys()[0]) select_palette(palettes.keys()[0])
else: else:
current_palette = null current_palette = null
select_palette("")
func current_palette_add_color(mouse_button: int, start_index := 0) -> void: func current_palette_add_color(mouse_button: int, start_index := 0) -> void:

View file

@ -15,8 +15,8 @@ const X_MINUS_Y_LINE := Vector2(0.707107, 0.707107)
var picking_color_for := MOUSE_BUTTON_LEFT var picking_color_for := MOUSE_BUTTON_LEFT
var horizontal_mirror := false var horizontal_mirror := false
var vertical_mirror := false var vertical_mirror := false
var diagonal_mirror := false var diagonal_xy_mirror := false
var diagonal_opposite_mirror := false var diagonal_x_minus_y_mirror := false
var pixel_perfect := false var pixel_perfect := false
var alpha_locked := false var alpha_locked := false
@ -534,23 +534,23 @@ func get_mirrored_positions(
if vertical_mirror: if vertical_mirror:
positions.append(calculate_mirror_vertical(mirror_x, project, offset)) positions.append(calculate_mirror_vertical(mirror_x, project, offset))
else: else:
if diagonal_mirror: if diagonal_xy_mirror:
positions.append(calculate_mirror_xy(mirror_x, project)) positions.append(calculate_mirror_xy(mirror_x, project))
if diagonal_opposite_mirror: if diagonal_x_minus_y_mirror:
positions.append(calculate_mirror_x_minus_y(mirror_x, project)) positions.append(calculate_mirror_x_minus_y(mirror_x, project))
if vertical_mirror: if vertical_mirror:
var mirror_y := calculate_mirror_vertical(pos, project, offset) var mirror_y := calculate_mirror_vertical(pos, project, offset)
positions.append(mirror_y) positions.append(mirror_y)
if diagonal_mirror: if diagonal_xy_mirror:
positions.append(calculate_mirror_xy(mirror_y, project)) positions.append(calculate_mirror_xy(mirror_y, project))
if diagonal_opposite_mirror: if diagonal_x_minus_y_mirror:
positions.append(calculate_mirror_x_minus_y(mirror_y, project)) positions.append(calculate_mirror_x_minus_y(mirror_y, project))
if diagonal_mirror: if diagonal_xy_mirror:
var mirror_diagonal := calculate_mirror_xy(pos, project) var mirror_diagonal := calculate_mirror_xy(pos, project)
positions.append(mirror_diagonal) positions.append(mirror_diagonal)
if not horizontal_mirror and not vertical_mirror: if not horizontal_mirror and not vertical_mirror and diagonal_x_minus_y_mirror:
positions.append(calculate_mirror_x_minus_y(mirror_diagonal, project)) positions.append(calculate_mirror_x_minus_y(mirror_diagonal, project))
if diagonal_opposite_mirror: if diagonal_x_minus_y_mirror:
positions.append(calculate_mirror_x_minus_y(pos, project)) positions.append(calculate_mirror_x_minus_y(pos, project))
return positions return positions
@ -564,11 +564,14 @@ func calculate_mirror_vertical(pos: Vector2i, project: Project, offset := 0) ->
func calculate_mirror_xy(pos: Vector2i, project: Project) -> Vector2i: func calculate_mirror_xy(pos: Vector2i, project: Project) -> Vector2i:
return Vector2i(Vector2(pos).reflect(XY_LINE).round()) + project.size - Vector2i.ONE return Vector2i(Vector2(pos).reflect(XY_LINE).round()) + Vector2i(project.xy_symmetry_point)
func calculate_mirror_x_minus_y(pos: Vector2i, _project: Project) -> Vector2i: func calculate_mirror_x_minus_y(pos: Vector2i, project: Project) -> Vector2i:
return Vector2i(Vector2(pos).reflect(X_MINUS_Y_LINE).round()) return (
Vector2i(Vector2(pos).reflect(X_MINUS_Y_LINE).round())
+ Vector2i(project.x_minus_y_symmetry_point)
)
func set_button_size(button_size: int) -> void: func set_button_size(button_size: int) -> void:

View file

@ -8,7 +8,7 @@ var image: ImageExtended:
set = image_changed set = image_changed
func _init(_image: ImageExtended, _opacity := 1.0) -> void: func _init(_image := ImageExtended.new(), _opacity := 1.0) -> void:
image_texture = ImageTexture.new() image_texture = ImageTexture.new()
image = _image # Set image and call setter image = _image # Set image and call setter
opacity = _opacity opacity = _opacity
@ -20,7 +20,7 @@ func image_changed(value: ImageExtended) -> void:
image_texture.set_image(image) image_texture.set_image(image)
func get_content(): func get_content() -> ImageExtended:
return image return image
@ -34,17 +34,19 @@ func set_content(content, texture: ImageTexture = null) -> void:
image_texture.update(image) image_texture.update(image)
func create_empty_content(): func create_empty_content() -> ImageExtended:
var empty_image := Image.create( var empty := Image.create(image.get_width(), image.get_height(), false, image.get_format())
image.get_size().x, image.get_size().y, false, Image.FORMAT_RGBA8 var new_image := ImageExtended.new()
) new_image.copy_from_custom(empty, image.is_indexed)
return empty_image return new_image
func copy_content(): func copy_content() -> ImageExtended:
var copy_image := Image.create_from_data( var tmp_image := Image.create_from_data(
image.get_width(), image.get_height(), false, Image.FORMAT_RGBA8, image.get_data() image.get_width(), image.get_height(), false, image.get_format(), image.get_data()
) )
var copy_image := ImageExtended.new()
copy_image.copy_from_custom(tmp_image, image.is_indexed)
return copy_image return copy_image

View file

@ -87,8 +87,8 @@ func set_pixel(image: Image, position: Vector2i, color: Color, ignore_mirroring
if ( if (
not Tools.horizontal_mirror not Tools.horizontal_mirror
and not Tools.vertical_mirror and not Tools.vertical_mirror
and not Tools.diagonal_mirror and not Tools.diagonal_xy_mirror
and not Tools.diagonal_opposite_mirror and not Tools.diagonal_x_minus_y_mirror
): ):
return return
# Handle mirroring # Handle mirroring

View file

@ -74,17 +74,20 @@ func select_palette(_name: String, convert_to_rgb := true) -> void:
## Updates [member palette] to contain the colors of [member current_palette]. ## Updates [member palette] to contain the colors of [member current_palette].
func update_palette() -> void: func update_palette() -> void:
if palette.size() != current_palette.colors.size(): if not is_instance_valid(current_palette):
palette.resize(current_palette.colors.size()) return
if palette.size() != current_palette.colors_max:
palette.resize(current_palette.colors_max)
palette.fill(TRANSPARENT)
for i in current_palette.colors: for i in current_palette.colors:
palette[i] = current_palette.colors[i].color palette[i] = current_palette.colors[i].color
## Displays the actual RGBA values of each pixel in the image from indexed mode. ## Displays the actual RGBA values of each pixel in the image from indexed mode.
func convert_indexed_to_rgb() -> void: func convert_indexed_to_rgb() -> void:
if not is_indexed: if not is_indexed or not is_instance_valid(current_palette):
return return
var palette_image := Palettes.current_palette.convert_to_image() var palette_image := current_palette.convert_to_image(false)
var palette_texture := ImageTexture.create_from_image(palette_image) var palette_texture := ImageTexture.create_from_image(palette_image)
var shader_image_effect := ShaderImageEffect.new() var shader_image_effect := ShaderImageEffect.new()
var indices_texture := ImageTexture.create_from_image(indices_image) var indices_texture := ImageTexture.create_from_image(indices_image)
@ -96,9 +99,9 @@ func convert_indexed_to_rgb() -> void:
## Automatically maps each color of the image's pixel to the closest color of the palette, ## Automatically maps each color of the image's pixel to the closest color of the palette,
## by finding the palette color's index and storing it in [member indices_image]. ## by finding the palette color's index and storing it in [member indices_image].
func convert_rgb_to_indexed() -> void: func convert_rgb_to_indexed() -> void:
if not is_indexed: if not is_indexed or not is_instance_valid(current_palette):
return return
var palette_image := Palettes.current_palette.convert_to_image() var palette_image := current_palette.convert_to_image(false)
var palette_texture := ImageTexture.create_from_image(palette_image) var palette_texture := ImageTexture.create_from_image(palette_image)
var params := { var params := {
"palette_texture": palette_texture, "rgb_texture": ImageTexture.create_from_image(self) "palette_texture": palette_texture, "rgb_texture": ImageTexture.create_from_image(self)

View file

@ -69,6 +69,8 @@ var user_data := "" ## User defined data, set in the project properties.
var x_symmetry_point: float var x_symmetry_point: float
var y_symmetry_point: float var y_symmetry_point: float
var xy_symmetry_point: Vector2
var x_minus_y_symmetry_point: Vector2
var x_symmetry_axis := SymmetryGuide.new() var x_symmetry_axis := SymmetryGuide.new()
var y_symmetry_axis := SymmetryGuide.new() var y_symmetry_axis := SymmetryGuide.new()
var diagonal_xy_symmetry_axis := SymmetryGuide.new() var diagonal_xy_symmetry_axis := SymmetryGuide.new()
@ -113,6 +115,8 @@ func _init(_frames: Array[Frame] = [], _name := tr("untitled"), _size := Vector2
x_symmetry_point = size.x - 1 x_symmetry_point = size.x - 1
y_symmetry_point = size.y - 1 y_symmetry_point = size.y - 1
xy_symmetry_point = Vector2i(size.y, size.x) - Vector2i.ONE
x_minus_y_symmetry_point = Vector2(maxi(size.x - size.y, 0), maxi(size.y - size.x, 0))
x_symmetry_axis.type = Guide.Types.HORIZONTAL x_symmetry_axis.type = Guide.Types.HORIZONTAL
x_symmetry_axis.project = self x_symmetry_axis.project = self
x_symmetry_axis.add_point(Vector2(-19999, y_symmetry_point / 2 + 0.5)) x_symmetry_axis.add_point(Vector2(-19999, y_symmetry_point / 2 + 0.5))
@ -128,13 +132,13 @@ func _init(_frames: Array[Frame] = [], _name := tr("untitled"), _size := Vector2
diagonal_xy_symmetry_axis.type = Guide.Types.XY diagonal_xy_symmetry_axis.type = Guide.Types.XY
diagonal_xy_symmetry_axis.project = self diagonal_xy_symmetry_axis.project = self
diagonal_xy_symmetry_axis.add_point(Vector2(19999, -19999)) diagonal_xy_symmetry_axis.add_point(Vector2(19999, -19999))
diagonal_xy_symmetry_axis.add_point(Vector2i(-19999, 19999) + size) diagonal_xy_symmetry_axis.add_point(Vector2(-19999, 19999) + xy_symmetry_point + Vector2.ONE)
Global.canvas.add_child(diagonal_xy_symmetry_axis) Global.canvas.add_child(diagonal_xy_symmetry_axis)
diagonal_x_minus_y_symmetry_axis.type = Guide.Types.X_MINUS_Y diagonal_x_minus_y_symmetry_axis.type = Guide.Types.X_MINUS_Y
diagonal_x_minus_y_symmetry_axis.project = self diagonal_x_minus_y_symmetry_axis.project = self
diagonal_x_minus_y_symmetry_axis.add_point(Vector2(-19999, -19999)) diagonal_x_minus_y_symmetry_axis.add_point(Vector2(-19999, -19999))
diagonal_x_minus_y_symmetry_axis.add_point(Vector2(19999, 19999)) diagonal_x_minus_y_symmetry_axis.add_point(Vector2(19999, 19999) + x_minus_y_symmetry_point)
Global.canvas.add_child(diagonal_x_minus_y_symmetry_axis) Global.canvas.add_child(diagonal_x_minus_y_symmetry_axis)
if OS.get_name() == "Web": if OS.get_name() == "Web":
@ -182,6 +186,7 @@ func commit_undo() -> void:
Global.canvas.selection.transform_content_cancel() Global.canvas.selection.transform_content_cancel()
else: else:
undo_redo.undo() undo_redo.undo()
SteamManager.set_achievement("ACH_TIME_TRAVELER")
func commit_redo() -> void: func commit_redo() -> void:

View file

@ -10,12 +10,17 @@ const APP_ID := 2779170
## because it is not available in non-Steam builds. ## because it is not available in non-Steam builds.
static var steam_class static var steam_class
static var achievements := { static var achievements := {
"ACH_ART_LOVER": false,
"ACH_FIRST_PIXEL": false, "ACH_FIRST_PIXEL": false,
"ACH_ERASE_PIXEL": false, "ACH_ERASE_PIXEL": false,
"ACH_TIME_TRAVELER": false,
"ACH_SAVE": false, "ACH_SAVE": false,
"ACH_ALMOST_FORGOT": false,
"ACH_PREFERENCES": false, "ACH_PREFERENCES": false,
"ACH_ONLINE_DOCS": false, "ACH_ONLINE_DOCS": false,
"ACH_SUPPORT_DEVELOPMENT": false, "ACH_SUPPORT_DEVELOPMENT": false,
"ACH_BLEND_IN": false,
"ACH_STRONGER_TOGETHER": false,
"ACH_3D_LAYER": false, "ACH_3D_LAYER": false,
} }

View file

@ -540,6 +540,7 @@ func _on_QuitAndSaveDialog_custom_action(action: String) -> void:
func _on_QuitAndSaveDialog_confirmed() -> void: func _on_QuitAndSaveDialog_confirmed() -> void:
is_quitting_on_save = true is_quitting_on_save = true
show_save_dialog(changed_projects_on_quit[0]) show_save_dialog(changed_projects_on_quit[0])
SteamManager.set_achievement("ACH_ALMOST_FORGOT")
func _quit() -> void: func _quit() -> void:

View file

@ -25,7 +25,7 @@ var colors_max := 0
class PaletteColor: class PaletteColor:
var color := Color.TRANSPARENT var color := Color(0, 0, 0, 0)
var index := -1 var index := -1
func _init(init_color := Color.BLACK, init_index := -1) -> void: func _init(init_color := Color.BLACK, init_index := -1) -> void:
@ -358,9 +358,11 @@ static func strip_unvalid_characters(string_to_strip: String) -> String:
return regex.sub(string_to_strip, "", true) return regex.sub(string_to_strip, "", true)
func convert_to_image() -> Image: func convert_to_image(crop_image := true) -> Image:
var image := Image.create(colors_max, 1, false, Image.FORMAT_RGBA8) var image := Image.create(colors_max, 1, false, Image.FORMAT_RGBA8)
for i in colors_max: for i in colors_max:
if colors.has(i): if colors.has(i):
image.set_pixel(i, 0, colors[i].color) image.set_pixel(i, 0, Color(colors[i].color.to_html()))
if crop_image:
image.copy_from(image.get_region(image.get_used_rect()))
return image return image

View file

@ -23,10 +23,6 @@ func _ready() -> void:
func set_palette(new_palette: Palette) -> void: func set_palette(new_palette: Palette) -> void:
# Only display valid palette objects
if not new_palette:
return
current_palette = new_palette current_palette = new_palette
grid_window_origin = Vector2.ZERO grid_window_origin = Vector2.ZERO
@ -87,6 +83,8 @@ func scroll_palette(origin: Vector2i) -> void:
## Called when the color changes, either the left or the right, determined by [param mouse_button]. ## Called when the color changes, either the left or the right, determined by [param mouse_button].
## If current palette has [param target_color] as a [Color], then select it. ## If current palette has [param target_color] as a [Color], then select it.
func find_and_select_color(target_color: Color, mouse_button: int) -> void: func find_and_select_color(target_color: Color, mouse_button: int) -> void:
if not is_instance_valid(current_palette):
return
var old_index := Palettes.current_palette_get_selected_color_index(mouse_button) var old_index := Palettes.current_palette_get_selected_color_index(mouse_button)
for color_ind in swatches.size(): for color_ind in swatches.size():
if ( if (
@ -115,6 +113,8 @@ func find_and_select_color(target_color: Color, mouse_button: int) -> void:
## Displays a left/right highlight over a swatch ## Displays a left/right highlight over a swatch
func select_swatch(mouse_button: int, palette_index: int, old_palette_index: int) -> void: func select_swatch(mouse_button: int, palette_index: int, old_palette_index: int) -> void:
if not is_instance_valid(current_palette):
return
var index := convert_palette_index_to_grid_index(palette_index) var index := convert_palette_index_to_grid_index(palette_index)
var old_index := convert_palette_index_to_grid_index(old_palette_index) var old_index := convert_palette_index_to_grid_index(old_palette_index)
if index >= 0 and index < swatches.size(): if index >= 0 and index < swatches.size():
@ -159,16 +159,17 @@ func convert_palette_index_to_grid_index(palette_index: int) -> int:
func resize_grid(new_rect_size: Vector2) -> void: func resize_grid(new_rect_size: Vector2) -> void:
if not is_instance_valid(current_palette):
return
var grid_x: int = ( var grid_x: int = (
new_rect_size.x / (swatch_size.x + get("theme_override_constants/h_separation")) new_rect_size.x / (swatch_size.x + get("theme_override_constants/h_separation"))
) )
var grid_y: int = ( var grid_y: int = (
new_rect_size.y / (swatch_size.y + get("theme_override_constants/v_separation")) new_rect_size.y / (swatch_size.y + get("theme_override_constants/v_separation"))
) )
grid_size.x = mini(grid_x, current_palette.width) if is_instance_valid(current_palette):
grid_size.y = mini(grid_y, current_palette.height) grid_size.x = mini(grid_x, current_palette.width)
grid_size.y = mini(grid_y, current_palette.height)
else:
grid_size = Vector2i.ZERO
setup_swatches() setup_swatches()
draw_palette() draw_palette()

View file

@ -89,16 +89,16 @@ func select_palette(palette_name: String) -> void:
var palette_id = palettes_path_id.get(palette_name) var palette_id = palettes_path_id.get(palette_name)
if palette_id != null: if palette_id != null:
palette_select.selected = palette_id palette_select.selected = palette_id
palette_grid.set_palette(Palettes.current_palette) palette_grid.set_palette(Palettes.current_palette)
palette_scroll.resize_grid() palette_scroll.resize_grid()
palette_scroll.set_sliders(Palettes.current_palette, palette_grid.grid_window_origin) palette_scroll.set_sliders(Palettes.current_palette, palette_grid.grid_window_origin)
var left_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_LEFT) var left_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_LEFT)
var right_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT) var right_selected := Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT)
palette_grid.select_swatch(MOUSE_BUTTON_LEFT, left_selected, left_selected) palette_grid.select_swatch(MOUSE_BUTTON_LEFT, left_selected, left_selected)
palette_grid.select_swatch(MOUSE_BUTTON_RIGHT, right_selected, right_selected) palette_grid.select_swatch(MOUSE_BUTTON_RIGHT, right_selected, right_selected)
toggle_add_delete_buttons() toggle_add_delete_buttons()
## Select and display current palette ## Select and display current palette
@ -115,6 +115,8 @@ func redraw_current_palette() -> void:
func toggle_add_delete_buttons() -> void: func toggle_add_delete_buttons() -> void:
if not is_instance_valid(Palettes.current_palette):
return
add_color_button.disabled = Palettes.current_palette.is_full() add_color_button.disabled = Palettes.current_palette.is_full()
if add_color_button.disabled: if add_color_button.disabled:
add_color_button.mouse_default_cursor_shape = CURSOR_FORBIDDEN add_color_button.mouse_default_cursor_shape = CURSOR_FORBIDDEN
@ -252,6 +254,7 @@ func _on_ColorPicker_color_changed(color: Color) -> void:
== Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT) == Palettes.current_palette_get_selected_color_index(MOUSE_BUTTON_RIGHT)
): ):
Tools.assign_color(color, MOUSE_BUTTON_RIGHT) Tools.assign_color(color, MOUSE_BUTTON_RIGHT)
Palettes.current_palette_set_color(edited_swatch_index, edited_swatch_color)
## Saves edited swatch to palette file when color selection dialog is closed ## Saves edited swatch to palette file when color selection dialog is closed

View file

@ -4,9 +4,9 @@ var scroll := Vector2i.ZERO
var drag_started := false var drag_started := false
var drag_start_position := Vector2i.ZERO var drag_start_position := Vector2i.ZERO
@onready var h_slider := %HScrollBar @onready var h_slider := %HScrollBar as HScrollBar
@onready var v_slider := %VScrollBar @onready var v_slider := %VScrollBar as VScrollBar
@onready var palette_grid := %PaletteGrid @onready var palette_grid := %PaletteGrid as PaletteGrid
func _input(event: InputEvent) -> void: func _input(event: InputEvent) -> void:
@ -17,16 +17,21 @@ func _input(event: InputEvent) -> void:
func set_sliders(palette: Palette, origin: Vector2i) -> void: func set_sliders(palette: Palette, origin: Vector2i) -> void:
if not is_instance_valid(palette): if is_instance_valid(palette):
return h_slider.value = origin.x
h_slider.value = origin.x h_slider.max_value = palette.width
h_slider.max_value = palette.width h_slider.page = palette_grid.grid_size.x
h_slider.page = palette_grid.grid_size.x v_slider.value = origin.y
v_slider.max_value = palette.height
v_slider.page = palette_grid.grid_size.y
else:
h_slider.value = 0
h_slider.max_value = 0
h_slider.page = 0
v_slider.value = 0
v_slider.max_value = 0
v_slider.page = 0
h_slider.visible = false if h_slider.max_value <= palette_grid.grid_size.x else true h_slider.visible = false if h_slider.max_value <= palette_grid.grid_size.x else true
v_slider.value = origin.y
v_slider.max_value = palette.height
v_slider.page = palette_grid.grid_size.y
v_slider.visible = false if v_slider.max_value <= palette_grid.grid_size.y else true v_slider.visible = false if v_slider.max_value <= palette_grid.grid_size.y else true
@ -58,7 +63,7 @@ func _on_PaletteGrid_gui_input(event: InputEvent) -> void:
drag_started = true drag_started = true
# Keeps position where the dragging started # Keeps position where the dragging started
drag_start_position = ( drag_start_position = (
event.position + Vector2i(h_slider.value, v_slider.value) * palette_grid.swatch_size event.position + Vector2(h_slider.value, v_slider.value) * palette_grid.swatch_size
) )
if event is InputEventMouseMotion and drag_started: if event is InputEventMouseMotion and drag_started:

View file

@ -14,7 +14,7 @@ vec4 swap_color(vec4 color) {
int n_of_colors = textureSize(palette_texture, 0).x; int n_of_colors = textureSize(palette_texture, 0).x;
int color_index = find_index(color, n_of_colors, palette_texture); int color_index = find_index(color, n_of_colors, palette_texture);
return texture(palette_texture, vec2(float(color_index) / float(n_of_colors), 0.0)); return texelFetch(palette_texture, ivec2(color_index, 0), 0);
} }
void fragment() { void fragment() {

View file

@ -2,8 +2,7 @@ int find_index(vec4 color, int n_of_colors, sampler2D palette_texture) {
int color_index = 0; int color_index = 0;
float smaller_distance = distance(color, texture(palette_texture, vec2(0.0))); float smaller_distance = distance(color, texture(palette_texture, vec2(0.0)));
for (int i = 0; i <= n_of_colors; i++) { for (int i = 0; i <= n_of_colors; i++) {
vec2 uv = vec2(float(i) / float(n_of_colors), 0.0); vec4 palette_color = texelFetch(palette_texture, ivec2(i, 0), 0);
vec4 palette_color = texture(palette_texture, uv);
float dist = distance(color, palette_color); float dist = distance(color, palette_color);
if (dist < smaller_distance) { if (dist < smaller_distance) {
smaller_distance = dist; smaller_distance = dist;

View file

@ -7,16 +7,16 @@ uniform sampler2D palette_texture : filter_nearest;
uniform sampler2D indices_texture : filter_nearest; uniform sampler2D indices_texture : filter_nearest;
void fragment() { void fragment() {
float index = texture(indices_texture, UV).r; float index = texture(indices_texture, UV).r * 255.0;
if (index <= EPSILON) { // If index is zero, make it transparent if (index <= EPSILON) { // If index is zero, make it transparent
COLOR = vec4(0.0); COLOR = vec4(0.0);
} }
else { else {
float n_of_colors = float(textureSize(palette_texture, 0).x); float n_of_colors = float(textureSize(palette_texture, 0).x);
index -= 1.0 / 255.0; index -= 1.0;
float index_normalized = ((index * 255.0)) / n_of_colors; float index_normalized = index / n_of_colors;
if (index_normalized + EPSILON < 1.0) { if (index < n_of_colors) {
COLOR = texture(palette_texture, vec2(index_normalized + EPSILON, 0.0)); COLOR = texelFetch(palette_texture, ivec2(int(index), 0), 0);
} }
else { else {
// If index is bigger than the size of the palette, make it transparent. // If index is bigger than the size of the palette, make it transparent.

View file

@ -8,7 +8,7 @@ uniform sampler2D palette_texture : filter_nearest;
void fragment() { void fragment() {
vec4 color = texture(rgb_texture, UV); vec4 color = texture(rgb_texture, UV);
if (color.a <= 0.01) { if (color.a <= 0.0001) {
COLOR.r = 0.0; COLOR.r = 0.0;
} }
else { else {

View file

@ -269,9 +269,11 @@ func fill_in_selection() -> void:
var selection_map_copy := project.selection_map.return_cropped_copy(project.size) var selection_map_copy := project.selection_map.return_cropped_copy(project.size)
for image in images: for image in images:
image.blit_rect_mask(filler, selection_map_copy, rect, rect.position) image.blit_rect_mask(filler, selection_map_copy, rect, rect.position)
image.convert_rgb_to_indexed()
else: else:
for image in images: for image in images:
image.fill(tool_slot.color) image.fill(tool_slot.color)
image.convert_rgb_to_indexed()
else: else:
# End early if we are filling with an empty pattern # End early if we are filling with an empty pattern
var pattern_image: Image = _pattern.image var pattern_image: Image = _pattern.image

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=6 format=3 uid="uid://ct4o5i1jeul3k"] [gd_scene load_steps=6 format=3 uid="uid://bdregpkflev7u"]
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1_1q6ub"] [ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1_1q6ub"]
[ext_resource type="Script" path="res://src/Tools/UtilityTools/Text.gd" id="2_ql5g6"] [ext_resource type="Script" path="res://src/Tools/UtilityTools/Text.gd" id="2_ql5g6"]
@ -63,6 +63,8 @@ stretch_margin_bottom = 3
script = ExtResource("3_tidsq") script = ExtResource("3_tidsq")
prefix = "Size:" prefix = "Size:"
suffix = "px" suffix = "px"
global_increment_action = "brush_size_increment"
global_decrement_action = "brush_size_decrement"
[node name="GridContainer" type="GridContainer" parent="." index="4"] [node name="GridContainer" type="GridContainer" parent="." index="4"]
layout_mode = 2 layout_mode = 2

View file

@ -31,12 +31,13 @@ func _input(_event: InputEvent) -> void:
if type == Types.HORIZONTAL: if type == Types.HORIZONTAL:
point0.y -= width * INPUT_WIDTH point0.y -= width * INPUT_WIDTH
point1.y += width * INPUT_WIDTH point1.y += width * INPUT_WIDTH
else: elif type == Types.VERTICAL:
point0.x -= width * INPUT_WIDTH point0.x -= width * INPUT_WIDTH
point1.x += width * INPUT_WIDTH point1.x += width * INPUT_WIDTH
var rect := Rect2() var rect := Rect2()
rect.position = point0 rect.position = point0
rect.end = point1 rect.end = point1
rect = rect.abs()
if ( if (
Input.is_action_just_pressed(&"left_mouse") Input.is_action_just_pressed(&"left_mouse")
and Global.can_draw and Global.can_draw
@ -55,7 +56,7 @@ func _input(_event: InputEvent) -> void:
var yy := snappedf(mouse_pos.y, 0.5) var yy := snappedf(mouse_pos.y, 0.5)
points[0].y = yy points[0].y = yy
points[1].y = yy points[1].y = yy
else: elif type == Types.VERTICAL:
var xx := snappedf(mouse_pos.x, 0.5) var xx := snappedf(mouse_pos.x, 0.5)
points[0].x = xx points[0].x = xx
points[1].x = xx points[1].x = xx
@ -234,7 +235,7 @@ func _project_switched() -> void:
elif type == Types.VERTICAL: elif type == Types.VERTICAL:
visible = Global.show_y_symmetry_axis and Global.show_guides visible = Global.show_y_symmetry_axis and Global.show_guides
elif type == Types.XY: elif type == Types.XY:
visible = Global.show_x_y_symmetry_axis and Global.show_guides visible = Global.show_xy_symmetry_axis and Global.show_guides
elif type == Types.X_MINUS_Y: elif type == Types.X_MINUS_Y:
visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides
else: else:

View file

@ -808,9 +808,11 @@ func delete(selected_cels := true) -> void:
image.blit_rect_mask( image.blit_rect_mask(
blank, selection_map_copy, big_bounding_rectangle, big_bounding_rectangle.position blank, selection_map_copy, big_bounding_rectangle, big_bounding_rectangle.position
) )
image.convert_rgb_to_indexed()
else: else:
for image in images: for image in images:
image.fill(0) image.fill(0)
image.convert_rgb_to_indexed()
commit_undo("Draw", undo_data_tmp) commit_undo("Draw", undo_data_tmp)

View file

@ -90,6 +90,8 @@ func _on_SplashDialog_about_to_show() -> void:
func change_artwork(direction: int) -> void: func change_artwork(direction: int) -> void:
if direction != 0:
SteamManager.set_achievement("ACH_ART_LOVER")
chosen_artwork = wrapi(chosen_artwork + direction, 0, artworks.size()) chosen_artwork = wrapi(chosen_artwork + direction, 0, artworks.size())
splash_art_texturerect.texture = artworks[chosen_artwork].artwork splash_art_texturerect.texture = artworks[chosen_artwork].artwork
set_process(artworks[chosen_artwork].artwork is AnimatedTexture) set_process(artworks[chosen_artwork].artwork is AnimatedTexture)

View file

@ -3,6 +3,8 @@ extends PanelContainer
@onready var grid_container: GridContainer = find_child("GridContainer") @onready var grid_container: GridContainer = find_child("GridContainer")
@onready var horizontal_mirror: BaseButton = grid_container.get_node("Horizontal") @onready var horizontal_mirror: BaseButton = grid_container.get_node("Horizontal")
@onready var vertical_mirror: BaseButton = grid_container.get_node("Vertical") @onready var vertical_mirror: BaseButton = grid_container.get_node("Vertical")
@onready var diagonal_xy_mirror: BaseButton = grid_container.get_node("DiagonalXY")
@onready var diagonal_x_minus_y_mirror: BaseButton = grid_container.get_node("DiagonalXMinusY")
@onready var pixel_perfect: BaseButton = grid_container.get_node("PixelPerfect") @onready var pixel_perfect: BaseButton = grid_container.get_node("PixelPerfect")
@onready var alpha_lock: BaseButton = grid_container.get_node("AlphaLock") @onready var alpha_lock: BaseButton = grid_container.get_node("AlphaLock")
@onready var dynamics: Button = $"%Dynamics" @onready var dynamics: Button = $"%Dynamics"
@ -39,25 +41,25 @@ func _on_resized() -> void:
grid_container.columns = column_n grid_container.columns = column_n
func _on_Horizontal_toggled(button_pressed: bool) -> void: func _on_Horizontal_toggled(toggled_on: bool) -> void:
Tools.horizontal_mirror = button_pressed Tools.horizontal_mirror = toggled_on
Global.config_cache.set_value("tools", "horizontal_mirror", button_pressed) Global.config_cache.set_value("tools", "horizontal_mirror", toggled_on)
Global.show_y_symmetry_axis = button_pressed Global.show_y_symmetry_axis = toggled_on
Global.current_project.y_symmetry_axis.visible = ( Global.current_project.y_symmetry_axis.visible = (
Global.show_y_symmetry_axis and Global.show_guides Global.show_y_symmetry_axis and Global.show_guides
) )
var texture_button: TextureRect = horizontal_mirror.get_node("TextureRect") var texture_button: TextureRect = horizontal_mirror.get_node("TextureRect")
var file_name := "horizontal_mirror_on.png" var file_name := "horizontal_mirror_on.png"
if !button_pressed: if not toggled_on:
file_name = "horizontal_mirror_off.png" file_name = "horizontal_mirror_off.png"
Global.change_button_texturerect(texture_button, file_name) Global.change_button_texturerect(texture_button, file_name)
func _on_Vertical_toggled(button_pressed: bool) -> void: func _on_Vertical_toggled(toggled_on: bool) -> void:
Tools.vertical_mirror = button_pressed Tools.vertical_mirror = toggled_on
Global.config_cache.set_value("tools", "vertical_mirror", button_pressed) Global.config_cache.set_value("tools", "vertical_mirror", toggled_on)
Global.show_x_symmetry_axis = button_pressed Global.show_x_symmetry_axis = toggled_on
# If the button is not pressed but another button is, keep the symmetry guide visible # If the button is not pressed but another button is, keep the symmetry guide visible
Global.current_project.x_symmetry_axis.visible = ( Global.current_project.x_symmetry_axis.visible = (
Global.show_x_symmetry_axis and Global.show_guides Global.show_x_symmetry_axis and Global.show_guides
@ -65,11 +67,43 @@ func _on_Vertical_toggled(button_pressed: bool) -> void:
var texture_button: TextureRect = vertical_mirror.get_node("TextureRect") var texture_button: TextureRect = vertical_mirror.get_node("TextureRect")
var file_name := "vertical_mirror_on.png" var file_name := "vertical_mirror_on.png"
if !button_pressed: if not toggled_on:
file_name = "vertical_mirror_off.png" file_name = "vertical_mirror_off.png"
Global.change_button_texturerect(texture_button, file_name) Global.change_button_texturerect(texture_button, file_name)
func _on_diagonal_xy_toggled(toggled_on: bool) -> void:
Tools.diagonal_xy_mirror = toggled_on
Global.config_cache.set_value("tools", "diagonal_xy_mirror", toggled_on)
Global.show_xy_symmetry_axis = toggled_on
# If the button is not pressed but another button is, keep the symmetry guide visible
Global.current_project.diagonal_xy_symmetry_axis.visible = (
Global.show_xy_symmetry_axis and Global.show_guides
)
var texture_button: TextureRect = diagonal_xy_mirror.get_node("TextureRect")
var file_name := "xy_mirror_on.png"
if not toggled_on:
file_name = "xy_mirror_off.png"
Global.change_button_texturerect(texture_button, file_name)
func _on_diagonal_x_minus_y_toggled(toggled_on: bool) -> void:
Tools.diagonal_x_minus_y_mirror = toggled_on
Global.config_cache.set_value("tools", "diagonal_x_minus_y_mirror", toggled_on)
Global.show_x_minus_y_symmetry_axis = toggled_on
# If the button is not pressed but another button is, keep the symmetry guide visible
Global.current_project.diagonal_x_minus_y_symmetry_axis.visible = (
Global.show_x_minus_y_symmetry_axis and Global.show_guides
)
var texture_button: TextureRect = diagonal_x_minus_y_mirror.get_node("TextureRect")
var file_name := "x_minus_y_mirror_on.png"
if not toggled_on:
file_name = "x_minus_y_mirror_off.png"
Global.change_button_texturerect(texture_button, file_name)
func _on_PixelPerfect_toggled(button_pressed: bool) -> void: func _on_PixelPerfect_toggled(button_pressed: bool) -> void:
Tools.pixel_perfect = button_pressed Tools.pixel_perfect = button_pressed
Global.config_cache.set_value("tools", "pixel_perfect", button_pressed) Global.config_cache.set_value("tools", "pixel_perfect", button_pressed)

View file

@ -1,4 +1,4 @@
[gd_scene load_steps=25 format=3 uid="uid://wo0hqxkst808"] [gd_scene load_steps=27 format=3 uid="uid://wo0hqxkst808"]
[ext_resource type="Texture2D" uid="uid://cjrokejjsp5dm" path="res://assets/graphics/misc/horizontal_mirror_off.png" id="1"] [ext_resource type="Texture2D" uid="uid://cjrokejjsp5dm" path="res://assets/graphics/misc/horizontal_mirror_off.png" id="1"]
[ext_resource type="Texture2D" uid="uid://hiduvaa73fr6" path="res://assets/graphics/misc/vertical_mirror_off.png" id="2"] [ext_resource type="Texture2D" uid="uid://hiduvaa73fr6" path="res://assets/graphics/misc/vertical_mirror_off.png" id="2"]
@ -6,8 +6,10 @@
[ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="3_faalk"] [ext_resource type="Texture2D" uid="uid://ct8wn8m6x4m54" path="res://assets/graphics/misc/value_arrow.svg" id="3_faalk"]
[ext_resource type="Texture2D" uid="uid://22h12g8p3jtd" path="res://assets/graphics/misc/pixel_perfect_off.png" id="4"] [ext_resource type="Texture2D" uid="uid://22h12g8p3jtd" path="res://assets/graphics/misc/pixel_perfect_off.png" id="4"]
[ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5"] [ext_resource type="Script" path="res://src/UI/Nodes/ValueSlider.gd" id="5"]
[ext_resource type="Texture2D" uid="uid://dlxhm0ronna25" path="res://assets/graphics/misc/xy_mirror_off.png" id="5_hcmgx"]
[ext_resource type="Texture2D" uid="uid://j8eywwy082a4" path="res://assets/graphics/misc/alpha_lock_off.png" id="5_jv20x"] [ext_resource type="Texture2D" uid="uid://j8eywwy082a4" path="res://assets/graphics/misc/alpha_lock_off.png" id="5_jv20x"]
[ext_resource type="Texture2D" uid="uid://dg3dumyfj1682" path="res://assets/graphics/misc/dynamics.png" id="6"] [ext_resource type="Texture2D" uid="uid://dg3dumyfj1682" path="res://assets/graphics/misc/dynamics.png" id="6"]
[ext_resource type="Texture2D" uid="uid://1kj5gcswa3t2" path="res://assets/graphics/misc/x_minus_y_mirror_off.png" id="6_sw8fy"]
[ext_resource type="Texture2D" uid="uid://di8au2u87jgv5" path="res://assets/graphics/misc/uncheck.png" id="7"] [ext_resource type="Texture2D" uid="uid://di8au2u87jgv5" path="res://assets/graphics/misc/uncheck.png" id="7"]
[ext_resource type="Script" path="res://src/UI/GlobalToolOptions/DynamicsPanel.gd" id="7_iqcw1"] [ext_resource type="Script" path="res://src/UI/GlobalToolOptions/DynamicsPanel.gd" id="7_iqcw1"]
[ext_resource type="PackedScene" uid="uid://bmsc0s03pwji4" path="res://src/UI/Nodes/MaxMinEdit.tscn" id="8"] [ext_resource type="PackedScene" uid="uid://bmsc0s03pwji4" path="res://src/UI/Nodes/MaxMinEdit.tscn" id="8"]
@ -179,6 +181,108 @@ grow_vertical = 2
texture = ExtResource("3_faalk") texture = ExtResource("3_faalk")
stretch_mode = 3 stretch_mode = 3
[node name="DiagonalXY" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
visible = false
custom_minimum_size = Vector2(46, 32)
layout_mode = 2
tooltip_text = "Enable vertical mirrored drawing"
mouse_default_cursor_shape = 2
toggle_mode = true
shortcut = SubResource("Shortcut_ai7qc")
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY"]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 5.0
offset_top = -10.0
offset_right = 25.0
offset_bottom = 10.0
grow_vertical = 2
texture = ExtResource("5_hcmgx")
[node name="MirrorOptions" type="MenuButton" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY"]
visible = false
custom_minimum_size = Vector2(20, 0)
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = -20.0
offset_top = -10.0
offset_bottom = 10.0
grow_horizontal = 0
grow_vertical = 2
mouse_default_cursor_shape = 2
item_count = 2
popup/item_0/text = "Move to canvas center"
popup/item_1/text = "Move to view center"
popup/item_1/id = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXY/MirrorOptions"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("3_faalk")
stretch_mode = 3
[node name="DiagonalXMinusY" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
visible = false
custom_minimum_size = Vector2(46, 32)
layout_mode = 2
tooltip_text = "Enable vertical mirrored drawing"
mouse_default_cursor_shape = 2
toggle_mode = true
shortcut = SubResource("Shortcut_ai7qc")
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY"]
layout_mode = 1
anchors_preset = 4
anchor_top = 0.5
anchor_bottom = 0.5
offset_left = 5.0
offset_top = -10.0
offset_right = 25.0
offset_bottom = 10.0
grow_vertical = 2
texture = ExtResource("6_sw8fy")
[node name="MirrorOptions" type="MenuButton" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY"]
visible = false
custom_minimum_size = Vector2(20, 0)
layout_mode = 1
anchors_preset = 6
anchor_left = 1.0
anchor_top = 0.5
anchor_right = 1.0
anchor_bottom = 0.5
offset_left = -20.0
offset_top = -10.0
offset_bottom = 10.0
grow_horizontal = 0
grow_vertical = 2
mouse_default_cursor_shape = 2
item_count = 2
popup/item_0/text = "Move to canvas center"
popup/item_1/text = "Move to view center"
popup/item_1/id = 1
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY/MirrorOptions"]
layout_mode = 1
anchors_preset = 15
anchor_right = 1.0
anchor_bottom = 1.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("3_faalk")
stretch_mode = 3
[node name="PixelPerfect" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]] [node name="PixelPerfect" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
custom_minimum_size = Vector2(32, 32) custom_minimum_size = Vector2(32, 32)
layout_mode = 2 layout_mode = 2
@ -546,6 +650,8 @@ offset_bottom = 23.0
[connection signal="resized" from="." to="." method="_on_resized"] [connection signal="resized" from="." to="." method="_on_resized"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Horizontal" to="." method="_on_Horizontal_toggled"] [connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Horizontal" to="." method="_on_Horizontal_toggled"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Vertical" to="." method="_on_Vertical_toggled"] [connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/Vertical" to="." method="_on_Vertical_toggled"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/DiagonalXY" to="." method="_on_diagonal_xy_toggled"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/DiagonalXMinusY" to="." method="_on_diagonal_x_minus_y_toggled"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/PixelPerfect" to="." method="_on_PixelPerfect_toggled"] [connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/PixelPerfect" to="." method="_on_PixelPerfect_toggled"]
[connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/AlphaLock" to="." method="_on_alpha_lock_toggled"] [connection signal="toggled" from="ScrollContainer/CenterContainer/GridContainer/AlphaLock" to="." method="_on_alpha_lock_toggled"]
[connection signal="pressed" from="ScrollContainer/CenterContainer/GridContainer/Dynamics" to="." method="_on_Dynamics_pressed"] [connection signal="pressed" from="ScrollContainer/CenterContainer/GridContainer/Dynamics" to="." method="_on_Dynamics_pressed"]

View file

@ -55,6 +55,7 @@ class Recorder:
dir.make_dir_recursive(save_directory) dir.make_dir_recursive(save_directory)
project.removed.connect(recorder_panel.finalize_recording.bind(project)) project.removed.connect(recorder_panel.finalize_recording.bind(project))
project.undo_redo.version_changed.connect(capture_frame) project.undo_redo.version_changed.connect(capture_frame)
recorder_panel.captured_label.text = ""
func _notification(what: int) -> void: func _notification(what: int) -> void:
if what == NOTIFICATION_PREDELETE: if what == NOTIFICATION_PREDELETE:
@ -100,6 +101,9 @@ func _on_project_switched() -> void:
initialize_recording() initialize_recording()
start_button.set_pressed_no_signal(true) start_button.set_pressed_no_signal(true)
Global.change_button_texturerect(start_button.get_child(0), "stop.png") Global.change_button_texturerect(start_button.get_child(0), "stop.png")
captured_label.text = str(
"Saved: ", recorded_projects[Global.current_project].frames_captured
)
else: else:
finalize_recording() finalize_recording()
start_button.set_pressed_no_signal(false) start_button.set_pressed_no_signal(false)

View file

@ -40,15 +40,18 @@ mouse_default_cursor_shape = 2
toggle_mode = true toggle_mode = true
[node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/Start"] [node name="TextureRect" type="TextureRect" parent="ScrollContainer/CenterContainer/GridContainer/Start"]
layout_mode = 0 layout_mode = 1
anchors_preset = 8
anchor_left = 0.5 anchor_left = 0.5
anchor_top = 0.5 anchor_top = 0.5
anchor_right = 0.5 anchor_right = 0.5
anchor_bottom = 0.5 anchor_bottom = 0.5
offset_left = -10.0 offset_left = -11.0
offset_top = -10.5 offset_top = -11.0
offset_right = 10.0 offset_right = 11.0
offset_bottom = 10.5 offset_bottom = 11.0
grow_horizontal = 2
grow_vertical = 2
texture = ExtResource("1") texture = ExtResource("1")
expand_mode = 1 expand_mode = 1
stretch_mode = 5 stretch_mode = 5
@ -74,7 +77,7 @@ offset_bottom = 10.5
texture = ExtResource("3") texture = ExtResource("3")
stretch_mode = 5 stretch_mode = 5
[node name="OpenFolder" type="Button" parent="ScrollContainer/CenterContainer/GridContainer"] [node name="OpenFolder" type="Button" parent="ScrollContainer/CenterContainer/GridContainer" groups=["UIButtons"]]
custom_minimum_size = Vector2(32, 32) custom_minimum_size = Vector2(32, 32)
layout_mode = 2 layout_mode = 2
tooltip_text = "Open Folder" tooltip_text = "Open Folder"

View file

@ -140,8 +140,10 @@ func _input(event: InputEvent) -> void:
var timeline_rect := Rect2(global_position, size) var timeline_rect := Rect2(global_position, size)
if timeline_rect.has_point(mouse_pos): if timeline_rect.has_point(mouse_pos):
if Input.is_key_pressed(KEY_CTRL): if Input.is_key_pressed(KEY_CTRL):
cel_size += (2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out"))) var zoom := 2 * int(event.is_action("zoom_in")) - 2 * int(event.is_action("zoom_out"))
get_viewport().set_input_as_handled() cel_size += zoom
if zoom != 0:
get_viewport().set_input_as_handled()
func reset_settings() -> void: func reset_settings() -> void:
@ -283,6 +285,7 @@ func _on_blend_modes_item_selected(index: int) -> void:
project.undo_redo.add_undo_method(_update_layer_ui) project.undo_redo.add_undo_method(_update_layer_ui)
project.undo_redo.add_undo_method(_update_layers) project.undo_redo.add_undo_method(_update_layers)
project.undo_redo.commit_action() project.undo_redo.commit_action()
SteamManager.set_achievement("ACH_BLEND_IN")
func _update_layers() -> void: func _update_layers() -> void:
@ -841,6 +844,7 @@ func add_layer(type := 0) -> void:
l = PixelLayer.new(project) l = PixelLayer.new(project)
Global.LayerTypes.GROUP: Global.LayerTypes.GROUP:
l = GroupLayer.new(project) l = GroupLayer.new(project)
SteamManager.set_achievement("ACH_STRONGER_TOGETHER")
Global.LayerTypes.THREE_D: Global.LayerTypes.THREE_D:
l = Layer3D.new(project) l = Layer3D.new(project)
SteamManager.set_achievement("ACH_3D_LAYER") SteamManager.set_achievement("ACH_3D_LAYER")

View file

@ -421,7 +421,6 @@ func _setup_color_mode_submenu(item: String) -> void:
color_mode_submenu.add_radio_check_item("RGBA", ColorModes.RGBA) color_mode_submenu.add_radio_check_item("RGBA", ColorModes.RGBA)
color_mode_submenu.set_item_checked(ColorModes.RGBA, true) color_mode_submenu.set_item_checked(ColorModes.RGBA, true)
color_mode_submenu.add_radio_check_item("Indexed", ColorModes.INDEXED) color_mode_submenu.add_radio_check_item("Indexed", ColorModes.INDEXED)
color_mode_submenu.hide_on_checkable_item_selection = false
color_mode_submenu.id_pressed.connect(_color_mode_submenu_id_pressed) color_mode_submenu.id_pressed.connect(_color_mode_submenu_id_pressed)
image_menu.add_child(color_mode_submenu) image_menu.add_child(color_mode_submenu)
@ -838,7 +837,7 @@ func _toggle_show_guides() -> void:
elif guide.type == Guide.Types.VERTICAL: elif guide.type == Guide.Types.VERTICAL:
guide.visible = Global.show_y_symmetry_axis and Global.show_guides guide.visible = Global.show_y_symmetry_axis and Global.show_guides
elif guide.type == Guide.Types.XY: elif guide.type == Guide.Types.XY:
guide.visible = Global.show_x_y_symmetry_axis and Global.show_guides guide.visible = Global.show_xy_symmetry_axis and Global.show_guides
elif guide.type == Guide.Types.X_MINUS_Y: elif guide.type == Guide.Types.X_MINUS_Y:
guide.visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides guide.visible = Global.show_x_minus_y_symmetry_axis and Global.show_guides