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

Format code and add static checks (#599)

* gdformat .

* Lint code - Part 1

* Format code - Part 2

* Lint code - Part 2

Trying to fix the max allowed line length errors

* Add normal_map_invert_y to the image .import files

Because of Godot 3.4

* Do not call private methods outside of the script's scope

Lint code - Part 3

* Format code - Part 3

* Fixed more line length exceeded errors - Lint code Part 3

* Export array of licenses - Lint code part 4

* Clean hint_tooltip code from Global

Removes a lot of lines of code

* Create static-checks.yml

* Fix FreeType's license
This commit is contained in:
Manolis Papadeas 2021-11-25 14:48:30 +02:00 committed by GitHub
parent 41b5db4622
commit c6b9a1fb82
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
201 changed files with 4767 additions and 3096 deletions

24
.github/workflows/static-checks.yml vendored Normal file
View file

@ -0,0 +1,24 @@
name: Static Checks 📊
on:
push:
branches-ignore:
- gh-pages
- l10n_master
pull_request:
paths:
- "addons/*"
- "src/*"
jobs:
format:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: pip3 install gdtoolkit
- run: gdformat --diff .
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- run: pip3 install gdtoolkit
- run: gdlint .

View file

@ -1,6 +1,5 @@
extends Reference extends Reference
var _shader: Shader var _shader: Shader
@ -29,7 +28,9 @@ func _convert(image: Image, colors: Array) -> PoolByteArray:
VisualServer.canvas_item_set_parent(ci_rid, canvas) VisualServer.canvas_item_set_parent(ci_rid, canvas)
var texture = ImageTexture.new() var texture = ImageTexture.new()
texture.create_from_image(image) texture.create_from_image(image)
VisualServer.canvas_item_add_texture_rect(ci_rid, Rect2(Vector2(0, 0), image.get_size()), texture) VisualServer.canvas_item_add_texture_rect(
ci_rid, Rect2(Vector2(0, 0), image.get_size()), texture
)
var mat_rid = VisualServer.material_create() var mat_rid = VisualServer.material_create()
VisualServer.material_set_shader(mat_rid, _shader.get_rid()) VisualServer.material_set_shader(mat_rid, _shader.get_rid())

View file

@ -1,15 +1,9 @@
extends Reference extends Reference
enum Error { OK = 0, EMPTY_IMAGE = 1, BAD_IMAGE_FORMAT = 2 }
enum Error { var little_endian = preload("./little_endian.gd").new()
OK = 0, var lzw = preload("./gif-lzw/lzw.gd").new()
EMPTY_IMAGE = 1,
BAD_IMAGE_FORMAT = 2
}
var little_endian = preload('./little_endian.gd').new()
var lzw = preload('./gif-lzw/lzw.gd').new()
var converter = preload("./converter.gd") var converter = preload("./converter.gd")
var last_color_table := [] var last_color_table := []
@ -24,11 +18,14 @@ func _init(_width: int, _height: int):
add_logical_screen_descriptor(_width, _height) add_logical_screen_descriptor(_width, _height)
add_application_ext("NETSCAPE", "2.0", [1, 0, 0]) add_application_ext("NETSCAPE", "2.0", [1, 0, 0])
func export_file_data() -> PoolByteArray: func export_file_data() -> PoolByteArray:
return data + PoolByteArray([0x3b]) return data + PoolByteArray([0x3b])
func add_header() -> void: func add_header() -> void:
data += 'GIF'.to_ascii() + '89a'.to_ascii() data += "GIF".to_ascii() + "89a".to_ascii()
func add_logical_screen_descriptor(width: int, height: int) -> void: func add_logical_screen_descriptor(width: int, height: int) -> void:
# not Global Color Table Flag # not Global Color Table Flag
@ -46,6 +43,7 @@ func add_logical_screen_descriptor(width: int, height: int) -> void:
data.append(background_color_index) data.append(background_color_index)
data.append(pixel_aspect_ratio) data.append(pixel_aspect_ratio)
func add_application_ext(app_iden: String, app_auth_code: String, _data: Array) -> void: func add_application_ext(app_iden: String, app_auth_code: String, _data: Array) -> void:
var extension_introducer := 0x21 var extension_introducer := 0x21
var extension_label := 0xff var extension_label := 0xff
@ -61,6 +59,7 @@ func add_application_ext(app_iden: String, app_auth_code: String, _data: Array)
data += PoolByteArray(_data) data += PoolByteArray(_data)
data.append(0) data.append(0)
# finds the image color table. Stops if the size gets larger than 256. # finds the image color table. Stops if the size gets larger than 256.
func find_color_table(image: Image) -> Dictionary: func find_color_table(image: Image) -> Dictionary:
image.lock() image.lock()
@ -72,7 +71,8 @@ func find_color_table(image: Image) -> Dictionary:
int(image_data[i]), int(image_data[i]),
int(image_data[i + 1]), int(image_data[i + 1]),
int(image_data[i + 2]), int(image_data[i + 2]),
int(image_data[i + 3])] int(image_data[i + 3])
]
if not color in result: if not color in result:
result[color] = result.size() result[color] = result.size()
if result.size() > 256: if result.size() > 256:
@ -81,25 +81,21 @@ func find_color_table(image: Image) -> Dictionary:
image.unlock() image.unlock()
return result return result
func find_transparency_color_index(color_table: Dictionary) -> int: func find_transparency_color_index(color_table: Dictionary) -> int:
for color in color_table: for color in color_table:
if color[3] == 0: if color[3] == 0:
return color_table[color] return color_table[color]
return -1 return -1
func change_colors_to_codes(image: Image,
color_palette: Dictionary, func change_colors_to_codes(image: Image, color_palette: Dictionary, transparency_color_index: int) -> PoolByteArray:
transparency_color_index: int) -> PoolByteArray:
image.lock() image.lock()
var image_data: PoolByteArray = image.get_data() var image_data: PoolByteArray = image.get_data()
var result: PoolByteArray = PoolByteArray([]) var result: PoolByteArray = PoolByteArray([])
for i in range(0, image_data.size(), 4): for i in range(0, image_data.size(), 4):
var color: Array = [ var color: Array = [image_data[i], image_data[i + 1], image_data[i + 2], image_data[i + 3]]
image_data[i],
image_data[i + 1],
image_data[i + 2],
image_data[i + 3]]
if color in color_palette: if color in color_palette:
if color[3] == 0 and transparency_color_index != -1: if color[3] == 0 and transparency_color_index != -1:
@ -108,11 +104,12 @@ func change_colors_to_codes(image: Image,
result.append(color_palette[color]) result.append(color_palette[color])
else: else:
result.append(0) result.append(0)
push_warning('change_colors_to_codes: color not found! [%d, %d, %d, %d]' % color) push_warning("change_colors_to_codes: color not found! [%d, %d, %d, %d]" % color)
image.unlock() image.unlock()
return result return result
# makes sure that the color table is at least size 4. # makes sure that the color table is at least size 4.
func make_proper_size(color_table: Array) -> Array: func make_proper_size(color_table: Array) -> Array:
var result := [] + color_table var result := [] + color_table
@ -121,15 +118,18 @@ func make_proper_size(color_table: Array) -> Array:
result.append([0, 0, 0, 0]) result.append([0, 0, 0, 0])
return result return result
func calc_delay_time(frame_delay: float) -> int: func calc_delay_time(frame_delay: float) -> int:
return int(ceil(frame_delay / 0.01)) return int(ceil(frame_delay / 0.01))
func color_table_to_indexes(colors: Array) -> PoolByteArray: func color_table_to_indexes(colors: Array) -> PoolByteArray:
var result: PoolByteArray = PoolByteArray([]) var result: PoolByteArray = PoolByteArray([])
for i in range(colors.size()): for i in range(colors.size()):
result.append(i) result.append(i)
return result return result
func add_frame(image: Image, frame_delay: float, quantizator: Script) -> int: func add_frame(image: Image, frame_delay: float, quantizator: Script) -> int:
# check if image is of good format # check if image is of good format
if image.get_format() != Image.FORMAT_RGBA8: if image.get_format() != Image.FORMAT_RGBA8:
@ -144,7 +144,7 @@ func add_frame(image: Image, frame_delay: float, quantizator: Script) -> int:
var image_converted_to_codes: PoolByteArray var image_converted_to_codes: PoolByteArray
var transparency_color_index: int = -1 var transparency_color_index: int = -1
var color_table: Array var color_table: Array
if found_color_table.size() <= 256: # we don't need to quantize the image. if found_color_table.size() <= 256: # we don't need to quantize the image.
# try to find transparency color index. # try to find transparency color index.
transparency_color_index = find_transparency_color_index(found_color_table) transparency_color_index = find_transparency_color_index(found_color_table)
# if didn't found transparency color index but there is atleast one # if didn't found transparency color index but there is atleast one
@ -153,9 +153,10 @@ func add_frame(image: Image, frame_delay: float, quantizator: Script) -> int:
found_color_table[[0, 0, 0, 0]] = found_color_table.size() found_color_table[[0, 0, 0, 0]] = found_color_table.size()
transparency_color_index = found_color_table.size() - 1 transparency_color_index = found_color_table.size() - 1
image_converted_to_codes = change_colors_to_codes( image_converted_to_codes = change_colors_to_codes(
image, found_color_table, transparency_color_index) image, found_color_table, transparency_color_index
)
color_table = make_proper_size(found_color_table.keys()) color_table = make_proper_size(found_color_table.keys())
else: # we have to quantize the image. else: # we have to quantize the image.
var quantization_result: Array = quantizator.new().quantize(image) var quantization_result: Array = quantizator.new().quantize(image)
image_converted_to_codes = quantization_result[0] image_converted_to_codes = quantization_result[0]
color_table = quantization_result[1] color_table = quantization_result[1]
@ -169,21 +170,19 @@ func add_frame(image: Image, frame_delay: float, quantizator: Script) -> int:
var color_table_indexes := color_table_to_indexes(color_table) var color_table_indexes := color_table_to_indexes(color_table)
var compressed_image_result: Array = lzw.compress_lzw( var compressed_image_result: Array = lzw.compress_lzw(
image_converted_to_codes, image_converted_to_codes, color_table_indexes
color_table_indexes) )
var compressed_image_data: PoolByteArray = compressed_image_result[0] var compressed_image_data: PoolByteArray = compressed_image_result[0]
var lzw_min_code_size: int = compressed_image_result[1] var lzw_min_code_size: int = compressed_image_result[1]
add_graphic_constrol_ext(delay_time, transparency_color_index) add_graphic_constrol_ext(delay_time, transparency_color_index)
add_image_descriptor( add_image_descriptor(Vector2.ZERO, image.get_size(), color_table_bit_size(color_table))
Vector2.ZERO,
image.get_size(),
color_table_bit_size(color_table))
add_local_color_table(color_table) add_local_color_table(color_table)
add_image_data_block(lzw_min_code_size, compressed_image_data) add_image_data_block(lzw_min_code_size, compressed_image_data)
return Error.OK return Error.OK
# adds frame with last color informations # adds frame with last color informations
func add_frame_with_lci(image: Image, frame_delay: float) -> int: func add_frame_with_lci(image: Image, frame_delay: float) -> int:
# check if image is of good format # check if image is of good format
@ -194,27 +193,27 @@ func add_frame_with_lci(image: Image, frame_delay: float) -> int:
if image.is_empty(): if image.is_empty():
return Error.EMPTY_IMAGE return Error.EMPTY_IMAGE
var image_converted_to_codes: PoolByteArray = converter.new().get_similar_indexed_datas(image, last_color_table) var image_converted_to_codes: PoolByteArray = converter.new().get_similar_indexed_datas(
image, last_color_table
)
var color_table_indexes := color_table_to_indexes(last_color_table) var color_table_indexes := color_table_to_indexes(last_color_table)
var compressed_image_result: Array = lzw.compress_lzw( var compressed_image_result: Array = lzw.compress_lzw(
image_converted_to_codes, image_converted_to_codes, color_table_indexes
color_table_indexes) )
var compressed_image_data: PoolByteArray = compressed_image_result[0] var compressed_image_data: PoolByteArray = compressed_image_result[0]
var lzw_min_code_size: int = compressed_image_result[1] var lzw_min_code_size: int = compressed_image_result[1]
var delay_time := calc_delay_time(frame_delay) var delay_time := calc_delay_time(frame_delay)
add_graphic_constrol_ext(delay_time, last_transparency_index) add_graphic_constrol_ext(delay_time, last_transparency_index)
add_image_descriptor( add_image_descriptor(Vector2.ZERO, image.get_size(), color_table_bit_size(last_color_table))
Vector2.ZERO,
image.get_size(),
color_table_bit_size(last_color_table))
add_local_color_table(last_color_table) add_local_color_table(last_color_table)
add_image_data_block(lzw_min_code_size, compressed_image_data) add_image_data_block(lzw_min_code_size, compressed_image_data)
return Error.OK return Error.OK
func add_graphic_constrol_ext(_delay_time: float, tci: int = -1) -> void: func add_graphic_constrol_ext(_delay_time: float, tci: int = -1) -> void:
var extension_introducer: int = 0x21 var extension_introducer: int = 0x21
var graphic_control_label: int = 0xf9 var graphic_control_label: int = 0xf9
@ -237,27 +236,26 @@ func add_graphic_constrol_ext(_delay_time: float, tci: int = -1) -> void:
data.append(0) data.append(0)
func add_image_descriptor(pos: Vector2,
size: Vector2, func add_image_descriptor(pos: Vector2, size: Vector2, l_color_table_size: int) -> void:
l_color_table_size: int) -> void:
var image_separator: int = 0x2c var image_separator: int = 0x2c
var packed_fields: int = 0b10000000 | (0b111 & l_color_table_size) var packed_fields: int = 0b10000000 | (0b111 & l_color_table_size)
var little_endian = preload('./little_endian.gd').new()
data.append(image_separator) data.append(image_separator)
data += little_endian.int_to_2bytes(int(pos.x)) # left pos data += little_endian.int_to_2bytes(int(pos.x)) # left pos
data += little_endian.int_to_2bytes(int(pos.y)) # top pos data += little_endian.int_to_2bytes(int(pos.y)) # top pos
data += little_endian.int_to_2bytes(int(size.x)) # width data += little_endian.int_to_2bytes(int(size.x)) # width
data += little_endian.int_to_2bytes(int(size.y)) # height data += little_endian.int_to_2bytes(int(size.y)) # height
data.append(packed_fields) data.append(packed_fields)
func color_table_bit_size(color_table: Array) -> int: func color_table_bit_size(color_table: Array) -> int:
if color_table.size() <= 1: if color_table.size() <= 1:
return 0 return 0
var bit_size := int(ceil(log(color_table.size()) / log(2.0))) var bit_size := int(ceil(log(color_table.size()) / log(2.0)))
return bit_size - 1 return bit_size - 1
func add_local_color_table(color_table: Array) -> void: func add_local_color_table(color_table: Array) -> void:
for color in color_table: for color in color_table:
data.append(color[0]) data.append(color[0])
@ -271,6 +269,7 @@ func add_local_color_table(color_table: Array) -> void:
for i in range(proper_size - color_table.size()): for i in range(proper_size - color_table.size()):
data += PoolByteArray([0, 0, 0]) data += PoolByteArray([0, 0, 0])
func add_image_data_block(lzw_min_code_size: int, _data: PoolByteArray) -> void: func add_image_data_block(lzw_min_code_size: int, _data: PoolByteArray) -> void:
data.append(lzw_min_code_size) data.append(lzw_min_code_size)

View file

@ -1,7 +1,7 @@
extends Reference extends Reference
class LSB_LZWBitPacker: class LSBLZWBitPacker:
var bit_index: int = 0 var bit_index: int = 0
var stream: int = 0 var stream: int = 0

View file

@ -1,7 +1,7 @@
extends Reference extends Reference
class LSB_LZWBitUnpacker: class LSBLZWBitUnpacker:
var chunk_stream: PoolByteArray var chunk_stream: PoolByteArray
var bit_index: int = 0 var bit_index: int = 0
var byte: int var byte: int

View file

@ -1,8 +1,8 @@
extends Reference extends Reference
var lsbbitpacker = preload("./lsbbitpacker.gd")
var lsbbitunpacker = preload("./lsbbitunpacker.gd")
var lsbbitpacker = preload('./lsbbitpacker.gd')
var lsbbitunpacker = preload('./lsbbitunpacker.gd')
class CodeEntry: class CodeEntry:
var sequence: PoolByteArray var sequence: PoolByteArray
@ -16,11 +16,12 @@ class CodeEntry:
return CodeEntry.new(self.raw_array + other.raw_array) return CodeEntry.new(self.raw_array + other.raw_array)
func to_string(): func to_string():
var result: String = '' var result: String = ""
for element in self.sequence: for element in self.sequence:
result += str(element) + ', ' result += str(element) + ", "
return result.substr(0, result.length() - 2) return result.substr(0, result.length() - 2)
class CodeTable: class CodeTable:
var entries: Dictionary = {} var entries: Dictionary = {}
var counter: int = 0 var counter: int = 0
@ -42,20 +43,23 @@ class CodeTable:
return self.entries.get(index, null) return self.entries.get(index, null)
func to_string() -> String: func to_string() -> String:
var result: String = 'CodeTable:\n' var result: String = "CodeTable:\n"
for id in self.entries: for id in self.entries:
result += str(id) + ': ' + self.entries[id].to_string() + '\n' result += str(id) + ": " + self.entries[id].to_string() + "\n"
result += 'Counter: ' + str(self.counter) + '\n' result += "Counter: " + str(self.counter) + "\n"
return result return result
func log2(value: float) -> float: func log2(value: float) -> float:
return log(value) / log(2.0) return log(value) / log(2.0)
func get_bits_number_for(value: int) -> int: func get_bits_number_for(value: int) -> int:
if value == 0: if value == 0:
return 1 return 1
return int(ceil(log2(value + 1))) return int(ceil(log2(value + 1)))
func initialize_color_code_table(colors: PoolByteArray) -> CodeTable: func initialize_color_code_table(colors: PoolByteArray) -> CodeTable:
var result_code_table: CodeTable = CodeTable.new() var result_code_table: CodeTable = CodeTable.new()
for color_id in colors: for color_id in colors:
@ -67,9 +71,11 @@ func initialize_color_code_table(colors: PoolByteArray) -> CodeTable:
result_code_table.counter = clear_code_index + 2 result_code_table.counter = clear_code_index + 2
return result_code_table return result_code_table
# compression and decompression done with source: # compression and decompression done with source:
# http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp # http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp
func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array: func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array:
# Initialize code table # Initialize code table
var code_table: CodeTable = initialize_color_code_table(colors) var code_table: CodeTable = initialize_color_code_table(colors)
@ -83,7 +89,7 @@ func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array:
var clear_code_index: int = pow(2, get_bits_number_for(last_color_index)) var clear_code_index: int = pow(2, get_bits_number_for(last_color_index))
var index_stream: PoolByteArray = image var index_stream: PoolByteArray = image
var current_code_size: int = get_bits_number_for(clear_code_index) var current_code_size: int = get_bits_number_for(clear_code_index)
var binary_code_stream = lsbbitpacker.LSB_LZWBitPacker.new() var binary_code_stream = lsbbitpacker.LSBLZWBitPacker.new()
# initialize with Clear Code # initialize with Clear Code
binary_code_stream.write_bits(clear_code_index, current_code_size) binary_code_stream.write_bits(clear_code_index, current_code_size)
@ -94,15 +100,15 @@ func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array:
# <LOOP POINT> # <LOOP POINT>
while data_index < index_stream.size(): while data_index < index_stream.size():
# Get the next index from the index stream. # Get the next index from the index stream.
var K: CodeEntry = CodeEntry.new([index_stream[data_index]]) var k: CodeEntry = CodeEntry.new([index_stream[data_index]])
data_index += 1 data_index += 1
# Is index buffer + K in our code table? # Is index buffer + k in our code table?
var new_index_buffer: CodeEntry = index_buffer.add(K) var new_index_buffer: CodeEntry = index_buffer.add(k)
if code_table.has(new_index_buffer): # if YES if code_table.has(new_index_buffer): # if YES
# Add K to the end of the index buffer # Add k to the end of the index buffer
index_buffer = new_index_buffer index_buffer = new_index_buffer
else: # if NO else: # if NO
# Add a row for index buffer + K into our code table # Add a row for index buffer + k into our code table
binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size)
# We don't want to add new code to code table if we've exceeded 4095 # We don't want to add new code to code table if we've exceeded 4095
@ -128,8 +134,8 @@ func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array:
if new_code_size_candidate > current_code_size: if new_code_size_candidate > current_code_size:
current_code_size = new_code_size_candidate current_code_size = new_code_size_candidate
# Index buffer is set to K # Index buffer is set to k
index_buffer = K index_buffer = k
# Output code for contents of index buffer # Output code for contents of index buffer
binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size) binary_code_stream.write_bits(code_table.find(index_buffer), current_code_size)
@ -140,10 +146,11 @@ func compress_lzw(image: PoolByteArray, colors: PoolByteArray) -> Array:
return [binary_code_stream.pack(), min_code_size] return [binary_code_stream.pack(), min_code_size]
func decompress_lzw(code_stream_data: PoolByteArray, min_code_size: int, colors: PoolByteArray) -> PoolByteArray: func decompress_lzw(code_stream_data: PoolByteArray, min_code_size: int, colors: PoolByteArray) -> PoolByteArray:
var code_table: CodeTable = initialize_color_code_table(colors) var code_table: CodeTable = initialize_color_code_table(colors)
var index_stream: PoolByteArray = PoolByteArray([]) var index_stream: PoolByteArray = PoolByteArray([])
var binary_code_stream = lsbbitunpacker.LSB_LZWBitUnpacker.new(code_stream_data) var binary_code_stream = lsbbitunpacker.LSBLZWBitUnpacker.new(code_stream_data)
var current_code_size: int = min_code_size + 1 var current_code_size: int = min_code_size + 1
var clear_code_index: int = pow(2, min_code_size) var clear_code_index: int = pow(2, min_code_size)
@ -168,29 +175,29 @@ func decompress_lzw(code_stream_data: PoolByteArray, min_code_size: int, colors:
code_table = initialize_color_code_table(colors) code_table = initialize_color_code_table(colors)
current_code_size = min_code_size + 1 current_code_size = min_code_size + 1
code = binary_code_stream.read_bits(current_code_size) code = binary_code_stream.read_bits(current_code_size)
elif code == clear_code_index + 1: # Stop when detected EOI Code. elif code == clear_code_index + 1: # Stop when detected EOI Code.
break break
# is CODE in the code table? # is CODE in the code table?
var code_entry: CodeEntry = code_table.get(code) var code_entry: CodeEntry = code_table.get(code)
if code_entry != null: # if YES if code_entry != null: # if YES
# output {CODE} to index stream # output {CODE} to index stream
index_stream.append_array(code_entry.sequence) index_stream.append_array(code_entry.sequence)
# let K be the first index in {CODE} # let k be the first index in {CODE}
var K: CodeEntry = CodeEntry.new([code_entry.sequence[0]]) var k: CodeEntry = CodeEntry.new([code_entry.sequence[0]])
# warning-ignore:return_value_discarded # warning-ignore:return_value_discarded
# add {PREVCODE} + K to the code table # add {PREVCODE} + k to the code table
code_table.add(code_table.get(prevcode).add(K)) code_table.add(code_table.get(prevcode).add(k))
# set PREVCODE = CODE # set PREVCODE = CODE
prevcode = code prevcode = code
else: # if NO else: # if NO
# let K be the first index of {PREVCODE} # let k be the first index of {PREVCODE}
var prevcode_entry: CodeEntry = code_table.get(prevcode) var prevcode_entry: CodeEntry = code_table.get(prevcode)
var K: CodeEntry = CodeEntry.new([prevcode_entry.sequence[0]]) var k: CodeEntry = CodeEntry.new([prevcode_entry.sequence[0]])
# output {PREVCODE} + K to index stream # output {PREVCODE} + k to index stream
index_stream.append_array(prevcode_entry.add(K).sequence) index_stream.append_array(prevcode_entry.add(k).sequence)
# add {PREVCODE} + K to code table # add {PREVCODE} + k to code table
# warning-ignore:return_value_discarded # warning-ignore:return_value_discarded
code_table.add(prevcode_entry.add(K)) code_table.add(prevcode_entry.add(k))
# set PREVCODE = CODE # set PREVCODE = CODE
prevcode = code prevcode = code

View file

@ -1,9 +1,9 @@
extends Reference extends Reference
var converter = preload("../converter.gd").new()
var converter = preload('../converter.gd').new()
var transparency := false var transparency := false
func longest_axis(colors: Array) -> int: func longest_axis(colors: Array) -> int:
var start := [255, 255, 255] var start := [255, 255, 255]
var end := [0, 0, 0] var end := [0, 0, 0]
@ -24,6 +24,7 @@ func longest_axis(colors: Array) -> int:
return 1 return 1
return 2 return 2
func get_median(colors: Array) -> Vector3: func get_median(colors: Array) -> Vector3:
return colors[colors.size() >> 1] return colors[colors.size() >> 1]
@ -51,6 +52,7 @@ func median_cut(colors: Array) -> Array:
return [left_colors, right_colors] return [left_colors, right_colors]
func average_color(bucket: Array) -> Array: func average_color(bucket: Array) -> Array:
var r := 0 var r := 0
var g := 0 var g := 0
@ -61,6 +63,7 @@ func average_color(bucket: Array) -> Array:
b += color[2] b += color[2]
return [r / bucket.size(), g / bucket.size(), b / bucket.size()] return [r / bucket.size(), g / bucket.size(), b / bucket.size()]
func average_colors(buckets: Array) -> Dictionary: func average_colors(buckets: Array) -> Dictionary:
var avg_colors := {} var avg_colors := {}
for bucket in buckets: for bucket in buckets:
@ -68,6 +71,7 @@ func average_colors(buckets: Array) -> Dictionary:
avg_colors[average_color(bucket)] = avg_colors.size() avg_colors[average_color(bucket)] = avg_colors.size()
return avg_colors return avg_colors
func pixels_to_colors(image: Image) -> Array: func pixels_to_colors(image: Image) -> Array:
image.lock() image.lock()
var result := [] var result := []
@ -81,6 +85,7 @@ func pixels_to_colors(image: Image) -> Array:
image.unlock() image.unlock()
return result return result
func remove_smallest_bucket(buckets: Array) -> Array: func remove_smallest_bucket(buckets: Array) -> Array:
if buckets.size() == 0: if buckets.size() == 0:
return buckets return buckets
@ -91,6 +96,7 @@ func remove_smallest_bucket(buckets: Array) -> Array:
buckets.remove(i_of_smallest_bucket) buckets.remove(i_of_smallest_bucket)
return buckets return buckets
func remove_empty_buckets(buckets: Array) -> Array: func remove_empty_buckets(buckets: Array) -> Array:
if buckets.size() == 0: if buckets.size() == 0:
return buckets return buckets
@ -102,6 +108,7 @@ func remove_empty_buckets(buckets: Array) -> Array:
return buckets return buckets
# quantizes to gif ready codes # quantizes to gif ready codes
func quantize(image: Image) -> Array: func quantize(image: Image) -> Array:
var pixels = pixels_to_colors(image) var pixels = pixels_to_colors(image)

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=true detect_3d=true

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -28,6 +28,7 @@ process/fix_alpha_border=true
process/premult_alpha=false process/premult_alpha=false
process/HDR_as_SRGB=false process/HDR_as_SRGB=false
process/invert_color=false process/invert_color=false
process/normal_map_invert_y=false
stream=false stream=false
size_limit=0 size_limit=0
detect_3d=false detect_3d=false

View file

@ -1,85 +1,88 @@
extends Node extends Node
enum GradientDirection { TOP, BOTTOM, LEFT, RIGHT }
enum GradientDirection {TOP, BOTTOM, LEFT, RIGHT}
func scale3X(sprite : Image, tol : float = 50) -> Image: func scale_3x(sprite: Image, tol: float = 50) -> Image:
var scaled := Image.new() var scaled := Image.new()
scaled.create(sprite.get_width()*3, sprite.get_height()*3, false, Image.FORMAT_RGBA8) scaled.create(sprite.get_width() * 3, sprite.get_height() * 3, false, Image.FORMAT_RGBA8)
scaled.lock() scaled.lock()
sprite.lock() sprite.lock()
var a : Color var a: Color
var b : Color var b: Color
var c : Color var c: Color
var d : Color var d: Color
var e : Color var e: Color
var f : Color var f: Color
var g : Color var g: Color
var h : Color var h: Color
var i : Color var i: Color
for x in range(1,sprite.get_width()-1): for x in range(1, sprite.get_width() - 1):
for y in range(1,sprite.get_height()-1): for y in range(1, sprite.get_height() - 1):
var xs : float = 3*x var xs: float = 3 * x
var ys : float = 3*y var ys: float = 3 * y
a = sprite.get_pixel(x-1,y-1) a = sprite.get_pixel(x - 1, y - 1)
b = sprite.get_pixel(x,y-1) b = sprite.get_pixel(x, y - 1)
c = sprite.get_pixel(x+1,y-1) c = sprite.get_pixel(x + 1, y - 1)
d = sprite.get_pixel(x-1,y) d = sprite.get_pixel(x - 1, y)
e = sprite.get_pixel(x,y) e = sprite.get_pixel(x, y)
f = sprite.get_pixel(x+1,y) f = sprite.get_pixel(x + 1, y)
g = sprite.get_pixel(x-1,y+1) g = sprite.get_pixel(x - 1, y + 1)
h = sprite.get_pixel(x,y+1) h = sprite.get_pixel(x, y + 1)
i = sprite.get_pixel(x+1,y+1) i = sprite.get_pixel(x + 1, y + 1)
var db : bool = similarColors(d, b, tol) var db: bool = similar_colors(d, b, tol)
var dh : bool = similarColors(d, h, tol) var dh: bool = similar_colors(d, h, tol)
var bf : bool = similarColors(f, b, tol) var bf: bool = similar_colors(f, b, tol)
var ec : bool = similarColors(e, c, tol) var ec: bool = similar_colors(e, c, tol)
var ea : bool = similarColors(e, a, tol) var ea: bool = similar_colors(e, a, tol)
var fh : bool = similarColors(f, h, tol) var fh: bool = similar_colors(f, h, tol)
var eg : bool = similarColors(e, g, tol) var eg: bool = similar_colors(e, g, tol)
var ei : bool = similarColors(e, i, tol) var ei: bool = similar_colors(e, i, tol)
scaled.set_pixel(xs-1, ys-1, d if (db and !dh and !bf) else e ) scaled.set_pixel(xs - 1, ys - 1, d if (db and !dh and !bf) else e)
scaled.set_pixel(xs, ys-1, b if (db and !dh and !bf and !ec) or scaled.set_pixel(
(bf and !db and !fh and !ea) else e) xs, ys - 1, b if (db and !dh and !bf and !ec) or (bf and !db and !fh and !ea) else e
scaled.set_pixel(xs+1, ys-1, f if (bf and !db and !fh) else e) )
scaled.set_pixel(xs-1, ys, d if (dh and !fh and !db and !ea) or scaled.set_pixel(xs + 1, ys - 1, f if (bf and !db and !fh) else e)
(db and !dh and !bf and !eg) else e) scaled.set_pixel(
scaled.set_pixel(xs, ys, e); xs - 1, ys, d if (dh and !fh and !db and !ea) or (db and !dh and !bf and !eg) else e
scaled.set_pixel(xs+1, ys, f if (bf and !db and !fh and !ei) or )
(fh and !bf and !dh and !ec) else e) scaled.set_pixel(xs, ys, e)
scaled.set_pixel(xs-1, ys+1, d if (dh and !fh and !db) else e) scaled.set_pixel(
scaled.set_pixel(xs, ys+1, h if (fh and !bf and !dh and !eg) or xs + 1, ys, f if (bf and !db and !fh and !ei) or (fh and !bf and !dh and !ec) else e
(dh and !fh and !db and !ei) else e) )
scaled.set_pixel(xs+1, ys+1, f if (fh and !bf and !dh) else e) scaled.set_pixel(xs - 1, ys + 1, d if (dh and !fh and !db) else e)
scaled.set_pixel(
xs, ys + 1, h if (fh and !bf and !dh and !eg) or (dh and !fh and !db and !ei) else e
)
scaled.set_pixel(xs + 1, ys + 1, f if (fh and !bf and !dh) else e)
scaled.unlock() scaled.unlock()
sprite.unlock() sprite.unlock()
return scaled return scaled
func rotxel(sprite : Image, angle : float, pivot : Vector2) -> void: func rotxel(sprite: Image, angle: float, pivot: Vector2) -> void:
# If angle is simple, then nn rotation is the best # If angle is simple, then nn rotation is the best
if angle == 0 || angle == PI/2 || angle == PI || angle == 2*PI: if angle == 0 || angle == PI / 2 || angle == PI || angle == 2 * PI:
nn_rotate(sprite, angle, pivot) nn_rotate(sprite, angle, pivot)
return return
var aux : Image = Image.new() var aux: Image = Image.new()
aux.copy_from(sprite) aux.copy_from(sprite)
var ox : int var ox: int
var oy : int var oy: int
var p : Color var p: Color
aux.lock() aux.lock()
sprite.lock() sprite.lock()
for x in sprite.get_size().x: for x in sprite.get_size().x:
for y in sprite.get_size().y: for y in sprite.get_size().y:
var dx = 3*(x - pivot.x) var dx = 3 * (x - pivot.x)
var dy = 3*(y - pivot.y) var dy = 3 * (y - pivot.y)
var found_pixel : bool = false var found_pixel: bool = false
for k in range(9): for k in range(9):
var i = -1 + k % 3 var i = -1 + k % 3
# warning-ignore:integer_division # warning-ignore:integer_division
@ -87,95 +90,182 @@ func rotxel(sprite : Image, angle : float, pivot : Vector2) -> void:
var dir = atan2(dy + j, dx + i) var dir = atan2(dy + j, dx + i)
var mag = sqrt(pow(dx + i, 2) + pow(dy + j, 2)) var mag = sqrt(pow(dx + i, 2) + pow(dy + j, 2))
dir -= angle dir -= angle
ox = round(pivot.x*3 + 1 + mag*cos(dir)) ox = round(pivot.x * 3 + 1 + mag * cos(dir))
oy = round(pivot.y*3 + 1 + mag*sin(dir)) oy = round(pivot.y * 3 + 1 + mag * sin(dir))
if (sprite.get_width() % 2 != 0): if sprite.get_width() % 2 != 0:
ox += 1 ox += 1
oy += 1 oy += 1
if (ox >= 0 && ox < sprite.get_width()*3 if (
&& oy >= 0 && oy < sprite.get_height()*3): ox >= 0
found_pixel = true && ox < sprite.get_width() * 3
break && oy >= 0
&& oy < sprite.get_height() * 3
):
found_pixel = true
break
if !found_pixel: if !found_pixel:
sprite.set_pixel(x, y, Color(0,0,0,0)) sprite.set_pixel(x, y, Color(0, 0, 0, 0))
continue continue
var fil : int = oy % 3 var fil: int = oy % 3
var col : int = ox % 3 var col: int = ox % 3
var index : int = col + 3*fil var index: int = col + 3 * fil
ox = round((ox - 1)/3.0); ox = round((ox - 1) / 3.0)
oy = round((oy - 1)/3.0); oy = round((oy - 1) / 3.0)
var a : Color var a: Color
var b : Color var b: Color
var c : Color var c: Color
var d : Color var d: Color
var e : Color var e: Color
var f : Color var f: Color
var g : Color var g: Color
var h : Color var h: Color
var i : Color var i: Color
if (ox == 0 || ox == sprite.get_width() - 1 || if ox == 0 || ox == sprite.get_width() - 1 || oy == 0 || oy == sprite.get_height() - 1:
oy == 0 || oy == sprite.get_height() - 1): p = aux.get_pixel(ox, oy)
p = aux.get_pixel(ox, oy)
else: else:
a = aux.get_pixel(ox-1,oy-1); a = aux.get_pixel(ox - 1, oy - 1)
b = aux.get_pixel(ox,oy-1); b = aux.get_pixel(ox, oy - 1)
c = aux.get_pixel(ox+1,oy-1); c = aux.get_pixel(ox + 1, oy - 1)
d = aux.get_pixel(ox-1,oy); d = aux.get_pixel(ox - 1, oy)
e = aux.get_pixel(ox,oy); e = aux.get_pixel(ox, oy)
f = aux.get_pixel(ox+1,oy); f = aux.get_pixel(ox + 1, oy)
g = aux.get_pixel(ox-1,oy+1); g = aux.get_pixel(ox - 1, oy + 1)
h = aux.get_pixel(ox,oy+1); h = aux.get_pixel(ox, oy + 1)
i = aux.get_pixel(ox+1,oy+1); i = aux.get_pixel(ox + 1, oy + 1)
match(index): match index:
0: 0:
p = d if (similarColors(d,b) && !similarColors(d,h) p = (
&& !similarColors(b,f)) else e; d
if (
similar_colors(d, b)
&& !similar_colors(d, h)
&& !similar_colors(b, f)
)
else e
)
1: 1:
p = b if ((similarColors(d,b) && !similarColors(d,h) && p = (
!similarColors(b,f) && !similarColors(e,c)) || b
(similarColors(b,f) && !similarColors(d,b) && if (
!similarColors(f,h) && !similarColors(e,a))) else e; (
similar_colors(d, b)
&& !similar_colors(d, h)
&& !similar_colors(b, f)
&& !similar_colors(e, c)
)
|| (
similar_colors(b, f)
&& !similar_colors(d, b)
&& !similar_colors(f, h)
&& !similar_colors(e, a)
)
)
else e
)
2: 2:
p = f if (similarColors(b,f) && !similarColors(d,b) && p = (
!similarColors(f,h)) else e; f
if (
similar_colors(b, f)
&& !similar_colors(d, b)
&& !similar_colors(f, h)
)
else e
)
3: 3:
p = d if ((similarColors(d,h) && !similarColors(f,h) && p = (
!similarColors(d,b) && !similarColors(e,a)) || d
(similarColors(d,b) && !similarColors(d,h) && if (
!similarColors(b,f) && !similarColors(e,g))) else e; (
similar_colors(d, h)
&& !similar_colors(f, h)
&& !similar_colors(d, b)
&& !similar_colors(e, a)
)
|| (
similar_colors(d, b)
&& !similar_colors(d, h)
&& !similar_colors(b, f)
&& !similar_colors(e, g)
)
)
else e
)
4: 4:
p = e p = e
5: 5:
p = f if((similarColors(b,f) && !similarColors(d,b) && p = (
!similarColors(f,h) && !similarColors(e,i)) f
|| (similarColors(f,h) && !similarColors(b,f) && if (
!similarColors(d,h) && !similarColors(e,c))) else e; (
similar_colors(b, f)
&& !similar_colors(d, b)
&& !similar_colors(f, h)
&& !similar_colors(e, i)
)
|| (
similar_colors(f, h)
&& !similar_colors(b, f)
&& !similar_colors(d, h)
&& !similar_colors(e, c)
)
)
else e
)
6: 6:
p = d if (similarColors(d,h) && !similarColors(f,h) && p = (
!similarColors(d,b)) else e; d
if (
similar_colors(d, h)
&& !similar_colors(f, h)
&& !similar_colors(d, b)
)
else e
)
7: 7:
p = h if ((similarColors(f,h) && !similarColors(f,b) && p = (
!similarColors(d,h) && !similarColors(e,g)) h
|| (similarColors(d,h) && !similarColors(f,h) && if (
!similarColors(d,b) && !similarColors(e,i))) else e; (
similar_colors(f, h)
&& !similar_colors(f, b)
&& !similar_colors(d, h)
&& !similar_colors(e, g)
)
|| (
similar_colors(d, h)
&& !similar_colors(f, h)
&& !similar_colors(d, b)
&& !similar_colors(e, i)
)
)
else e
)
8: 8:
p = f if (similarColors(f,h) && !similarColors(f,b) && p = (
!similarColors(d,h)) else e; f
if (
similar_colors(f, h)
&& !similar_colors(f, b)
&& !similar_colors(d, h)
)
else e
)
sprite.set_pixel(x, y, p) sprite.set_pixel(x, y, p)
sprite.unlock() sprite.unlock()
aux.unlock() aux.unlock()
func fake_rotsprite(sprite : Image, angle : float, pivot : Vector2) -> void: func fake_rotsprite(sprite: Image, angle: float, pivot: Vector2) -> void:
var selected_sprite := Image.new() var selected_sprite := Image.new()
selected_sprite.copy_from(sprite) selected_sprite.copy_from(sprite)
selected_sprite.copy_from(scale3X(selected_sprite)) selected_sprite.copy_from(scale_3x(selected_sprite))
nn_rotate(selected_sprite, angle, pivot * 3) nn_rotate(selected_sprite, angle, pivot * 3)
# warning-ignore:integer_division # warning-ignore:integer_division
# warning-ignore:integer_division # warning-ignore:integer_division
@ -183,8 +273,8 @@ func fake_rotsprite(sprite : Image, angle : float, pivot : Vector2) -> void:
sprite.blit_rect(selected_sprite, Rect2(Vector2.ZERO, selected_sprite.get_size()), Vector2.ZERO) sprite.blit_rect(selected_sprite, Rect2(Vector2.ZERO, selected_sprite.get_size()), Vector2.ZERO)
func nn_rotate(sprite : Image, angle : float, pivot : Vector2) -> void: func nn_rotate(sprite: Image, angle: float, pivot: Vector2) -> void:
var aux : Image = Image.new() var aux: Image = Image.new()
aux.copy_from(sprite) aux.copy_from(sprite)
sprite.lock() sprite.lock()
aux.lock() aux.lock()
@ -192,44 +282,57 @@ func nn_rotate(sprite : Image, angle : float, pivot : Vector2) -> void:
var oy: int var oy: int
for x in range(sprite.get_width()): for x in range(sprite.get_width()):
for y in range(sprite.get_height()): for y in range(sprite.get_height()):
ox = (x - pivot.x)*cos(angle) + (y - pivot.y)*sin(angle) + pivot.x ox = (x - pivot.x) * cos(angle) + (y - pivot.y) * sin(angle) + pivot.x
oy = -(x - pivot.x)*sin(angle) + (y - pivot.y)*cos(angle) + pivot.y oy = -(x - pivot.x) * sin(angle) + (y - pivot.y) * cos(angle) + pivot.y
if ox >= 0 && ox < sprite.get_width() && oy >= 0 && oy < sprite.get_height(): if ox >= 0 && ox < sprite.get_width() && oy >= 0 && oy < sprite.get_height():
sprite.set_pixel(x, y, aux.get_pixel(ox, oy)) sprite.set_pixel(x, y, aux.get_pixel(ox, oy))
else: else:
sprite.set_pixel(x, y, Color(0,0,0,0)) sprite.set_pixel(x, y, Color(0, 0, 0, 0))
sprite.unlock() sprite.unlock()
aux.unlock() aux.unlock()
func similarColors(c1 : Color, c2 : Color, tol : float = 100) -> bool: func similar_colors(c1: Color, c2: Color, tol: float = 100) -> bool:
var dist = colorDistance(c1, c2) var dist = color_distance(c1, c2)
return dist <= tol return dist <= tol
func colorDistance(c1 : Color, c2 : Color) -> float: func color_distance(c1: Color, c2: Color) -> float:
return sqrt(pow((c1.r - c2.r)*255, 2) + pow((c1.g - c2.g)*255, 2) return sqrt(
+ pow((c1.b - c2.b)*255, 2) + pow((c1.a - c2.a)*255, 2)) (
pow((c1.r - c2.r) * 255, 2)
+ pow((c1.g - c2.g) * 255, 2)
+ pow((c1.b - c2.b) * 255, 2)
+ pow((c1.a - c2.a) * 255, 2)
)
)
# Image effects # Image effects
func scale_image(width : int, height : int, interpolation : int) -> void:
func scale_image(width: int, height: int, interpolation: int) -> void:
general_do_scale(width, height) general_do_scale(width, height)
for f in Global.current_project.frames: for f in Global.current_project.frames:
for i in range(f.cels.size() - 1, -1, -1): for i in range(f.cels.size() - 1, -1, -1):
var sprite := Image.new() var sprite := Image.new()
sprite.copy_from(f.cels[i].image) sprite.copy_from(f.cels[i].image)
# Different method for scale3x # Different method for scale_3x
if interpolation == 5: if interpolation == 5:
var times : Vector2 = Vector2(ceil(width/(3.0*sprite.get_width())),ceil(height/(3.0*sprite.get_height()))) var times: Vector2 = Vector2(
for _j in range(max(times.x,times.y)): ceil(width / (3.0 * sprite.get_width())),
sprite.copy_from(scale3X(sprite)) ceil(height / (3.0 * sprite.get_height()))
)
for _j in range(max(times.x, times.y)):
sprite.copy_from(scale_3x(sprite))
sprite.resize(width, height, 0) sprite.resize(width, height, 0)
else: else:
sprite.resize(width, height, interpolation) sprite.resize(width, height, interpolation)
Global.current_project.undo_redo.add_do_property(f.cels[i].image, "data", sprite.data) Global.current_project.undo_redo.add_do_property(f.cels[i].image, "data", sprite.data)
Global.current_project.undo_redo.add_undo_property(f.cels[i].image, "data", f.cels[i].image.data) Global.current_project.undo_redo.add_undo_property(
f.cels[i].image, "data", f.cels[i].image.data
)
general_undo_scale() general_undo_scale()
@ -239,17 +342,19 @@ func centralize() -> void:
# Find used rect of the current frame (across all of the layers) # Find used rect of the current frame (across all of the layers)
var used_rect := Rect2() var used_rect := Rect2()
for cel in Global.current_project.frames[Global.current_project.current_frame].cels: for cel in Global.current_project.frames[Global.current_project.current_frame].cels:
var cel_rect : Rect2 = cel.image.get_used_rect() var cel_rect: Rect2 = cel.image.get_used_rect()
if not cel_rect.has_no_area(): if not cel_rect.has_no_area():
used_rect = cel_rect if used_rect.has_no_area() else used_rect.merge(cel_rect) used_rect = cel_rect if used_rect.has_no_area() else used_rect.merge(cel_rect)
if used_rect.has_no_area(): if used_rect.has_no_area():
return return
var offset : Vector2 = (0.5 * (Global.current_project.size - used_rect.size)).floor() var offset: Vector2 = (0.5 * (Global.current_project.size - used_rect.size)).floor()
general_do_centralize() general_do_centralize()
for c in Global.current_project.frames[Global.current_project.current_frame].cels: for c in Global.current_project.frames[Global.current_project.current_frame].cels:
var sprite := Image.new() var sprite := Image.new()
sprite.create(Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8) sprite.create(
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8
)
sprite.blend_rect(c.image, used_rect, offset) sprite.blend_rect(c.image, used_rect, offset)
Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data) Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data)
Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data) Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data)
@ -261,12 +366,12 @@ func crop_image() -> void:
var used_rect := Rect2() var used_rect := Rect2()
for f in Global.current_project.frames: for f in Global.current_project.frames:
for cel in f.cels: for cel in f.cels:
cel.image.unlock() # May be unneeded now, but keep it just in case cel.image.unlock() # May be unneeded now, but keep it just in case
var cel_used_rect : Rect2 = cel.image.get_used_rect() var cel_used_rect: Rect2 = cel.image.get_used_rect()
if cel_used_rect == Rect2(0, 0, 0, 0): # If the cel has no content if cel_used_rect == Rect2(0, 0, 0, 0): # If the cel has no content
continue continue
if used_rect == Rect2(0, 0, 0, 0): # If we still haven't found the first cel with content if used_rect == Rect2(0, 0, 0, 0): # If we still haven't found the first cel with content
used_rect = cel_used_rect used_rect = cel_used_rect
else: else:
used_rect = used_rect.merge(cel_used_rect) used_rect = used_rect.merge(cel_used_rect)
@ -281,33 +386,37 @@ func crop_image() -> void:
# Loop through all the cels to crop them # Loop through all the cels to crop them
for f in Global.current_project.frames: for f in Global.current_project.frames:
for cel in f.cels: for cel in f.cels:
var sprite : Image = cel.image.get_rect(used_rect) var sprite: Image = cel.image.get_rect(used_rect)
Global.current_project.undo_redo.add_do_property(cel.image, "data", sprite.data) Global.current_project.undo_redo.add_do_property(cel.image, "data", sprite.data)
Global.current_project.undo_redo.add_undo_property(cel.image, "data", cel.image.data) Global.current_project.undo_redo.add_undo_property(cel.image, "data", cel.image.data)
general_undo_scale() general_undo_scale()
func resize_canvas(width : int, height : int, offset_x : int, offset_y : int) -> void: func resize_canvas(width: int, height: int, offset_x: int, offset_y: int) -> void:
general_do_scale(width, height) general_do_scale(width, height)
for f in Global.current_project.frames: for f in Global.current_project.frames:
for c in f.cels: for c in f.cels:
var sprite := Image.new() var sprite := Image.new()
sprite.create(width, height, false, Image.FORMAT_RGBA8) sprite.create(width, height, false, Image.FORMAT_RGBA8)
sprite.blend_rect(c.image, Rect2(Vector2.ZERO, Global.current_project.size), Vector2(offset_x, offset_y)) sprite.blend_rect(
c.image,
Rect2(Vector2.ZERO, Global.current_project.size),
Vector2(offset_x, offset_y)
)
Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data) Global.current_project.undo_redo.add_do_property(c.image, "data", sprite.data)
Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data) Global.current_project.undo_redo.add_undo_property(c.image, "data", c.image.data)
general_undo_scale() general_undo_scale()
func general_do_scale(width : int, height : int) -> void: func general_do_scale(width: int, height: int) -> void:
var project: Project = Global.current_project var project: Project = Global.current_project
var size := Vector2(width, height).floor() var size := Vector2(width, height).floor()
var x_ratio = project.size.x / width var x_ratio = project.size.x / width
var y_ratio = project.size.y / height var y_ratio = project.size.y / height
var bitmap : BitMap var bitmap: BitMap
bitmap = project.resize_bitmap(project.selection_bitmap, size) bitmap = project.resize_bitmap(project.selection_bitmap, size)
var new_x_symmetry_point = project.x_symmetry_point / x_ratio var new_x_symmetry_point = project.x_symmetry_point / x_ratio
@ -335,8 +444,12 @@ func general_undo_scale() -> void:
project.undo_redo.add_undo_property(project, "selection_bitmap", project.selection_bitmap) project.undo_redo.add_undo_property(project, "selection_bitmap", project.selection_bitmap)
project.undo_redo.add_undo_property(project, "x_symmetry_point", project.x_symmetry_point) project.undo_redo.add_undo_property(project, "x_symmetry_point", project.x_symmetry_point)
project.undo_redo.add_undo_property(project, "y_symmetry_point", project.y_symmetry_point) project.undo_redo.add_undo_property(project, "y_symmetry_point", project.y_symmetry_point)
project.undo_redo.add_undo_property(project.x_symmetry_axis, "points", project.x_symmetry_axis.points) project.undo_redo.add_undo_property(
project.undo_redo.add_undo_property(project.y_symmetry_axis, "points", project.y_symmetry_axis.points) project.x_symmetry_axis, "points", project.x_symmetry_axis.points
)
project.undo_redo.add_undo_property(
project.y_symmetry_axis, "points", project.y_symmetry_axis.points
)
project.undo_redo.add_undo_method(Global, "undo") project.undo_redo.add_undo_method(Global, "undo")
project.undo_redo.add_do_method(Global, "redo") project.undo_redo.add_do_method(Global, "redo")
project.undo_redo.commit_action() project.undo_redo.commit_action()
@ -355,50 +468,15 @@ func general_undo_centralize() -> void:
project.undo_redo.commit_action() project.undo_redo.commit_action()
# TO BE REMOVED func generate_outline(
# func invert_image_colors(image : Image, affect_selection : bool, project : Project, red := true, green := true, blue := true, alpha := false) -> void: image: Image,
# image.lock() affect_selection: bool,
# for x in project.size.x: project: Project,
# for y in project.size.y: outline_color: Color,
# var pos := Vector2(x, y) thickness: int,
# if affect_selection and !project.can_pixel_get_drawn(pos): diagonal: bool,
# continue inside_image: bool
# var px_color := image.get_pixelv(pos) ) -> void:
# # Manually invert each color channel
# if red:
# px_color.r = 1.0 - px_color.r
# if green:
# px_color.g = 1.0 - px_color.g
# if blue:
# px_color.b = 1.0 - px_color.b
# if alpha:
# px_color.a = 1.0 - px_color.a
# image.set_pixelv(pos, px_color)
# TO BE REMOVED
# func desaturate_image(image : Image, affect_selection : bool, project : Project, red := true, green := true, blue := true, alpha := false) -> void:
# image.lock()
# for x in project.size.x:
# for y in project.size.y:
# var pos := Vector2(x, y)
# if affect_selection and !project.can_pixel_get_drawn(pos):
# continue
# var px_color := image.get_pixelv(pos)
# var gray = px_color.v
# if red:
# px_color.r = gray
# if green:
# px_color.g = gray
# if blue:
# px_color.b = gray
# if alpha:
# px_color.a = gray
# image.set_pixelv(pos, px_color)
func generate_outline(image : Image, affect_selection : bool, project : Project, outline_color : Color, thickness : int, diagonal : bool, inside_image : bool) -> void:
if image.is_invisible(): if image.is_invisible():
return return
var new_image := Image.new() var new_image := Image.new()
@ -417,117 +495,144 @@ func generate_outline(image : Image, affect_selection : bool, project : Project,
for i in range(1, thickness + 1): for i in range(1, thickness + 1):
if inside_image: if inside_image:
var outline_pos : Vector2 = pos + Vector2.LEFT # Left var outline_pos: Vector2 = pos + Vector2.LEFT # Left
if outline_pos.x < 0 || image.get_pixelv(outline_pos).a == 0: if outline_pos.x < 0 || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.RIGHT * (i - 1) var new_pos: Vector2 = pos + Vector2.RIGHT * (i - 1)
if new_pos.x < Global.current_project.size.x: if new_pos.x < Global.current_project.size.x:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.RIGHT # Right outline_pos = pos + Vector2.RIGHT # Right
if outline_pos.x >= Global.current_project.size.x || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + Vector2.LEFT * (i - 1) outline_pos.x >= Global.current_project.size.x
|| image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + Vector2.LEFT * (i - 1)
if new_pos.x >= 0: if new_pos.x >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.UP # Up outline_pos = pos + Vector2.UP # Up
if outline_pos.y < 0 || image.get_pixelv(outline_pos).a == 0: if outline_pos.y < 0 || image.get_pixelv(outline_pos).a == 0:
var new_pos : Vector2 = pos + Vector2.DOWN * (i - 1) var new_pos: Vector2 = pos + Vector2.DOWN * (i - 1)
if new_pos.y < Global.current_project.size.y: if new_pos.y < Global.current_project.size.y:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + Vector2.DOWN # Down outline_pos = pos + Vector2.DOWN # Down
if outline_pos.y >= Global.current_project.size.y || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + Vector2.UP * (i - 1) outline_pos.y >= Global.current_project.size.y
|| image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + Vector2.UP * (i - 1)
if new_pos.y >= 0: if new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
if diagonal: if diagonal:
outline_pos = pos + (Vector2.LEFT + Vector2.UP) # Top left outline_pos = pos + (Vector2.LEFT + Vector2.UP) # Top left
if (outline_pos.x < 0 && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.DOWN) * (i - 1) (outline_pos.x < 0 && outline_pos.y < 0)
if new_pos.x < Global.current_project.size.x && new_pos.y < Global.current_project.size.y: || image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + (Vector2.RIGHT + Vector2.DOWN) * (i - 1)
if (
new_pos.x < Global.current_project.size.x
&& new_pos.y < Global.current_project.size.y
):
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.LEFT + Vector2.DOWN) # Bottom left outline_pos = pos + (Vector2.LEFT + Vector2.DOWN) # Bottom left
if (outline_pos.x < 0 && outline_pos.y >= Global.current_project.size.y) || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + (Vector2.RIGHT + Vector2.UP) * (i - 1) (outline_pos.x < 0 && outline_pos.y >= Global.current_project.size.y)
|| image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + (Vector2.RIGHT + Vector2.UP) * (i - 1)
if new_pos.x < Global.current_project.size.x && new_pos.y >= 0: if new_pos.x < Global.current_project.size.x && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.RIGHT + Vector2.UP) # Top right outline_pos = pos + (Vector2.RIGHT + Vector2.UP) # Top right
if (outline_pos.x >= Global.current_project.size.x && outline_pos.y < 0) || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.DOWN) * (i - 1) (outline_pos.x >= Global.current_project.size.x && outline_pos.y < 0)
|| image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + (Vector2.LEFT + Vector2.DOWN) * (i - 1)
if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y: if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
outline_pos = pos + (Vector2.RIGHT + Vector2.DOWN) # Bottom right outline_pos = pos + (Vector2.RIGHT + Vector2.DOWN) # Bottom right
if (outline_pos.x >= Global.current_project.size.x && outline_pos.y >= Global.current_project.size.y) || image.get_pixelv(outline_pos).a == 0: if (
var new_pos : Vector2 = pos + (Vector2.LEFT + Vector2.UP) * (i - 1) (
outline_pos.x >= Global.current_project.size.x
&& outline_pos.y >= Global.current_project.size.y
)
|| image.get_pixelv(outline_pos).a == 0
):
var new_pos: Vector2 = pos + (Vector2.LEFT + Vector2.UP) * (i - 1)
if new_pos.x >= 0 && new_pos.y >= 0: if new_pos.x >= 0 && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a > 0: if new_pixel.a > 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
else: else:
var new_pos : Vector2 = pos + Vector2.LEFT * i # Left var new_pos: Vector2 = pos + Vector2.LEFT * i # Left
if new_pos.x >= 0: if new_pos.x >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.RIGHT * i # Right new_pos = pos + Vector2.RIGHT * i # Right
if new_pos.x < Global.current_project.size.x: if new_pos.x < Global.current_project.size.x:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.UP * i # Up new_pos = pos + Vector2.UP * i # Up
if new_pos.y >= 0: if new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + Vector2.DOWN * i # Down new_pos = pos + Vector2.DOWN * i # Down
if new_pos.y < Global.current_project.size.y: if new_pos.y < Global.current_project.size.y:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
if diagonal: if diagonal:
new_pos = pos + (Vector2.LEFT + Vector2.UP) * i # Top left new_pos = pos + (Vector2.LEFT + Vector2.UP) * i # Top left
if new_pos.x >= 0 && new_pos.y >= 0: if new_pos.x >= 0 && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.LEFT + Vector2.DOWN) * i # Bottom left new_pos = pos + (Vector2.LEFT + Vector2.DOWN) * i # Bottom left
if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y: if new_pos.x >= 0 && new_pos.y < Global.current_project.size.y:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.RIGHT + Vector2.UP) * i # Top right new_pos = pos + (Vector2.RIGHT + Vector2.UP) * i # Top right
if new_pos.x < Global.current_project.size.x && new_pos.y >= 0: if new_pos.x < Global.current_project.size.x && new_pos.y >= 0:
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
new_pos = pos + (Vector2.RIGHT + Vector2.DOWN) * i # Bottom right new_pos = pos + (Vector2.RIGHT + Vector2.DOWN) * i # Bottom right
if new_pos.x < Global.current_project.size.x && new_pos.y < Global.current_project.size.y: if (
new_pos.x < Global.current_project.size.x
&& new_pos.y < Global.current_project.size.y
):
var new_pixel = image.get_pixelv(new_pos) var new_pixel = image.get_pixelv(new_pos)
if new_pixel.a == 0: if new_pixel.a == 0:
new_image.set_pixelv(new_pos, outline_color) new_image.set_pixelv(new_pos, outline_color)
@ -537,51 +642,20 @@ func generate_outline(image : Image, affect_selection : bool, project : Project,
image.copy_from(new_image) image.copy_from(new_image)
# TO BE REMOVED func generate_gradient(
# func adjust_hsv(img: Image, delta_h : float, delta_s : float, delta_v : float, affect_selection : bool, project : Project) -> void: image: Image,
# img.lock() colors: Array,
# for x in project.size.x: steps: int,
# for y in project.size.y: direction: int,
# var pos := Vector2(x, y) affect_selection: bool,
# if affect_selection and !project.can_pixel_get_drawn(pos): project: Project
# continue ) -> void:
# var c : Color = img.get_pixelv(pos)
# # Hue
# var hue = range_lerp(c.h,0,1,-180,180)
# hue = hue + delta_h
# while(hue >= 180):
# hue -= 360
# while(hue < -180):
# hue += 360
# # Saturation
# var sat = c.s
# if delta_s > 0:
# sat = range_lerp(delta_s,0,100,c.s,1)
# elif delta_s < 0:
# sat = range_lerp(delta_s,-100,0,0,c.s)
# # Value
# var val = c.v
# if delta_v > 0:
# val = range_lerp(delta_v,0,100,c.v,1)
# elif delta_v < 0:
# val = range_lerp(delta_v,-100,0,0,c.v)
# c.h = range_lerp(hue,-180,180,0,1)
# c.s = sat
# c.v = val
# img.set_pixelv(pos, c)
func generate_gradient(image : Image, colors : Array, steps : int, direction : int, affect_selection : bool, project : Project) -> void:
if colors.size() < 2: if colors.size() < 2:
return return
var t = 1.0 / (steps - 1) var t = 1.0 / (steps - 1)
for i in range(1, steps - 1): for i in range(1, steps - 1):
var color : Color var color: Color
color = colors[-1].linear_interpolate(colors[0], t * i) color = colors[-1].linear_interpolate(colors[0], t * i)
colors.insert(1, color) colors.insert(1, color)
@ -605,7 +679,7 @@ func generate_gradient(image : Image, colors : Array, steps : int, direction : i
var start = i * gradient_size var start = i * gradient_size
var end = (i + 1) * gradient_size var end = (i + 1) * gradient_size
for yy in range(start, end): for yy in range(start, end):
var pos : Vector2 = Vector2(xx, yy) + draw_rectangle.position var pos: Vector2 = Vector2(xx, yy) + draw_rectangle.position
if selection and !project.selection_bitmap.get_bit(pos): if selection and !project.selection_bitmap.get_bit(pos):
continue continue
image.set_pixelv(pos, colors[i]) image.set_pixelv(pos, colors[i])
@ -617,7 +691,7 @@ func generate_gradient(image : Image, colors : Array, steps : int, direction : i
var start = i * gradient_size var start = i * gradient_size
var end = (i + 1) * gradient_size var end = (i + 1) * gradient_size
for xx in range(start, end): for xx in range(start, end):
var pos : Vector2 = Vector2(xx, yy) + draw_rectangle.position var pos: Vector2 = Vector2(xx, yy) + draw_rectangle.position
if selection and !project.selection_bitmap.get_bit(pos): if selection and !project.selection_bitmap.get_bit(pos):
continue continue
image.set_pixelv(pos, colors[i]) image.set_pixelv(pos, colors[i])

View file

@ -1,44 +1,42 @@
extends Node extends Node
enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 }
enum Orientation { ROWS = 0, COLUMNS = 1 }
enum AnimationType { MULTIPLE_FILES = 0, ANIMATED = 1 }
enum AnimationDirection { FORWARD = 0, BACKWARDS = 1, PING_PONG = 2 }
enum FileFormat { PNG = 0, GIF = 1 }
# Gif exporter # Gif exporter
const GIFExporter = preload("res://addons/gdgifexporter/exporter.gd") const GIFExporter = preload("res://addons/gdgifexporter/exporter.gd")
const MedianCutQuantization = preload("res://addons/gdgifexporter/quantization/median_cut.gd") const MedianCutQuantization = preload("res://addons/gdgifexporter/quantization/median_cut.gd")
enum ExportTab { FRAME = 0, SPRITESHEET = 1, ANIMATION = 2 } var current_tab: int = ExportTab.FRAME
var current_tab : int = ExportTab.FRAME
# Frame options # Frame options
var frame_number := 0 var frame_number := 0
# All frames and their layers processed/blended into images # All frames and their layers processed/blended into images
var processed_images = [] # Image[] var processed_images = [] # Image[]
# Spritesheet options # Spritesheet options
var frame_current_tag := 0 # Export only current frame tag var frame_current_tag := 0 # Export only current frame tag
var number_of_frames := 1 var number_of_frames := 1
enum Orientation { ROWS = 0, COLUMNS = 1 } var orientation: int = Orientation.ROWS
var orientation : int = Orientation.ROWS
# How many rows/columns before new line is added
var lines_count := 1
# Animation options var lines_count := 1 # How many rows/columns before new line is added
enum AnimationType { MULTIPLE_FILES = 0, ANIMATED = 1 }
var animation_type : int = AnimationType.MULTIPLE_FILES var animation_type: int = AnimationType.MULTIPLE_FILES
enum AnimationDirection { FORWARD = 0, BACKWARDS = 1, PING_PONG = 2 } var direction: int = AnimationDirection.FORWARD
var direction : int = AnimationDirection.FORWARD
# Options # Options
var resize := 100 var resize := 100
var interpolation := 0 # Image.Interpolation var interpolation := 0 # Image.Interpolation
var new_dir_for_each_frame_tag : bool = true # you don't need to store this after export var new_dir_for_each_frame_tag: bool = true # you don't need to store this after export
# Export directory path and export file name # Export directory path and export file name
var directory_path := "" var directory_path := ""
var file_name := "untitled" var file_name := "untitled"
var file_format : int = FileFormat.PNG var file_format: int = FileFormat.PNG
enum FileFormat { PNG = 0, GIF = 1}
var was_exported : bool = false var was_exported: bool = false
# Export coroutine signal # Export coroutine signal
var stop_export = false var stop_export = false
@ -71,7 +69,9 @@ func process_frame() -> void:
processed_images.clear() processed_images.clear()
var frame = Global.current_project.frames[frame_number - 1] var frame = Global.current_project.frames[frame_number - 1]
var image := Image.new() var image := Image.new()
image.create(Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8) image.create(
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8
)
blend_layers(image, frame) blend_layers(image, frame)
processed_images.append(image) processed_images.append(image)
@ -83,7 +83,7 @@ func process_spritesheet() -> void:
if frame_current_tag > 0: if frame_current_tag > 0:
var frame_start = Global.current_project.animation_tags[frame_current_tag - 1].from var frame_start = Global.current_project.animation_tags[frame_current_tag - 1].from
var frame_end = Global.current_project.animation_tags[frame_current_tag - 1].to var frame_end = Global.current_project.animation_tags[frame_current_tag - 1].to
frames = Global.current_project.frames.slice(frame_start-1, frame_end-1, 1, true) frames = Global.current_project.frames.slice(frame_start - 1, frame_end - 1, 1, true)
else: else:
frames = Global.current_project.frames frames = Global.current_project.frames
@ -91,8 +91,16 @@ func process_spritesheet() -> void:
number_of_frames = frames.size() number_of_frames = frames.size()
# If rows mode selected calculate columns count and vice versa # If rows mode selected calculate columns count and vice versa
var spritesheet_columns = lines_count if orientation == Orientation.ROWS else frames_divided_by_spritesheet_lines() var spritesheet_columns = (
var spritesheet_rows = lines_count if orientation == Orientation.COLUMNS else frames_divided_by_spritesheet_lines() lines_count
if orientation == Orientation.ROWS
else frames_divided_by_spritesheet_lines()
)
var spritesheet_rows = (
lines_count
if orientation == Orientation.COLUMNS
else frames_divided_by_spritesheet_lines()
)
var width = Global.current_project.size.x * spritesheet_columns var width = Global.current_project.size.x * spritesheet_columns
var height = Global.current_project.size.y * spritesheet_rows var height = Global.current_project.size.y * spritesheet_rows
@ -131,12 +139,14 @@ func process_animation() -> void:
processed_images.clear() processed_images.clear()
for frame in Global.current_project.frames: for frame in Global.current_project.frames:
var image := Image.new() var image := Image.new()
image.create(Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8) image.create(
Global.current_project.size.x, Global.current_project.size.y, false, Image.FORMAT_RGBA8
)
blend_layers(image, frame) blend_layers(image, frame)
processed_images.append(image) processed_images.append(image)
func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialog ) -> bool: func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialog) -> bool:
# Stop export if directory path or file name are not valid # Stop export if directory path or file name are not valid
var dir = Directory.new() var dir = Directory.new()
if not dir.dir_exists(directory_path) or not file_name.is_valid_filename(): if not dir.dir_exists(directory_path) or not file_name.is_valid_filename():
@ -147,17 +157,25 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo
var export_paths = [] var export_paths = []
for i in range(processed_images.size()): for i in range(processed_images.size()):
stop_export = false stop_export = false
var multiple_files := true if (current_tab == ExportTab.ANIMATION and animation_type == AnimationType.MULTIPLE_FILES) else false var multiple_files := (
true
if (
current_tab == ExportTab.ANIMATION
and animation_type == AnimationType.MULTIPLE_FILES
)
else false
)
var export_path = create_export_path(multiple_files, i + 1) var export_path = create_export_path(multiple_files, i + 1)
# If user want to create new directory for each animation tag then check if directories exist and create them if not # If user want to create new directory for each animation tag then check
# if directories exist and create them if not
if multiple_files and new_dir_for_each_frame_tag: if multiple_files and new_dir_for_each_frame_tag:
var frame_tag_directory := Directory.new() var frame_tag_directory := Directory.new()
if not frame_tag_directory.dir_exists(export_path.get_base_dir()): if not frame_tag_directory.dir_exists(export_path.get_base_dir()):
frame_tag_directory.open(directory_path) frame_tag_directory.open(directory_path)
frame_tag_directory.make_dir(export_path.get_base_dir().get_file()) frame_tag_directory.make_dir(export_path.get_base_dir().get_file())
# Check if the file already exists # Check if the file already exists
var fileCheck = File.new() var file_check: File = File.new()
if fileCheck.file_exists(export_path): if file_check.file_exists(export_path):
# Ask user if he want's to overwrite the file # Ask user if he want's to overwrite the file
if not was_exported or (was_exported and not ignore_overwrites): if not was_exported or (was_exported and not ignore_overwrites):
# Overwrite existing file? # Overwrite existing file?
@ -181,11 +199,17 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo
else: else:
if gif_export_thread.is_active(): if gif_export_thread.is_active():
gif_export_thread.wait_to_finish() gif_export_thread.wait_to_finish()
gif_export_thread.start(self, "export_gif", {"export_dialog": export_dialog, "export_paths": export_paths}) gif_export_thread.start(
self, "export_gif", {"export_dialog": export_dialog, "export_paths": export_paths}
)
else: else:
for i in range(processed_images.size()): for i in range(processed_images.size()):
if OS.get_name() == "HTML5": if OS.get_name() == "HTML5":
JavaScript.download_buffer(processed_images[i].save_png_to_buffer(), export_paths[i].get_file(), "image/png") JavaScript.download_buffer(
processed_images[i].save_png_to_buffer(),
export_paths[i].get_file(),
"image/png"
)
else: else:
var err = processed_images[i].save_png(export_paths[i]) var err = processed_images[i].save_png(export_paths[i])
if err != OK: if err != OK:
@ -196,7 +220,9 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo
# Store settings for quick export and when the dialog is opened again # Store settings for quick export and when the dialog is opened again
was_exported = true was_exported = true
Global.current_project.was_exported = true Global.current_project.was_exported = true
Global.top_menu_container.file_menu.set_item_text(6, tr("Export") + " %s" % (file_name + file_format_string(file_format))) Global.top_menu_container.file_menu.set_item_text(
6, tr("Export") + " %s" % (file_name + file_format_string(file_format))
)
# Only show when not exporting gif - gif export finishes in thread # Only show when not exporting gif - gif export finishes in thread
if not (current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED): if not (current_tab == ExportTab.ANIMATION and animation_type == AnimationType.ANIMATED):
@ -206,29 +232,54 @@ func export_processed_images(ignore_overwrites: bool, export_dialog: AcceptDialo
func export_gif(args: Dictionary) -> void: func export_gif(args: Dictionary) -> void:
# Export progress popup # Export progress popup
export_progress_fraction = 100 / processed_images.size() # one fraction per each frame, one fraction for write to disk # One fraction per each frame, one fraction for write to disk
export_progress_fraction = 100 / processed_images.size()
export_progress = 0.0 export_progress = 0.0
args["export_dialog"].set_export_progress_bar(export_progress) args["export_dialog"].set_export_progress_bar(export_progress)
args["export_dialog"].toggle_export_progress_popup(true) args["export_dialog"].toggle_export_progress_popup(true)
# Export and save gif # Export and save gif
var exporter = GIFExporter.new(processed_images[0].get_width(), processed_images[0].get_height()) var exporter = GIFExporter.new(
processed_images[0].get_width(), processed_images[0].get_height()
)
match direction: match direction:
AnimationDirection.FORWARD: AnimationDirection.FORWARD:
for i in range(processed_images.size()): for i in range(processed_images.size()):
write_frame_to_gif(processed_images[i], Global.current_project.frames[i].duration * (1 / Global.current_project.fps), exporter, args["export_dialog"]) write_frame_to_gif(
processed_images[i],
Global.current_project.frames[i].duration * (1 / Global.current_project.fps),
exporter,
args["export_dialog"]
)
AnimationDirection.BACKWARDS: AnimationDirection.BACKWARDS:
for i in range(processed_images.size() - 1, -1, -1): for i in range(processed_images.size() - 1, -1, -1):
write_frame_to_gif(processed_images[i], Global.current_project.frames[i].duration * (1 / Global.current_project.fps), exporter, args["export_dialog"]) write_frame_to_gif(
processed_images[i],
Global.current_project.frames[i].duration * (1 / Global.current_project.fps),
exporter,
args["export_dialog"]
)
AnimationDirection.PING_PONG: AnimationDirection.PING_PONG:
export_progress_fraction = 100 / (processed_images.size() * 2) export_progress_fraction = 100 / (processed_images.size() * 2)
for i in range(0, processed_images.size()): for i in range(0, processed_images.size()):
write_frame_to_gif(processed_images[i], Global.current_project.frames[i].duration * (1 / Global.current_project.fps), exporter, args["export_dialog"]) write_frame_to_gif(
processed_images[i],
Global.current_project.frames[i].duration * (1 / Global.current_project.fps),
exporter,
args["export_dialog"]
)
for i in range(processed_images.size() - 2, 0, -1): for i in range(processed_images.size() - 2, 0, -1):
write_frame_to_gif(processed_images[i], Global.current_project.frames[i].duration * (1 / Global.current_project.fps), exporter, args["export_dialog"]) write_frame_to_gif(
processed_images[i],
Global.current_project.frames[i].duration * (1 / Global.current_project.fps),
exporter,
args["export_dialog"]
)
if OS.get_name() == "HTML5": if OS.get_name() == "HTML5":
JavaScript.download_buffer(exporter.export_file_data(), args["export_paths"][0], "image/gif") JavaScript.download_buffer(
exporter.export_file_data(), args["export_paths"][0], "image/gif"
)
else: else:
var file: File = File.new() var file: File = File.new()
@ -239,9 +290,9 @@ func export_gif(args: Dictionary) -> void:
Global.notification_label("File(s) exported") Global.notification_label("File(s) exported")
func write_frame_to_gif(image: Image, wait_time: float, exporter: Reference, export_dialog: Node) -> void: func write_frame_to_gif(image: Image, wait_time: float, exporter: Reference, dialog: Node) -> void:
exporter.add_frame(image, wait_time, MedianCutQuantization) exporter.add_frame(image, wait_time, MedianCutQuantization)
increase_export_progress(export_dialog) increase_export_progress(dialog)
func increase_export_progress(export_dialog: Node) -> void: func increase_export_progress(export_dialog: Node) -> void:
@ -253,17 +304,21 @@ func scale_processed_images() -> void:
for processed_image in processed_images: for processed_image in processed_images:
if resize != 100: if resize != 100:
processed_image.unlock() processed_image.unlock()
processed_image.resize(processed_image.get_size().x * resize / 100, processed_image.get_size().y * resize / 100, interpolation) processed_image.resize(
processed_image.get_size().x * resize / 100,
processed_image.get_size().y * resize / 100,
interpolation
)
func file_format_string(format_enum : int) -> String: func file_format_string(format_enum: int) -> String:
match format_enum: match format_enum:
0: # PNG 0: # PNG
return '.png' return ".png"
1: # GIF 1: # GIF
return '.gif' return ".gif"
_: _:
return '' return ""
func create_export_path(multifile: bool, frame: int = 0) -> String: func create_export_path(multifile: bool, frame: int = 0) -> String:
@ -283,7 +338,9 @@ func create_export_path(multifile: bool, frame: int = 0) -> String:
# Add frame tag if frame has one # Add frame tag if frame has one
# (frame - start_id + 1) Makes frames id to start from 1 in each frame tag directory # (frame - start_id + 1) Makes frames id to start from 1 in each frame tag directory
path += "_" + frame_tag_dir + "_" + String(frame - start_id + 1) path += "_" + frame_tag_dir + "_" + String(frame - start_id + 1)
return directory_path.plus_file(frame_tag_dir).plus_file(path + file_format_string(file_format)) return directory_path.plus_file(frame_tag_dir).plus_file(
path + file_format_string(file_format)
)
else: else:
# Add frame tag if frame has one # Add frame tag if frame has one
# (frame - start_id + 1) Makes frames id to start from 1 in each frame tag # (frame - start_id + 1) Makes frames id to start from 1 in each frame tag
@ -294,19 +351,22 @@ func create_export_path(multifile: bool, frame: int = 0) -> String:
return directory_path.plus_file(path + file_format_string(file_format)) return directory_path.plus_file(path + file_format_string(file_format))
func get_proccessed_image_animation_tag_and_start_id(processed_image_id : int) -> Array: func get_proccessed_image_animation_tag_and_start_id(processed_image_id: int) -> Array:
var result_animation_tag_and_start_id = null var result_animation_tag_and_start_id = null
for animation_tag in Global.current_project.animation_tags: for animation_tag in Global.current_project.animation_tags:
# Check if processed image is in frame tag and assign frame tag and start id if yes # Check if processed image is in frame tag and assign frame tag and start id if yes
# Then stop # Then stop
if (processed_image_id + 1) >= animation_tag.from and (processed_image_id + 1) <= animation_tag.to: if (
(processed_image_id + 1) >= animation_tag.from
and (processed_image_id + 1) <= animation_tag.to
):
result_animation_tag_and_start_id = [animation_tag.name, animation_tag.from] result_animation_tag_and_start_id = [animation_tag.name, animation_tag.from]
break break
return result_animation_tag_and_start_id return result_animation_tag_and_start_id
# Blends canvas layers into passed image starting from the origin position # Blends canvas layers into passed image starting from the origin position
func blend_layers(image : Image, frame : Frame, origin : Vector2 = Vector2(0, 0)) -> void: func blend_layers(image: Image, frame: Frame, origin: Vector2 = Vector2(0, 0)) -> void:
image.lock() image.lock()
var layer_i := 0 var layer_i := 0
for cel in frame.cels: for cel in frame.cels:
@ -314,12 +374,14 @@ func blend_layers(image : Image, frame : Frame, origin : Vector2 = Vector2(0, 0)
var cel_image := Image.new() var cel_image := Image.new()
cel_image.copy_from(cel.image) cel_image.copy_from(cel.image)
cel_image.lock() cel_image.lock()
if cel.opacity < 1: # If we have cel transparency if cel.opacity < 1: # If we have cel transparency
for xx in cel_image.get_size().x: for xx in cel_image.get_size().x:
for yy in cel_image.get_size().y: for yy in cel_image.get_size().y:
var pixel_color := cel_image.get_pixel(xx, yy) var pixel_color := cel_image.get_pixel(xx, yy)
var alpha : float = pixel_color.a * cel.opacity var alpha: float = pixel_color.a * cel.opacity
cel_image.set_pixel(xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)) cel_image.set_pixel(
xx, yy, Color(pixel_color.r, pixel_color.g, pixel_color.b, alpha)
)
image.blend_rect(cel_image, Rect2(Vector2.ZERO, Global.current_project.size), origin) image.blend_rect(cel_image, Rect2(Vector2.ZERO, Global.current_project.size), origin)
cel_image.unlock() cel_image.unlock()
layer_i += 1 layer_i += 1

View file

@ -1,25 +1,25 @@
extends Node extends Node
enum GridTypes { CARTESIAN, ISOMETRIC, ALL }
enum GridTypes {CARTESIAN, ISOMETRIC, ALL} enum PressureSensitivity { NONE, ALPHA, SIZE, ALPHA_AND_SIZE }
enum PressureSensitivity {NONE, ALPHA, SIZE, ALPHA_AND_SIZE} enum ThemeTypes { DARK, BLUE, CARAMEL, LIGHT }
enum ThemeTypes {DARK, BLUE, CARAMEL, LIGHT} enum TileMode { NONE, BOTH, X_AXIS, Y_AXIS }
enum TileMode {NONE, BOTH, X_AXIS, Y_AXIS} enum PanelLayout { AUTO, WIDESCREEN, TALLSCREEN }
enum PanelLayout {AUTO, WIDESCREEN, TALLSCREEN} enum IconColorFrom { THEME, CUSTOM }
enum IconColorFrom {THEME, CUSTOM} enum ButtonSize { SMALL, BIG }
enum ButtonSize {SMALL, BIG}
var root_directory := "." var root_directory := "."
var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()? var window_title := "" setget title_changed # Why doesn't Godot have get_window_title()?
var config_cache := ConfigFile.new() var config_cache := ConfigFile.new()
var XDGDataPaths = preload("res://src/XDGDataPaths.gd") var XDGDataPaths = preload("res://src/XDGDataPaths.gd")
var directory_module : Reference var directory_module: Reference
var projects := [] # Array of Projects var projects := [] # Array of Projects
var current_project : Project var current_project: Project
var current_project_index := 0 setget project_changed var current_project_index := 0 setget project_changed
var panel_layout = PanelLayout.AUTO var panel_layout = PanelLayout.AUTO
var ui_tooltips := {}
# Canvas related stuff # Canvas related stuff
var layers_changed_skip := false var layers_changed_skip := false
@ -38,11 +38,11 @@ var smooth_zoom := true
var shrink := 1.0 var shrink := 1.0
var dim_on_popup := true var dim_on_popup := true
var theme_type : int = ThemeTypes.DARK var theme_type: int = ThemeTypes.DARK
var modulate_icon_color := Color.gray var modulate_icon_color := Color.gray
var icon_color_from : int = IconColorFrom.THEME var icon_color_from: int = IconColorFrom.THEME
var custom_icon_color := Color.gray var custom_icon_color := Color.gray
var tool_button_size : int = ButtonSize.SMALL var tool_button_size: int = ButtonSize.SMALL
var default_image_width := 64 var default_image_width := 64
var default_image_height := 64 var default_image_height := 64
@ -56,7 +56,7 @@ var grid_offset_x := 0
var grid_offset_y := 0 var grid_offset_y := 0
var grid_draw_over_tile_mode := false var grid_draw_over_tile_mode := false
var grid_color := Color.black var grid_color := Color.black
var pixel_grid_show_at_zoom := 1500.0 # percentage var pixel_grid_show_at_zoom := 1500.0 # percentage
var pixel_grid_color := Color("91212121") var pixel_grid_color := Color("91212121")
var guide_color := Color.purple var guide_color := Color.purple
var checker_size := 10 var checker_size := 10
@ -103,67 +103,69 @@ var palettes := {}
# Nodes # Nodes
var notification_label_node = preload("res://src/UI/NotificationLabel.tscn") var notification_label_node = preload("res://src/UI/NotificationLabel.tscn")
onready var root : Node = get_tree().get_root() onready var root: Node = get_tree().get_root()
onready var control : Node = root.get_node("Control") onready var control: Node = root.get_node("Control")
onready var left_cursor : Sprite = control.find_node("LeftCursor") onready var left_cursor: Sprite = control.find_node("LeftCursor")
onready var right_cursor : Sprite = control.find_node("RightCursor") onready var right_cursor: Sprite = control.find_node("RightCursor")
onready var canvas : Canvas = control.find_node("Canvas") onready var canvas: Canvas = control.find_node("Canvas")
onready var tabs : Tabs = control.find_node("Tabs") onready var tabs: Tabs = control.find_node("Tabs")
onready var main_viewport : ViewportContainer = control.find_node("ViewportContainer") onready var main_viewport: ViewportContainer = control.find_node("ViewportContainer")
onready var second_viewport : ViewportContainer = control.find_node("ViewportContainer2") onready var second_viewport: ViewportContainer = control.find_node("ViewportContainer2")
onready var canvas_preview_container : Container = control.find_node("CanvasPreviewContainer") onready var canvas_preview_container: Container = control.find_node("CanvasPreviewContainer")
onready var small_preview_viewport : ViewportContainer = canvas_preview_container.find_node("PreviewViewportContainer") onready var small_preview_viewport: ViewportContainer = canvas_preview_container.find_node(
onready var camera : Camera2D = main_viewport.find_node("Camera2D") "PreviewViewportContainer"
onready var camera2 : Camera2D = control.find_node("Camera2D2") )
onready var camera_preview : Camera2D = control.find_node("CameraPreview") onready var camera: Camera2D = main_viewport.find_node("Camera2D")
onready var camera2: Camera2D = control.find_node("Camera2D2")
onready var camera_preview: Camera2D = control.find_node("CameraPreview")
onready var cameras = [Global.camera, Global.camera2, Global.camera_preview] onready var cameras = [Global.camera, Global.camera2, Global.camera_preview]
onready var horizontal_ruler : BaseButton = control.find_node("HorizontalRuler") onready var horizontal_ruler: BaseButton = control.find_node("HorizontalRuler")
onready var vertical_ruler : BaseButton = control.find_node("VerticalRuler") onready var vertical_ruler: BaseButton = control.find_node("VerticalRuler")
onready var transparent_checker : ColorRect = control.find_node("TransparentChecker") onready var transparent_checker: ColorRect = control.find_node("TransparentChecker")
onready var preview_zoom_slider : VSlider = control.find_node("PreviewZoomSlider") onready var preview_zoom_slider: VSlider = control.find_node("PreviewZoomSlider")
onready var tool_panel : Panel = control.find_node("ToolPanel") onready var tool_panel: Panel = control.find_node("ToolPanel")
onready var right_panel : Panel = control.find_node("RightPanel") onready var right_panel: Panel = control.find_node("RightPanel")
onready var brushes_popup : Popup = control.find_node("BrushesPopup") onready var brushes_popup: Popup = control.find_node("BrushesPopup")
onready var patterns_popup : Popup = control.find_node("PatternsPopup") onready var patterns_popup: Popup = control.find_node("PatternsPopup")
onready var palette_panel : PalettePanel = control.find_node("PalettePanel") onready var palette_panel: PalettePanel = control.find_node("PalettePanel")
onready var top_menu_container : Panel = control.find_node("TopMenuContainer") onready var top_menu_container: Panel = control.find_node("TopMenuContainer")
onready var rotation_level_button : Button = control.find_node("RotationLevel") onready var rotation_level_button: Button = control.find_node("RotationLevel")
onready var rotation_level_spinbox : SpinBox = control.find_node("RotationSpinbox") onready var rotation_level_spinbox: SpinBox = control.find_node("RotationSpinbox")
onready var zoom_level_button : Button = control.find_node("ZoomLevel") onready var zoom_level_button: Button = control.find_node("ZoomLevel")
onready var zoom_level_spinbox : SpinBox = control.find_node("ZoomSpinbox") onready var zoom_level_spinbox: SpinBox = control.find_node("ZoomSpinbox")
onready var cursor_position_label : Label = control.find_node("CursorPosition") onready var cursor_position_label: Label = control.find_node("CursorPosition")
onready var current_frame_mark_label : Label = control.find_node("CurrentFrameMark") onready var current_frame_mark_label: Label = control.find_node("CurrentFrameMark")
onready var animation_timeline : Panel = control.find_node("AnimationTimeline") onready var animation_timeline: Panel = control.find_node("AnimationTimeline")
onready var animation_timer : Timer = animation_timeline.find_node("AnimationTimer") onready var animation_timer: Timer = animation_timeline.find_node("AnimationTimer")
onready var frame_ids : HBoxContainer = animation_timeline.find_node("FrameIDs") onready var frame_ids: HBoxContainer = animation_timeline.find_node("FrameIDs")
onready var play_forward : BaseButton = animation_timeline.find_node("PlayForward") onready var play_forward: BaseButton = animation_timeline.find_node("PlayForward")
onready var play_backwards : BaseButton = animation_timeline.find_node("PlayBackwards") onready var play_backwards: BaseButton = animation_timeline.find_node("PlayBackwards")
onready var layers_container : VBoxContainer = animation_timeline.find_node("LayersContainer") onready var layers_container: VBoxContainer = animation_timeline.find_node("LayersContainer")
onready var frames_container : VBoxContainer = animation_timeline.find_node("FramesContainer") onready var frames_container: VBoxContainer = animation_timeline.find_node("FramesContainer")
onready var tag_container : Control = animation_timeline.find_node("TagContainer") onready var tag_container: Control = animation_timeline.find_node("TagContainer")
onready var remove_frame_button : BaseButton = animation_timeline.find_node("DeleteFrame") onready var remove_frame_button: BaseButton = animation_timeline.find_node("DeleteFrame")
onready var move_left_frame_button : BaseButton = animation_timeline.find_node("MoveLeft") onready var move_left_frame_button: BaseButton = animation_timeline.find_node("MoveLeft")
onready var move_right_frame_button : BaseButton = animation_timeline.find_node("MoveRight") onready var move_right_frame_button: BaseButton = animation_timeline.find_node("MoveRight")
onready var remove_layer_button : BaseButton = animation_timeline.find_node("RemoveLayer") onready var remove_layer_button: BaseButton = animation_timeline.find_node("RemoveLayer")
onready var move_up_layer_button : BaseButton = animation_timeline.find_node("MoveUpLayer") onready var move_up_layer_button: BaseButton = animation_timeline.find_node("MoveUpLayer")
onready var move_down_layer_button : BaseButton = animation_timeline.find_node("MoveDownLayer") onready var move_down_layer_button: BaseButton = animation_timeline.find_node("MoveDownLayer")
onready var merge_down_layer_button : BaseButton = animation_timeline.find_node("MergeDownLayer") onready var merge_down_layer_button: BaseButton = animation_timeline.find_node("MergeDownLayer")
onready var layer_opacity_slider : HSlider = animation_timeline.find_node("OpacitySlider") onready var layer_opacity_slider: HSlider = animation_timeline.find_node("OpacitySlider")
onready var layer_opacity_spinbox : SpinBox = animation_timeline.find_node("OpacitySpinBox") onready var layer_opacity_spinbox: SpinBox = animation_timeline.find_node("OpacitySpinBox")
onready var open_sprites_dialog : FileDialog = control.find_node("OpenSprite") onready var open_sprites_dialog: FileDialog = control.find_node("OpenSprite")
onready var save_sprites_dialog : FileDialog = control.find_node("SaveSprite") onready var save_sprites_dialog: FileDialog = control.find_node("SaveSprite")
onready var save_sprites_html5_dialog : ConfirmationDialog = control.find_node("SaveSpriteHTML5") onready var save_sprites_html5_dialog: ConfirmationDialog = control.find_node("SaveSpriteHTML5")
onready var export_dialog : AcceptDialog = control.find_node("ExportDialog") onready var export_dialog: AcceptDialog = control.find_node("ExportDialog")
onready var preferences_dialog : AcceptDialog = control.find_node("PreferencesDialog") onready var preferences_dialog: AcceptDialog = control.find_node("PreferencesDialog")
onready var error_dialog : AcceptDialog = control.find_node("ErrorDialog") onready var error_dialog: AcceptDialog = control.find_node("ErrorDialog")
onready var quit_and_save_dialog : ConfirmationDialog = control.find_node("QuitAndSaveDialog") onready var quit_and_save_dialog: ConfirmationDialog = control.find_node("QuitAndSaveDialog")
onready var current_version : String = ProjectSettings.get_setting("application/config/Version") onready var current_version: String = ProjectSettings.get_setting("application/config/Version")
func _ready() -> void: func _ready() -> void:
@ -180,34 +182,48 @@ func _ready() -> void:
projects.append(Project.new()) projects.append(Project.new())
projects[0].layers.append(Layer.new()) projects[0].layers.append(Layer.new())
current_project = projects[0] current_project = projects[0]
for node in get_tree().get_nodes_in_group("UIButtons"):
var tooltip: String = node.hint_tooltip
if !tooltip.empty() and node.shortcut:
ui_tooltips[node] = tooltip
func notification_label(text : String) -> void: func notification_label(text: String) -> void:
var notification : Label = notification_label_node.instance() var notification: Label = notification_label_node.instance()
notification.text = tr(text) notification.text = tr(text)
notification.rect_position = Vector2(70, animation_timeline.rect_position.y) notification.rect_position = Vector2(70, animation_timeline.rect_position.y)
notification.theme = control.theme notification.theme = control.theme
get_tree().get_root().add_child(notification) get_tree().get_root().add_child(notification)
func general_undo(project : Project = current_project) -> void: func general_undo(project: Project = current_project) -> void:
project.undos -= 1 project.undos -= 1
var action_name : String = project.undo_redo.get_current_action_name() var action_name: String = project.undo_redo.get_current_action_name()
notification_label("Undo: %s" % action_name) notification_label("Undo: %s" % action_name)
func general_redo(project : Project = current_project) -> void: func general_redo(project: Project = current_project) -> void:
if project.undos < project.undo_redo.get_version(): # If we did undo and then redo if project.undos < project.undo_redo.get_version(): # If we did undo and then redo
project.undos = project.undo_redo.get_version() project.undos = project.undo_redo.get_version()
if control.redone: if control.redone:
var action_name : String = project.undo_redo.get_current_action_name() var action_name: String = project.undo_redo.get_current_action_name()
notification_label("Redo: %s" % action_name) notification_label("Redo: %s" % action_name)
func undo(_frame_index := -1, _layer_index := -1, project : Project = current_project) -> void: func undo(_frame_index := -1, _layer_index := -1, project: Project = current_project) -> void:
general_undo(project) general_undo(project)
var action_name : String = project.undo_redo.get_current_action_name() var action_name: String = project.undo_redo.get_current_action_name()
if action_name == "Draw" or action_name == "Draw Shape" or action_name == "Rectangle Select" or action_name == "Move Selection" or action_name == "Scale" or action_name == "Centralize" or action_name == "Merge Layer" or action_name == "Link Cel" or action_name == "Unlink Cel": if (
action_name == "Draw"
or action_name == "Draw Shape"
or action_name == "Rectangle Select"
or action_name == "Move Selection"
or action_name == "Scale"
or action_name == "Centralize"
or action_name == "Merge Layer"
or action_name == "Link Cel"
or action_name == "Unlink Cel"
):
if _layer_index > -1 and _frame_index > -1: if _layer_index > -1 and _frame_index > -1:
canvas.update_texture(_layer_index, _frame_index, project) canvas.update_texture(_layer_index, _frame_index, project)
else: else:
@ -224,13 +240,13 @@ func undo(_frame_index := -1, _layer_index := -1, project : Project = current_pr
elif "Frame" in action_name: elif "Frame" in action_name:
# This actually means that frames.size is one, but it hasn't been updated yet # This actually means that frames.size is one, but it hasn't been updated yet
if project.frames.size() == 2: # Stop animating if project.frames.size() == 2: # Stop animating
play_forward.pressed = false play_forward.pressed = false
play_backwards.pressed = false play_backwards.pressed = false
animation_timer.stop() animation_timer.stop()
elif "Move Cels" == action_name: elif "Move Cels" == action_name:
project.frames = project.frames # to call frames_changed project.frames = project.frames # to call frames_changed
canvas.update() canvas.update()
if !project.has_changed: if !project.has_changed:
@ -239,10 +255,20 @@ func undo(_frame_index := -1, _layer_index := -1, project : Project = current_pr
self.window_title = window_title + "(*)" self.window_title = window_title + "(*)"
func redo(_frame_index := -1, _layer_index := -1, project : Project = current_project) -> void: func redo(_frame_index := -1, _layer_index := -1, project: Project = current_project) -> void:
general_redo(project) general_redo(project)
var action_name : String = project.undo_redo.get_current_action_name() var action_name: String = project.undo_redo.get_current_action_name()
if action_name == "Draw" or action_name == "Draw Shape" or action_name == "Rectangle Select" or action_name == "Move Selection" or action_name == "Scale" or action_name == "Centralize" or action_name == "Merge Layer" or action_name == "Link Cel" or action_name == "Unlink Cel": if (
action_name == "Draw"
or action_name == "Draw Shape"
or action_name == "Rectangle Select"
or action_name == "Move Selection"
or action_name == "Scale"
or action_name == "Centralize"
or action_name == "Merge Layer"
or action_name == "Link Cel"
or action_name == "Unlink Cel"
):
if _layer_index > -1 and _frame_index > -1: if _layer_index > -1 and _frame_index > -1:
canvas.update_texture(_layer_index, _frame_index, project) canvas.update_texture(_layer_index, _frame_index, project)
else: else:
@ -258,13 +284,13 @@ func redo(_frame_index := -1, _layer_index := -1, project : Project = current_pr
cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y] cursor_position_label.text = "[%s×%s]" % [project.size.x, project.size.y]
elif "Frame" in action_name: elif "Frame" in action_name:
if project.frames.size() == 1: # Stop animating if project.frames.size() == 1: # Stop animating
play_forward.pressed = false play_forward.pressed = false
play_backwards.pressed = false play_backwards.pressed = false
animation_timer.stop() animation_timer.stop()
elif "Move Cels" == action_name: elif "Move Cels" == action_name:
project.frames = project.frames # to call frames_changed project.frames = project.frames # to call frames_changed
canvas.update() canvas.update()
if !project.has_changed: if !project.has_changed:
@ -273,31 +299,47 @@ func redo(_frame_index := -1, _layer_index := -1, project : Project = current_pr
self.window_title = window_title + "(*)" self.window_title = window_title + "(*)"
func title_changed(value : String) -> void: func title_changed(value: String) -> void:
window_title = value window_title = value
OS.set_window_title(value) OS.set_window_title(value)
func project_changed(value : int) -> void: func project_changed(value: int) -> void:
canvas.selection.transform_content_confirm() canvas.selection.transform_content_confirm()
current_project_index = value current_project_index = value
current_project = projects[value] current_project = projects[value]
current_project.change_project() current_project.change_project()
func dialog_open(open : bool) -> void: func dialog_open(open: bool) -> void:
if open: if open:
can_draw = false can_draw = false
if dim_on_popup: if dim_on_popup:
control.get_node("ModulateTween").interpolate_property(control, "modulate", control.modulate, Color(0.5, 0.5, 0.5), 0.1, Tween.TRANS_LINEAR, Tween.EASE_OUT) control.get_node("ModulateTween").interpolate_property(
control,
"modulate",
control.modulate,
Color(0.5, 0.5, 0.5),
0.1,
Tween.TRANS_LINEAR,
Tween.EASE_OUT
)
else: else:
can_draw = true can_draw = true
control.get_node("ModulateTween").interpolate_property(control, "modulate", control.modulate, Color.white, 0.1, Tween.TRANS_LINEAR, Tween.EASE_OUT) control.get_node("ModulateTween").interpolate_property(
control,
"modulate",
control.modulate,
Color.white,
0.1,
Tween.TRANS_LINEAR,
Tween.EASE_OUT
)
control.get_node("ModulateTween").start() control.get_node("ModulateTween").start()
func disable_button(button : BaseButton, disable : bool) -> void: func disable_button(button: BaseButton, disable: bool) -> void:
button.disabled = disable button.disabled = disable
if disable: if disable:
button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN button.mouse_default_cursor_shape = Control.CURSOR_FORBIDDEN
@ -314,167 +356,19 @@ func disable_button(button : BaseButton, disable : bool) -> void:
break break
func change_button_texturerect(texture_button : TextureRect, new_file_name : String) -> void: func change_button_texturerect(texture_button: TextureRect, new_file_name: String) -> void:
var file_name := texture_button.texture.resource_path.get_basename().get_file() var file_name := texture_button.texture.resource_path.get_basename().get_file()
var directory_path := texture_button.texture.resource_path.get_basename().replace(file_name, "") var directory_path := texture_button.texture.resource_path.get_basename().replace(file_name, "")
texture_button.texture = load(directory_path.plus_file(new_file_name)) texture_button.texture = load(directory_path.plus_file(new_file_name))
func update_hint_tooltips() -> void: func update_hint_tooltips() -> void:
var tool_buttons = control.find_node("ToolButtons") var tool_buttons: Container = control.find_node("ToolButtons")
tool_buttons.update_hintooltips()
var rect_select : BaseButton = tool_buttons.find_node("RectSelect") for tip in ui_tooltips:
rect_select.hint_tooltip = tr("""Rectangular Selection tip.hint_tooltip = tr(ui_tooltips[tip]) % tip.shortcut.get_as_text()
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_rectangle_select_tool")[0].as_text(), InputMap.get_action_list("right_rectangle_select_tool")[0].as_text()]
var ellipse_select : BaseButton = tool_buttons.find_node("EllipseSelect")
ellipse_select.hint_tooltip = tr("""Elliptical Selection
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_ellipse_select_tool")[0].as_text(), InputMap.get_action_list("right_ellipse_select_tool")[0].as_text()]
var polygon_select : BaseButton = tool_buttons.find_node("PolygonSelect") func is_cjk(locale: String) -> bool:
polygon_select.hint_tooltip = tr("""Polygonal Selection
Double-click to connect the last point to the starting point
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_polygon_select_tool")[0].as_text(), InputMap.get_action_list("right_polygon_select_tool")[0].as_text()]
var color_select : BaseButton = tool_buttons.find_node("ColorSelect")
color_select.hint_tooltip = tr("""Select By Color
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_color_select_tool")[0].as_text(), InputMap.get_action_list("right_color_select_tool")[0].as_text()]
var magic_wand : BaseButton = tool_buttons.find_node("MagicWand")
magic_wand.hint_tooltip = tr("""Magic Wand
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_magic_wand_tool")[0].as_text(), InputMap.get_action_list("right_magic_wand_tool")[0].as_text()]
var lasso : BaseButton = tool_buttons.find_node("Lasso")
lasso.hint_tooltip = tr("""Lasso / Free Select Tool
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_lasso_tool")[0].as_text(), InputMap.get_action_list("right_lasso_tool")[0].as_text()]
var move_select : BaseButton = tool_buttons.find_node("Move")
move_select.hint_tooltip = tr("""Move
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_move_tool")[0].as_text(), InputMap.get_action_list("right_move_tool")[0].as_text()]
var zoom_tool : BaseButton = tool_buttons.find_node("Zoom")
zoom_tool.hint_tooltip = tr("""Zoom
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_zoom_tool")[0].as_text(), InputMap.get_action_list("right_zoom_tool")[0].as_text()]
var pan_tool : BaseButton = tool_buttons.find_node("Pan")
pan_tool.hint_tooltip = tr("""Pan
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_pan_tool")[0].as_text(), InputMap.get_action_list("right_pan_tool")[0].as_text()]
var color_picker : BaseButton = tool_buttons.find_node("ColorPicker")
color_picker.hint_tooltip = tr("""Color Picker
Select a color from a pixel of the sprite
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_colorpicker_tool")[0].as_text(), InputMap.get_action_list("right_colorpicker_tool")[0].as_text()]
var pencil : BaseButton = tool_buttons.find_node("Pencil")
pencil.hint_tooltip = tr("""Pencil
%s for left mouse button
%s for right mouse button
Hold %s to make a line""") % [InputMap.get_action_list("left_pencil_tool")[0].as_text(), InputMap.get_action_list("right_pencil_tool")[0].as_text(), "Shift"]
var eraser : BaseButton = tool_buttons.find_node("Eraser")
eraser.hint_tooltip = tr("""Eraser
%s for left mouse button
%s for right mouse button
Hold %s to make a line""") % [InputMap.get_action_list("left_eraser_tool")[0].as_text(), InputMap.get_action_list("right_eraser_tool")[0].as_text(), "Shift"]
var bucket : BaseButton = tool_buttons.find_node("Bucket")
bucket.hint_tooltip = tr("""Bucket
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_fill_tool")[0].as_text(), InputMap.get_action_list("right_fill_tool")[0].as_text()]
var ld : BaseButton = tool_buttons.find_node("Shading")
ld.hint_tooltip = tr("""Shading Tool
%s for left mouse button
%s for right mouse button""") % [InputMap.get_action_list("left_shading_tool")[0].as_text(), InputMap.get_action_list("right_shading_tool")[0].as_text()]
var linetool : BaseButton = tool_buttons.find_node("LineTool")
linetool.hint_tooltip = tr("""Line Tool
%s for left mouse button
%s for right mouse button
Hold %s to snap the angle of the line
Hold %s to center the shape on the click origin
Hold %s to displace the shape's origin""") % [InputMap.get_action_list("left_linetool_tool")[0].as_text(), InputMap.get_action_list("right_linetool_tool")[0].as_text(), "Shift", "Ctrl", "Alt"]
var recttool : BaseButton = tool_buttons.find_node("RectangleTool")
recttool.hint_tooltip = tr("""Rectangle Tool
%s for left mouse button
%s for right mouse button
Hold %s to create a 1:1 shape
Hold %s to center the shape on the click origin
Hold %s to displace the shape's origin""") % [InputMap.get_action_list("left_rectangletool_tool")[0].as_text(), InputMap.get_action_list("right_rectangletool_tool")[0].as_text(), "Shift", "Ctrl", "Alt"]
var ellipsetool : BaseButton = tool_buttons.find_node("EllipseTool")
ellipsetool.hint_tooltip = tr("""Ellipse Tool
%s for left mouse button
%s for right mouse button
Hold %s to create a 1:1 shape
Hold %s to center the shape on the click origin
Hold %s to displace the shape's origin""") % [InputMap.get_action_list("left_ellipsetool_tool")[0].as_text(), InputMap.get_action_list("right_ellipsetool_tool")[0].as_text(), "Shift", "Ctrl", "Alt"]
var color_switch : BaseButton = control.find_node("ColorSwitch")
color_switch.hint_tooltip = tr("""Switch left and right colors
(%s)""") % InputMap.get_action_list("switch_colors")[0].as_text()
var first_frame : BaseButton = control.find_node("FirstFrame")
first_frame.hint_tooltip = tr("""Jump to the first frame
(%s)""") % InputMap.get_action_list("go_to_first_frame")[0].as_text()
var previous_frame : BaseButton = control.find_node("PreviousFrame")
previous_frame.hint_tooltip = tr("""Go to the previous frame
(%s)""") % InputMap.get_action_list("go_to_previous_frame")[0].as_text()
play_backwards.hint_tooltip = tr("""Play the animation backwards (from end to beginning)
(%s)""") % InputMap.get_action_list("play_backwards")[0].as_text()
play_forward.hint_tooltip = tr("""Play the animation forward (from beginning to end)
(%s)""") % InputMap.get_action_list("play_forward")[0].as_text()
var next_frame : BaseButton = control.find_node("NextFrame")
next_frame.hint_tooltip = tr("""Go to the next frame
(%s)""") % InputMap.get_action_list("go_to_next_frame")[0].as_text()
var last_frame : BaseButton = control.find_node("LastFrame")
last_frame.hint_tooltip = tr("""Jump to the last frame
(%s)""") % InputMap.get_action_list("go_to_last_frame")[0].as_text()
func is_cjk(locale : String) -> bool:
return "zh" in locale or "ko" in locale or "ja" in locale return "zh" in locale or "ko" in locale or "ja" in locale

Some files were not shown because too many files have changed in this diff Show more