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

Replaced the _min and _max Project variables with Project.selected_pixels

This will allow us to create more selection tools in the future, that aren't necessarily rectangular (See #129) and even enhance the current rectangle selection tool (See #56)

Current issues spotted so far:
Drawing is slower for large images, and bucket filling is also considerably slower even on a 64x64 image. Optimizations are required.
This commit is contained in:
OverloadedOrama 2020-07-20 22:15:34 +03:00
parent 8c965c1858
commit 0f82be765e
10 changed files with 108 additions and 80 deletions

View file

@ -455,51 +455,44 @@ func generate_outline(image : Image, outline_color : Color, thickness : int, dia
func adjust_hsv(img: Image, id : int, delta : float) -> void:
var x_min = Global.current_project.x_min
var x_max = Global.current_project.x_max
var y_min = Global.current_project.y_min
var y_max = Global.current_project.y_max
img.lock()
match id:
0: # Hue
for i in range(x_min, x_max):
for j in range(y_min, y_max):
var c : Color = img.get_pixel(i,j)
var hue = range_lerp(c.h,0,1,-180,180)
hue = hue + delta
for i in Global.current_project.selected_pixels:
var c : Color = img.get_pixelv(i)
var hue = range_lerp(c.h,0,1,-180,180)
hue = hue + delta
while(hue >= 180):
hue -= 360
while(hue < -180):
hue += 360
c.h = range_lerp(hue,-180,180,0,1)
img.set_pixel(i,j,c)
while(hue >= 180):
hue -= 360
while(hue < -180):
hue += 360
c.h = range_lerp(hue,-180,180,0,1)
img.set_pixelv(i,c)
1: # Saturation
for i in range(x_min, x_max):
for j in range(y_min, y_max):
var c : Color = img.get_pixel(i,j)
var sat = c.s
if delta > 0:
sat = range_lerp(delta,0,100,c.s,1)
elif delta < 0:
sat = range_lerp(delta,-100,0,0,c.s)
c.s = sat
img.set_pixel(i,j,c)
for i in Global.current_project.selected_pixels:
var c : Color = img.get_pixelv(i)
var sat = c.s
if delta > 0:
sat = range_lerp(delta,0,100,c.s,1)
elif delta < 0:
sat = range_lerp(delta,-100,0,0,c.s)
c.s = sat
img.set_pixelv(i,c)
2: # Value
for i in range(x_min, x_max):
for j in range(y_min, y_max):
var c : Color = img.get_pixel(i,j)
var val = c.v
if delta > 0:
val = range_lerp(delta,0,100,c.v,1)
elif delta < 0:
val = range_lerp(delta,-100,0,0,c.v)
for i in Global.current_project.selected_pixels:
var c : Color = img.get_pixelv(i)
var val = c.v
if delta > 0:
val = range_lerp(delta,0,100,c.v,1)
elif delta < 0:
val = range_lerp(delta,-100,0,0,c.v)
c.v = val
img.set_pixel(i,j,c)
c.v = val
img.set_pixelv(i,c)
img.unlock()

View file

@ -322,10 +322,9 @@ func save_pxo_file(path : String, autosave : bool, use_zstd_compression := true,
func open_image_as_new_tab(path : String, image : Image) -> void:
var project = Project.new([], path.get_file())
var project = Project.new([], path.get_file(), image.get_size())
project.layers.append(Layer.new())
Global.projects.append(project)
project.size = image.get_size()
var frame := Frame.new()
image.convert(Image.FORMAT_RGBA8)

View file

@ -68,15 +68,6 @@ func _input(event : InputEvent) -> void:
sprite_changed_this_frame = false
var current_project : Project = Global.current_project
current_project.x_min = location.x
current_project.x_max = location.x + current_project.size.x
current_project.y_min = location.y
current_project.y_max = location.y + current_project.size.y
if not current_project.selected_rect.has_no_area():
current_project.x_min = max(current_project.x_min, current_project.selected_rect.position.x)
current_project.x_max = min(current_project.x_max, current_project.selected_rect.end.x)
current_project.y_min = max(current_project.y_min, current_project.selected_rect.position.y)
current_project.y_max = min(current_project.y_max, current_project.selected_rect.end.y)
if Global.has_focus:
if !cursor_image_has_changed:

View file

@ -71,8 +71,14 @@ func set_pixel(image: Image, position: Vector2, color: Color) -> void:
var mirror_x = project.x_symmetry_point - position.x
var mirror_y = project.y_symmetry_point - position.y
var mirror_x_inside : bool = mirror_x >= project.x_min and mirror_x <= project.x_max - 1
var mirror_y_inside : bool = mirror_y >= project.y_min and mirror_y <= project.y_max - 1
var selected_pixels_x := []
var selected_pixels_y := []
for i in project.selected_pixels:
selected_pixels_x.append(i.x)
selected_pixels_y.append(i.y)
var mirror_x_inside : bool = mirror_x in selected_pixels_x
var mirror_y_inside : bool = mirror_y in selected_pixels_y
drawers[0].set_pixel(image, position, color, color_op)
if horizontal_mirror and mirror_x_inside:

View file

@ -3,7 +3,7 @@ class_name Project extends Reference
var name := "" setget name_changed
var size := Vector2(64, 64)
var size : Vector2 setget size_changed
var undo_redo : UndoRedo
var undos := 0 # The number of times we added undo properties
var has_changed := false setget has_changed_changed
@ -16,15 +16,12 @@ var guides := [] # Array of Guides
var brushes := [] # Array of Images
var x_symmetry_point := size.x / 2 + 1
var y_symmetry_point := size.y / 2 + 1
var x_symmetry_point
var y_symmetry_point
var x_symmetry_axis : SymmetryGuide
var y_symmetry_axis : SymmetryGuide
var x_min := 0
var x_max := 64
var y_min := 0
var y_max := 64
var selected_pixels := []
var selected_rect := Rect2(0, 0, 0, 0) setget _set_selected_rect
# For every camera (currently there are 3)
@ -32,17 +29,21 @@ var cameras_zoom := [Vector2(0.15, 0.15), Vector2(0.15, 0.15), Vector2(0.15, 0.1
var cameras_offset := [Vector2.ZERO, Vector2.ZERO, Vector2.ZERO] # Array of Vector2
func _init(_frames := [], _name := tr("untitled")) -> void:
func _init(_frames := [], _name := tr("untitled"), _size := Vector2(64, 64)) -> void:
frames = _frames
name = _name
x_max = size.x
y_max = size.y
size = _size
select_all_pixels()
undo_redo = UndoRedo.new()
Global.tabs.add_tab(name)
OpenSave.current_save_paths.append("")
OpenSave.backup_save_paths.append("")
x_symmetry_point = size.x / 2 + 1
y_symmetry_point = size.y / 2 + 1
if !x_symmetry_axis:
x_symmetry_axis = SymmetryGuide.new()
x_symmetry_axis.type = x_symmetry_axis.Types.HORIZONTAL
@ -60,6 +61,17 @@ func _init(_frames := [], _name := tr("untitled")) -> void:
Global.canvas.add_child(y_symmetry_axis)
func select_all_pixels() -> void:
clear_selection()
for x in size.x:
for y in size.y:
selected_pixels.append(Vector2(x, y))
func clear_selection() -> void:
selected_pixels.clear()
func _set_selected_rect(value : Rect2) -> void:
selected_rect = value
Global.selection_rectangle.set_rect(value)
@ -290,6 +302,12 @@ func name_changed(value : String) -> void:
Global.tabs.set_tab_title(Global.tabs.current_tab, name)
func size_changed(value : Vector2) -> void:
size = value
if Global.selection_rectangle._selected_rect.has_no_area():
select_all_pixels()
func frames_changed(value : Array) -> void:
frames = value
remove_cel_buttons()

View file

@ -28,6 +28,7 @@ func has_point(position : Vector2) -> bool:
func get_rect() -> Rect2:
return _selected_rect
func set_rect(rect : Rect2) -> void:
_selected_rect = rect
polygon[0] = rect.position
@ -36,6 +37,19 @@ func set_rect(rect : Rect2) -> void:
polygon[3] = Vector2(rect.position.x, rect.end.y)
visible = not rect.has_no_area()
var project : Project = Global.current_project
if rect.has_no_area():
project.select_all_pixels()
else:
project.clear_selection()
for x in range(rect.position.x, rect.end.x):
for y in range(rect.position.y, rect.end.y):
if x < 0 or x >= project.size.x:
continue
if y < 0 or y >= project.size.y:
continue
project.selected_pixels.append(Vector2(x, y))
func move_rect(move : Vector2) -> void:
_selected_rect.position += move

View file

@ -77,11 +77,8 @@ func draw_indicator() -> void:
func _get_draw_rect() -> Rect2:
var x_min : int = Global.current_project.x_min
var x_max : int = Global.current_project.x_max
var y_min : int = Global.current_project.y_min
var y_max : int = Global.current_project.y_max
return Rect2(x_min, y_min, x_max - x_min, y_max - y_min)
var selected_pixels = Global.current_project.selected_pixels
return Rect2(selected_pixels[0].x, selected_pixels[0].y, selected_pixels[-1].x - selected_pixels[0].x + 1, selected_pixels[-1].y - selected_pixels[0].y + 1)
func _get_tile_mode_rect() -> Rect2:

View file

@ -94,7 +94,7 @@ func update_pattern() -> void:
func draw_start(position : Vector2) -> void:
if not _get_draw_rect().has_point(position):
if not position in Global.current_project.selected_pixels:
return
var undo_data = _get_undo_data()
if _fill_area == 0:
@ -121,18 +121,23 @@ func fill_in_color(position : Vector2) -> void:
return
image.lock()
for y in range(project.y_min, project.y_max):
for x in range(project.x_min, project.x_max):
if image.get_pixel(x, y).is_equal_approx(color):
_set_pixel(image, x, y, tool_slot.color)
for i in project.selected_pixels:
if image.get_pixelv(i).is_equal_approx(color):
_set_pixel(image, i.x, i.y, tool_slot.color)
func fill_in_area(position : Vector2) -> void:
var project : Project = Global.current_project
var mirror_x = project.x_symmetry_point - position.x
var mirror_y = project.y_symmetry_point - position.y
var mirror_x_inside : bool = mirror_x >= project.x_min and mirror_x <= project.x_max - 1
var mirror_y_inside : bool = mirror_y >= project.y_min and mirror_y <= project.y_max - 1
var selected_pixels_x := []
var selected_pixels_y := []
for i in project.selected_pixels:
selected_pixels_x.append(i.x)
selected_pixels_y.append(i.y)
var mirror_x_inside : bool = mirror_x in selected_pixels_x
var mirror_y_inside : bool = mirror_y in selected_pixels_y
_flood_fill(position)
if tool_slot.horizontal_mirror and mirror_x_inside:
@ -160,9 +165,9 @@ func _flood_fill(position : Vector2) -> void:
continue
var west : Vector2 = n
var east : Vector2 = n
while west.x >= project.x_min && image.get_pixelv(west).is_equal_approx(color):
while west in project.selected_pixels && image.get_pixelv(west).is_equal_approx(color):
west += Vector2.LEFT
while east.x < project.x_max && image.get_pixelv(east).is_equal_approx(color):
while east in project.selected_pixels && image.get_pixelv(east).is_equal_approx(color):
east += Vector2.RIGHT
for px in range(west.x + 1, east.x):
var p := Vector2(px, n.y)
@ -170,9 +175,9 @@ func _flood_fill(position : Vector2) -> void:
processed.set_bit(p, true)
var north := p + Vector2.UP
var south := p + Vector2.DOWN
if north.y >= project.y_min && image.get_pixelv(north).is_equal_approx(color):
if north in project.selected_pixels && image.get_pixelv(north).is_equal_approx(color):
q.append(north)
if south.y < project.y_max && image.get_pixelv(south).is_equal_approx(color):
if south in project.selected_pixels && image.get_pixelv(south).is_equal_approx(color):
q.append(south)

View file

@ -271,8 +271,14 @@ func draw_tool_brush(position : Vector2) -> void:
var project : Project = Global.current_project
var mirror_x = (project.x_symmetry_point + 1) - dst.x - src_rect.size.x
var mirror_y = (project.y_symmetry_point + 1) - dst.y - src_rect.size.y
var mirror_x_inside : bool = mirror_x >= project.x_min and mirror_x <= project.x_max - 1
var mirror_y_inside : bool = mirror_y >= project.y_min and mirror_y <= project.y_max - 1
var selected_pixels_x := []
var selected_pixels_y := []
for i in project.selected_pixels:
selected_pixels_x.append(i.x)
selected_pixels_y.append(i.y)
var mirror_x_inside : bool = mirror_x in selected_pixels_x
var mirror_y_inside : bool = mirror_y in selected_pixels_y
_draw_brush_image(_brush_image, src_rect, dst)
if tool_slot.horizontal_mirror and mirror_x_inside:
@ -287,7 +293,7 @@ func draw_indicator() -> void:
draw_indicator_at(_cursor, Vector2.ZERO, Color.blue)
if Global.tile_mode and _get_tile_mode_rect().has_point(_cursor):
var tile := _line_start if _draw_line else _cursor
if not _get_draw_rect().has_point(tile):
if not tile in Global.current_project.selected_pixels:
var offset := tile - tile.posmodv(Global.current_project.size)
draw_indicator_at(_cursor, offset, Color.green)
@ -316,7 +322,7 @@ func _set_pixel(position : Vector2) -> void:
if Global.tile_mode and _get_tile_mode_rect().has_point(position):
position = position.posmodv(Global.current_project.size)
if not _get_draw_rect().has_point(position):
if not position in Global.current_project.selected_pixels:
return
var image := _get_draw_image()

View file

@ -80,11 +80,10 @@ func _on_CreateNewImage_confirmed() -> void:
Global.canvas.fill_color = fill_color
var frame : Frame = Global.canvas.new_empty_frame(false, true, Vector2(width, height))
var new_project := Project.new([frame])
var new_project := Project.new([frame], tr("untitled"), Vector2(width, height).floor())
new_project.layers.append(Layer.new())
Global.projects.append(new_project)
Global.tabs.current_tab = Global.tabs.get_tab_count() - 1
Global.current_project.size = Vector2(width, height).floor()
Global.canvas.camera_zoom()