mirror of
https://github.com/Relintai/GraphicsEditor.git
synced 2024-11-12 08:15:17 +01:00
First commit!
This commit is contained in:
parent
0a82366f7b
commit
5168ed8193
14
.gitignore
vendored
Normal file
14
.gitignore
vendored
Normal file
@ -0,0 +1,14 @@
|
||||
\exports/
|
||||
\.import/
|
||||
|
||||
addons/scene_notes/
|
||||
|
||||
addons/todo/
|
||||
|
||||
scene-notes\.ini
|
||||
|
||||
todo\.cache\.ini
|
||||
|
||||
todo\.config\.ini
|
||||
|
||||
export_presets\.cfg
|
16
README.md
16
README.md
@ -1 +1,17 @@
|
||||
GraphicsEditor
|
||||
|
||||
Made by Flairieve!
|
||||
|
||||
This plugin was built in Godot v3.1 and is currently in alpha so it doesn't work fully and it's not finished!
|
||||
|
||||
Right now it can create basic images in a 100x100 resolution.
|
||||
It is using a chunk system to keep rendering optmized!
|
||||
|
||||
Stuff that's still WIP and are not finished:
|
||||
The bucket tool lags and the selection tool doesn't work at all!
|
||||
The way in which the program saves temporary data doesn't do it in chunks yet!
|
||||
There is no custom color selection tool yet so the color picker doesn't work on it.
|
||||
All chunks are always rendered which causes lag when there is more chunks.
|
||||
There is no way to change the resolution of the image.
|
||||
Images can only save in the PNG format.
|
||||
You can't zoom in and out on the image! Either a Camera2D can be used or every control node can be scaled!
|
8
addons/graphics_editor/Brush.gd
Normal file
8
addons/graphics_editor/Brush.gd
Normal file
@ -0,0 +1,8 @@
|
||||
extends Node
|
||||
|
||||
func _ready():
|
||||
print("test")
|
||||
pass
|
||||
|
||||
func draw_pixel():
|
||||
print("Drawed pixel!")
|
23
addons/graphics_editor/CanvasOutline.gd
Normal file
23
addons/graphics_editor/CanvasOutline.gd
Normal file
@ -0,0 +1,23 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
export var color = Color()
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _draw():
|
||||
draw_outline_box(self.rect_size, color, 3)
|
||||
|
||||
func draw_outline_box(size, color, width):
|
||||
#Top line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(size.x, 0), color, width)
|
||||
#Left line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(0, size.y), color, width)
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1, size.y), Vector2(size.x, size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(size.x, 0), Vector2(size.x, size.y), color, width)
|
||||
|
||||
func _process(delta):
|
||||
update()
|
219
addons/graphics_editor/Editor.gd
Normal file
219
addons/graphics_editor/Editor.gd
Normal file
@ -0,0 +1,219 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
onready var paint_canvas_container_node = get_node("PaintCanvasContainer")
|
||||
onready var paint_canvas_node = paint_canvas_container_node.get_node("PaintCanvas")
|
||||
onready var grids_node = paint_canvas_node.get_node("Grids")
|
||||
var selected_color = Color(1, 1, 1, 1)
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
onready var textinfo = get_node("BottomPanel/TextInfo")
|
||||
onready var grid_size = paint_canvas_node.grid_size
|
||||
onready var region_size = paint_canvas_node.region_size
|
||||
var allow_drawing = true
|
||||
|
||||
func _ready():
|
||||
#---------------------------
|
||||
#Setup the info bottom panel
|
||||
#---------------------------
|
||||
add_text_info_variables()
|
||||
|
||||
#--------------------
|
||||
#Setup the layer tree
|
||||
#--------------------
|
||||
setup_layer_tree()
|
||||
|
||||
#------------------
|
||||
#Setup visual grids
|
||||
#------------------
|
||||
for i in grids_node.get_children():
|
||||
i.rect_size = Vector2(paint_canvas_node.canvas_size.x * grid_size, paint_canvas_node.canvas_size.y * grid_size)
|
||||
grids_node.get_node("VisualGrid").size = grid_size
|
||||
grids_node.get_node("VisualGrid2").size = grid_size * region_size
|
||||
|
||||
#-----------------------------------
|
||||
#Setup canvas node size and position
|
||||
#-----------------------------------
|
||||
paint_canvas_node.rect_size = Vector2(paint_canvas_node.canvas_size.x * grid_size, paint_canvas_node.canvas_size.y * grid_size)
|
||||
paint_canvas_node.rect_min_size = Vector2(paint_canvas_node.canvas_size.x * grid_size, paint_canvas_node.canvas_size.y * grid_size)
|
||||
|
||||
#------------------------------------------------------------
|
||||
#Set the selected color to what the color picker has selected
|
||||
#------------------------------------------------------------
|
||||
selected_color = get_node("ToolMenu/Buttons/ColorPicker").color
|
||||
|
||||
#----------------------------------------------------------------
|
||||
#Setup is done so we can now allow the user to draw on the canvas
|
||||
#----------------------------------------------------------------
|
||||
paint_canvas_node.can_draw = true
|
||||
|
||||
func setup_layer_tree():
|
||||
var tree = get_node("ToolMenu/Layers/Tree")
|
||||
var root = tree.create_item()
|
||||
tree.set_hide_root(true)
|
||||
var child1 = tree.create_item(root)
|
||||
child1.set_text(0, "Layers")
|
||||
child1.set_editable(0, true)
|
||||
for i in paint_canvas_node.layers:
|
||||
var layer_name = i.name
|
||||
var subchild = tree.create_item(child1)
|
||||
subchild.set_text(0, layer_name)
|
||||
subchild.set_editable(0, true)
|
||||
|
||||
func _thread_process():
|
||||
pass
|
||||
|
||||
var brush_mode = "paint"
|
||||
|
||||
var mouse_position = Vector2()
|
||||
var canvas_position = Vector2()
|
||||
var canvas_mouse_position = Vector2()
|
||||
var cell_mouse_position = Vector2()
|
||||
var cell_region_position = Vector2()
|
||||
var cell_position_in_region = Vector2()
|
||||
var cell_color = Color()
|
||||
|
||||
var last_mouse_position = Vector2()
|
||||
var last_canvas_position = Vector2()
|
||||
var last_canvas_mouse_position = Vector2()
|
||||
var last_cell_mouse_position = Vector2()
|
||||
var last_cell_color = Color()
|
||||
|
||||
# warning-ignore:unused_argument
|
||||
func _process(delta):
|
||||
#It's a lot more easier to just keep updating the variables in here than just have a bunch of local variables
|
||||
#in every update function and make it very messy
|
||||
if paint_canvas_node == null:
|
||||
set_process(false)
|
||||
return
|
||||
|
||||
#Update commonly used variables
|
||||
grid_size = paint_canvas_node.grid_size
|
||||
region_size = paint_canvas_node.region_size
|
||||
mouse_position = get_local_mouse_position()
|
||||
canvas_position = paint_canvas_node.rect_position + paint_canvas_container_node.rect_position
|
||||
canvas_mouse_position = Vector2(mouse_position.x - canvas_position.x, mouse_position.y - canvas_position.y)
|
||||
cell_mouse_position = Vector2(floor(canvas_mouse_position.x / grid_size), floor(canvas_mouse_position.y / grid_size))
|
||||
cell_region_position = Vector2(floor(cell_mouse_position.x / region_size), floor(cell_mouse_position.y / region_size))
|
||||
cell_position_in_region = paint_canvas_node.get_region_from_cell(cell_mouse_position.x, cell_mouse_position.y)
|
||||
cell_color = paint_canvas_node.get_pixel_cell_color(cell_mouse_position.x, cell_mouse_position.y)
|
||||
|
||||
#Process the brush drawing stuff
|
||||
if paint_canvas_container_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
brush_process()
|
||||
|
||||
#Render the highlighting stuff
|
||||
update()
|
||||
|
||||
#Canvas Shift Moving
|
||||
if not mouse_position == last_mouse_position:
|
||||
if paint_canvas_container_node.has_focus():
|
||||
if Input.is_key_pressed(KEY_SHIFT):
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
var relative = mouse_position - last_mouse_position
|
||||
paint_canvas_node.rect_position += relative
|
||||
allow_drawing = false
|
||||
else:
|
||||
allow_drawing = true
|
||||
|
||||
#Update text info
|
||||
update_text_info()
|
||||
|
||||
#Update last variables with the current variables
|
||||
last_mouse_position = mouse_position
|
||||
last_canvas_position = canvas_position
|
||||
last_canvas_mouse_position = canvas_mouse_position
|
||||
last_cell_mouse_position = cell_mouse_position
|
||||
last_cell_color = cell_color
|
||||
|
||||
var currently_selecting = false
|
||||
func _draw():
|
||||
if paint_canvas_node == null:
|
||||
return
|
||||
if paint_canvas_container_node.mouse_in_region and paint_canvas_node.mouse_in_region:
|
||||
#draw cell_mouse_position
|
||||
if paint_canvas_node.cell_in_canvas_region(cell_mouse_position.x, cell_mouse_position.y):
|
||||
draw_rect(Rect2(Vector2((cell_mouse_position.x * grid_size) + canvas_position.x, (cell_mouse_position.y * grid_size) + canvas_position.y), Vector2(grid_size, grid_size)), Color(0.8, 0.8, 0.8, 0.8), true)
|
||||
|
||||
func draw_outline_box(pos, size, color, width):
|
||||
#Top line
|
||||
draw_line(Vector2(0 + 1 + pos.x, 0 + pos.y), Vector2(pos.x + size.x, 0 + pos.y), color, width)
|
||||
#Left line
|
||||
draw_line(Vector2(0 + 1 + pos.x, 0 + pos.y), Vector2(0 + pos.x, pos.y + size.y), color, width)
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1 + pos.x, pos.y + size.y), Vector2(pos.x + size.x, pos.y + size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(pos.x + size.x, 0 + pos.y), Vector2(pos.x + size.x, pos.y + size.y), color, width)
|
||||
|
||||
func pool_vector2_array_append_new_value(vec2array, vec2):
|
||||
for i in vec2array:
|
||||
if i == vec2:
|
||||
return
|
||||
vec2array.append(vec2)
|
||||
|
||||
func custom_rect_size_brush(x, y, color, size):
|
||||
for cx in range(x, x + size):
|
||||
for cy in range(y, y + size):
|
||||
paint_canvas_node.set_pixel_cell(cx, cy, color)
|
||||
pass
|
||||
|
||||
func brush_process():
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT):
|
||||
if allow_drawing:
|
||||
if brush_mode == "paint":
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, selected_color)
|
||||
if brush_mode == "bucket":
|
||||
paint_canvas_node.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, selected_color)
|
||||
if brush_mode == "rainbow":
|
||||
paint_canvas_node.set_random_pixels_from_line(cell_mouse_position, last_cell_mouse_position)
|
||||
elif Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
if allow_drawing:
|
||||
if brush_mode == "paint" or brush_mode == "rainbow":
|
||||
paint_canvas_node.set_pixels_from_line(cell_mouse_position, last_cell_mouse_position, Color(0, 0, 0, 0))
|
||||
if brush_mode == "bucket":
|
||||
paint_canvas_node.flood_fill(cell_mouse_position.x, cell_mouse_position.y, cell_color, Color(0, 0, 0, 0))
|
||||
|
||||
func add_text_info_variables():
|
||||
textinfo.add_text_info("FPS")
|
||||
textinfo.add_text_info("Mouse Position")
|
||||
textinfo.add_text_info("Canvas Mouse Position")
|
||||
textinfo.add_text_info("Canvas Position")
|
||||
textinfo.add_text_info("Cell Position")
|
||||
var cell_color_texture_rect = ColorRect.new()
|
||||
cell_color_texture_rect.name = "Cell Color"
|
||||
cell_color_texture_rect.rect_size = Vector2(14, 14)
|
||||
cell_color_texture_rect.rect_position.x = 120
|
||||
textinfo.add_text_info("Cell Color", cell_color_texture_rect)
|
||||
textinfo.add_text_info("Cell Region")
|
||||
textinfo.add_text_info("Cell Position in Region")
|
||||
|
||||
func update_text_info():
|
||||
textinfo.update_text_info("FPS", Engine.get_frames_per_second())
|
||||
textinfo.update_text_info("Mouse Position", mouse_position)
|
||||
textinfo.update_text_info("Canvas Mouse Position", canvas_mouse_position)
|
||||
textinfo.update_text_info("Canvas Position", canvas_position)
|
||||
textinfo.update_text_info("Cell Position", cell_mouse_position)
|
||||
var cell_color_text = cell_color
|
||||
if paint_canvas_node.mouse_in_region and paint_canvas_container_node.mouse_on_top:
|
||||
if Input.is_mouse_button_pressed(BUTTON_LEFT) or Input.is_mouse_button_pressed(BUTTON_RIGHT):
|
||||
if paint_canvas_node.last_pixel.size() > 0:
|
||||
cell_color_text = paint_canvas_node.last_pixel[2]
|
||||
if cell_color_text == null:
|
||||
cell_color_text = Color(0, 0, 0, 0)
|
||||
textinfo.update_text_info("Cell Color", cell_color_text, "Cell Color", "color", cell_color_text)
|
||||
textinfo.update_text_info("Cell Region", cell_region_position)
|
||||
textinfo.update_text_info("Cell Position in Region", cell_position_in_region)
|
||||
|
||||
func _on_PaintTool_pressed():
|
||||
brush_mode = "paint"
|
||||
|
||||
func _on_BucketTool_pressed():
|
||||
brush_mode = "bucket"
|
||||
|
||||
func _on_ColorPicker_color_changed(color):
|
||||
selected_color = color
|
||||
|
||||
func _on_Save_pressed():
|
||||
get_node("SaveFileDialog").show()
|
||||
|
||||
func _on_RainbowTool_pressed():
|
||||
brush_mode = "rainbow"
|
181
addons/graphics_editor/Editor.tscn
Normal file
181
addons/graphics_editor/Editor.tscn
Normal file
@ -0,0 +1,181 @@
|
||||
[gd_scene load_steps=11 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Editor.gd" type="Script" id=1]
|
||||
[ext_resource path="res://addons/graphics_editor/PaintCanvasContainer.gd" type="Script" id=2]
|
||||
[ext_resource path="res://addons/graphics_editor/PaintCanvas.tscn" type="PackedScene" id=3]
|
||||
[ext_resource path="res://addons/graphics_editor/VisualGrid.tscn" type="PackedScene" id=4]
|
||||
[ext_resource path="res://addons/graphics_editor/CanvasOutline.gd" type="Script" id=5]
|
||||
[ext_resource path="res://addons/graphics_editor/Navbar.gd" type="Script" id=6]
|
||||
[ext_resource path="res://addons/graphics_editor/MenuButtonExtended.gd" type="Script" id=7]
|
||||
[ext_resource path="res://addons/graphics_editor/TextInfo.gd" type="Script" id=8]
|
||||
[ext_resource path="res://addons/graphics_editor/SaveFileDialog.gd" type="Script" id=9]
|
||||
[ext_resource path="res://addons/graphics_editor/Settings.tscn" type="PackedScene" id=10]
|
||||
|
||||
[node name="Editor" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
rect_min_size = Vector2( 1024, 300 )
|
||||
rect_clip_content = true
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="PaintCanvasContainer" type="Control" parent="."]
|
||||
show_behind_parent = true
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 20.0
|
||||
margin_right = -114.0
|
||||
margin_bottom = -40.0
|
||||
focus_mode = 1
|
||||
mouse_filter = 1
|
||||
script = ExtResource( 2 )
|
||||
__meta__ = {
|
||||
"_edit_lock_": true
|
||||
}
|
||||
|
||||
[node name="PaintCanvas" parent="PaintCanvasContainer" instance=ExtResource( 3 )]
|
||||
anchor_right = 0.0
|
||||
anchor_bottom = 0.0
|
||||
margin_right = 1600.0
|
||||
margin_bottom = 1600.0
|
||||
rect_min_size = Vector2( 1600, 1600 )
|
||||
|
||||
[node name="Grids" type="Control" parent="PaintCanvasContainer/PaintCanvas"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="VisualGrid" parent="PaintCanvasContainer/PaintCanvas/Grids" instance=ExtResource( 4 )]
|
||||
mouse_filter = 2
|
||||
color = Color( 0.639216, 0.639216, 0.639216, 1 )
|
||||
|
||||
[node name="VisualGrid2" parent="PaintCanvasContainer/PaintCanvas/Grids" instance=ExtResource( 4 )]
|
||||
mouse_filter = 2
|
||||
color = Color( 1, 1, 1, 1 )
|
||||
size = 160
|
||||
|
||||
[node name="CanvasOutline" type="Control" parent="PaintCanvasContainer/PaintCanvas"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 5 )
|
||||
color = Color( 0, 1, 0, 1 )
|
||||
|
||||
[node name="Navbar" type="Control" parent="."]
|
||||
editor/display_folded = true
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 20.0
|
||||
script = ExtResource( 6 )
|
||||
|
||||
[node name="Panel" type="Panel" parent="Navbar"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="Buttons" type="Control" parent="Navbar"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
|
||||
[node name="File" type="MenuButton" parent="Navbar/Buttons"]
|
||||
margin_right = 90.0
|
||||
margin_bottom = 20.0
|
||||
text = "File"
|
||||
flat = false
|
||||
items = [ "Save", null, 0, false, false, -1, 0, null, "", false, "Quit", null, 0, false, false, -1, 0, null, "", false ]
|
||||
switch_on_hover = true
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="Editor" type="MenuButton" parent="Navbar/Buttons"]
|
||||
margin_left = 90.0
|
||||
margin_right = 180.0
|
||||
margin_bottom = 20.0
|
||||
text = "Editor"
|
||||
flat = false
|
||||
items = [ "Settings", null, 0, false, false, -1, 0, null, "", false, "Reset Canvas Position", null, 0, false, false, -1, 0, null, "", false, "Toggle Grid", null, 0, false, false, -1, 0, null, "", false ]
|
||||
switch_on_hover = true
|
||||
script = ExtResource( 7 )
|
||||
|
||||
[node name="ToolMenu" type="Control" parent="."]
|
||||
anchor_left = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_left = -114.0
|
||||
margin_top = 20.0
|
||||
margin_bottom = -40.0
|
||||
|
||||
[node name="Buttons" type="Control" parent="ToolMenu"]
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 310.0
|
||||
|
||||
[node name="PaintTool" type="Button" parent="ToolMenu/Buttons"]
|
||||
anchor_right = 1.0
|
||||
margin_bottom = 70.0
|
||||
text = "Paint Tool"
|
||||
|
||||
[node name="BucketTool" type="Button" parent="ToolMenu/Buttons"]
|
||||
anchor_right = 1.0
|
||||
margin_top = 70.0
|
||||
margin_bottom = 140.0
|
||||
text = "Bucket Tool"
|
||||
|
||||
[node name="RainbowTool" type="Button" parent="ToolMenu/Buttons"]
|
||||
anchor_right = 1.0
|
||||
margin_top = 140.0
|
||||
margin_bottom = 210.0
|
||||
text = "Rainbow Tool"
|
||||
|
||||
[node name="ColorPicker" type="ColorPickerButton" parent="ToolMenu/Buttons"]
|
||||
anchor_right = 1.0
|
||||
margin_top = 210.0
|
||||
margin_bottom = 240.0
|
||||
|
||||
[node name="Layers" type="Control" parent="ToolMenu"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = 310.0
|
||||
|
||||
[node name="Tree" type="Tree" parent="ToolMenu/Layers"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = -70.0
|
||||
hide_root = true
|
||||
|
||||
[node name="BottomPanel" type="Panel" parent="."]
|
||||
editor/display_folded = true
|
||||
anchor_top = 1.0
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
margin_top = -40.0
|
||||
|
||||
[node name="TextInfo" type="Control" parent="BottomPanel"]
|
||||
script = ExtResource( 8 )
|
||||
|
||||
[node name="SaveFileDialog" type="FileDialog" parent="."]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -340.0
|
||||
margin_top = -165.0
|
||||
margin_right = 340.0
|
||||
margin_bottom = 165.0
|
||||
filters = PoolStringArray( "*.png ; PNG Images" )
|
||||
script = ExtResource( 9 )
|
||||
|
||||
[node name="Settings" parent="." instance=ExtResource( 10 )]
|
||||
anchor_left = 0.5
|
||||
anchor_top = 0.5
|
||||
anchor_right = 0.5
|
||||
anchor_bottom = 0.5
|
||||
margin_left = -150.0
|
||||
margin_top = -50.0
|
||||
margin_right = 150.0
|
||||
margin_bottom = 50.0
|
||||
[connection signal="mouse_entered" from="PaintCanvasContainer" to="PaintCanvasContainer" method="_on_PaintCanvasContainer_mouse_entered"]
|
||||
[connection signal="mouse_exited" from="PaintCanvasContainer" to="PaintCanvasContainer" method="_on_PaintCanvasContainer_mouse_exited"]
|
||||
[connection signal="pressed" from="ToolMenu/Buttons/PaintTool" to="." method="_on_PaintTool_pressed"]
|
||||
[connection signal="pressed" from="ToolMenu/Buttons/BucketTool" to="." method="_on_BucketTool_pressed"]
|
||||
[connection signal="pressed" from="ToolMenu/Buttons/RainbowTool" to="." method="_on_RainbowTool_pressed"]
|
||||
[connection signal="color_changed" from="ToolMenu/Buttons/ColorPicker" to="." method="_on_ColorPicker_color_changed"]
|
||||
[connection signal="about_to_show" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_about_to_show"]
|
||||
[connection signal="confirmed" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_confirmed"]
|
||||
[connection signal="file_selected" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_file_selected"]
|
||||
[connection signal="visibility_changed" from="SaveFileDialog" to="SaveFileDialog" method="_on_SaveFileDialog_visibility_changed"]
|
11
addons/graphics_editor/MenuButtonExtended.gd
Normal file
11
addons/graphics_editor/MenuButtonExtended.gd
Normal file
@ -0,0 +1,11 @@
|
||||
tool
|
||||
extends MenuButton
|
||||
|
||||
var popup = self.get_popup()
|
||||
signal item_pressed
|
||||
|
||||
func _ready():
|
||||
popup.connect("id_pressed", self, "id_pressed")
|
||||
|
||||
func id_pressed(id):
|
||||
emit_signal("item_pressed", self.name, popup.get_item_text(id))
|
21
addons/graphics_editor/Navbar.gd
Normal file
21
addons/graphics_editor/Navbar.gd
Normal file
@ -0,0 +1,21 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
func _ready():
|
||||
for i in get_node("Buttons").get_children():
|
||||
i.connect("item_pressed", self, "button_pressed")
|
||||
|
||||
func button_pressed(button_name, button_item):
|
||||
if button_name == "File":
|
||||
if button_item == "Save":
|
||||
get_parent().get_node("SaveFileDialog").show()
|
||||
if button_item == "Quit":
|
||||
get_tree().quit()
|
||||
elif button_name == "Editor":
|
||||
if button_item == "Settings":
|
||||
get_parent().get_node("Settings").show()
|
||||
elif button_item == "Toggle Grid":
|
||||
var grids_node = get_parent().get_node("PaintCanvasContainer/PaintCanvas/Grids")
|
||||
grids_node.visible = !grids_node.visible
|
||||
elif button_item == "Reset Canvas Position":
|
||||
get_parent().paint_canvas_node.rect_position = Vector2(0, 0)
|
379
addons/graphics_editor/PaintCanvas.gd
Normal file
379
addons/graphics_editor/PaintCanvas.gd
Normal file
@ -0,0 +1,379 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var image = Image.new()
|
||||
var last_pixel = []
|
||||
onready var canvas_image_node = get_node("CanvasImage")
|
||||
export var grid_size = 16
|
||||
export var canvas_size = Vector2(100, 100)
|
||||
export var region_size = 10
|
||||
export var can_draw = true
|
||||
|
||||
var mouse_in_region
|
||||
var mouse_on_top
|
||||
|
||||
#terms
|
||||
#global cell - a cell that has a global grid position on the canvas
|
||||
#local cell - a cell that has a local grid position in a chunk region on the canvas
|
||||
#chunk region - a set of cells contained in an even number
|
||||
|
||||
#TODO: Maybe each chunk region can hold an image resource so that way the engine wouldn't lag at all when updating the canvas
|
||||
|
||||
var layers = [
|
||||
{
|
||||
"name": "Layer 1",
|
||||
"data": [],
|
||||
"chunks": []
|
||||
}
|
||||
]
|
||||
var active_layer = "Layer 1"
|
||||
|
||||
var chunks = []
|
||||
|
||||
func get_layer_data(layer_name):
|
||||
for layer in layers:
|
||||
if layer.name == layer_name:
|
||||
return layer.data
|
||||
#return layer.chunks
|
||||
|
||||
func set_layer_data(layer_name, layer_data):
|
||||
for layer in layers:
|
||||
if layer.name == layer_name:
|
||||
layer.data = layer_data
|
||||
return
|
||||
|
||||
func remove_layer(layer_name):
|
||||
for layer in layers:
|
||||
if layer.name == layer_name:
|
||||
layers[layer] = null
|
||||
return
|
||||
|
||||
func add_layer(layer_name):
|
||||
for layer in layers:
|
||||
#TODO: Allow users to create layers with the same name, we can do this because of the indexes in the layer array
|
||||
if layer.name == layer_name:
|
||||
return false
|
||||
layers.append({"name": layer_name, "data": []})
|
||||
#layers.append({"name": layer_name, "chunks": []})
|
||||
return true
|
||||
|
||||
var util = preload("res://addons/graphics_editor/Util.gd")
|
||||
|
||||
func _ready():
|
||||
#canvas_image_node.rect_scale = Vector2(grid_size, grid_size)
|
||||
#image.create(canvas_size.x, canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
#image.lock()
|
||||
#print(get_maxium_filled_chunks())
|
||||
# for pixel_data in get_layer_data(active_layer):
|
||||
# var cx = pixel_data[0]
|
||||
# var cy = pixel_data[1]
|
||||
# var ccolor = pixel_data[2]
|
||||
# image.set_pixel(cx, cy, ccolor)
|
||||
generate_chunks()
|
||||
|
||||
func _process(delta):
|
||||
var mouse_position = get_local_mouse_position()
|
||||
var rect = Rect2(Vector2(0, 0), self.rect_size)
|
||||
mouse_in_region = rect.has_point(mouse_position)
|
||||
update()
|
||||
#if not Engine.editor_hint:
|
||||
# print(mouse_on_canvas, " | ", has_focus())
|
||||
#draw_canvas_out just updates the image constantly
|
||||
#if can_draw:
|
||||
# draw_canvas_out()
|
||||
|
||||
func generate_chunks():
|
||||
var maxium_chunk_size = get_maxium_filled_chunks()
|
||||
#TODO: We probably don't need to check for x and y anymore
|
||||
for x in maxium_chunk_size.x:
|
||||
for y in maxium_chunk_size.y:
|
||||
var paint_canvas_chunk = load("res://addons/graphics_editor/PaintCanvasChunk.tscn").instance()
|
||||
paint_canvas_chunk.setup(region_size)
|
||||
paint_canvas_chunk.name = "C-%s-%s" % [x, y]
|
||||
paint_canvas_chunk.rect_position = Vector2(x * (16 * 10), y * (16 * 10))
|
||||
get_node("Chunks").add_child(paint_canvas_chunk)
|
||||
|
||||
func get_maxium_filled_chunks():
|
||||
return Vector2(canvas_size.x / region_size, canvas_size.y / region_size).ceil()
|
||||
|
||||
#TODO: Remake these functions with godot's setget features
|
||||
#so that we don't have to call these functions
|
||||
func resize_grid(grid):
|
||||
#print(grid)
|
||||
if grid <= 0:
|
||||
return
|
||||
grid_size = grid
|
||||
canvas_image_node.rect_scale = Vector2(grid, grid)
|
||||
|
||||
func resize_canvas(x, y):
|
||||
image.unlock()
|
||||
image.create(x, y, true, Image.FORMAT_RGBA8)
|
||||
canvas_size = Vector2(x, y)
|
||||
#setup_all_chunks()
|
||||
image.lock()
|
||||
|
||||
#func draw_canvas_out(a = ""):
|
||||
# if canvas_image_node == null:
|
||||
# return
|
||||
# var image_texture = ImageTexture.new()
|
||||
# image_texture.create_from_image(image)
|
||||
# image_texture.set_flags(0)
|
||||
# canvas_image_node.texture = image_texture
|
||||
|
||||
func get_wrapped_region_cell(x, y):
|
||||
return Vector2(wrapi(x, 0, region_size), wrapi(y, 0, region_size))
|
||||
|
||||
func get_region_from_cell(x, y):
|
||||
return Vector2(floor(x / region_size), floor(y / region_size))
|
||||
|
||||
func set_local_cell_in_chunk(chunk_x, chunk_y, local_cell_x, local_cell_y, color):
|
||||
var chunk_node = get_node("Chunks").get_node_or_null("C-%s-%s" % [chunk_x, chunk_y])
|
||||
if chunk_node == null:
|
||||
print("Can't find chunk node!")
|
||||
return
|
||||
chunk_node.set_cell(local_cell_x, local_cell_y, color)
|
||||
|
||||
func set_global_cell_in_chunk(cell_x, cell_y, color):
|
||||
var chunk = get_region_from_cell(cell_x, cell_y)
|
||||
var wrapped_cell = get_wrapped_region_cell(cell_x, cell_y)
|
||||
set_local_cell_in_chunk(chunk.x, chunk.y, wrapped_cell.x, wrapped_cell.y, color)
|
||||
|
||||
#func update_chunk_region_from_cell(x, y):
|
||||
# var region_to_update = get_region_from_cell(x, y)
|
||||
# update_chunk_region(region_to_update.x, region_to_update.y)
|
||||
|
||||
func get_pixel_cell_color(x, y):
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return null
|
||||
var pixel_cell = get_pixel_cell(x, y)
|
||||
if pixel_cell == null:
|
||||
#We already checked that the cell can't be out of the canvas region so we can assume the pixel cell is completely transparent if it's null
|
||||
return Color(0, 0, 0, 0)
|
||||
else:
|
||||
return util.color_from_array(pixel_cell[2])
|
||||
|
||||
func get_pixel_cell_color_v(vec2):
|
||||
return get_pixel_cell_color(vec2.x, vec2.y)
|
||||
|
||||
func get_pixel_cell(x, y):
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return null
|
||||
|
||||
for pixel in get_layer_data(active_layer):
|
||||
if pixel[0] == x and pixel[1] == y:
|
||||
return pixel
|
||||
|
||||
return null
|
||||
|
||||
func get_pixel_cell_v(vec2):
|
||||
return get_pixel_cell(vec2.x, vec2.y)
|
||||
|
||||
#func remove_pixel_cell(x, y):
|
||||
# if can_draw == false:
|
||||
# return false
|
||||
# if not cell_in_canvas_region(x, y):
|
||||
# return false
|
||||
# var layer_data = get_layer_data("Layer 1")
|
||||
# for pixel in range(0, layer_data.size()):
|
||||
# if layer_data[pixel][0] == x and layer_data[pixel][1] == y:
|
||||
# layer_data.remove(pixel)
|
||||
# #update_chunk_region_from_cell(x, y)
|
||||
# #TOOD: If pixel exists in temp_pool_pixels then remove it
|
||||
# image.set_pixel(x, y, Color(0, 0, 0, 0))
|
||||
# return true
|
||||
# return false
|
||||
|
||||
#func remove_pixel_cell_v(vec2):
|
||||
# return remove_pixel_cell(vec2.x, vec2.y)
|
||||
|
||||
func set_pixel_cell(x, y, color):
|
||||
if can_draw == false:
|
||||
return false
|
||||
if not cell_in_canvas_region(x, y):
|
||||
return false
|
||||
var layer_data = get_layer_data(active_layer)
|
||||
var index = 0
|
||||
for pixel in layer_data:
|
||||
#TODO: Make a better way of accessing the array because the more pixels we have, the longer it takes to
|
||||
#set the pixel
|
||||
if pixel[0] == x and pixel[1] == y:
|
||||
#No reason to set the pixel again if the colors are the same
|
||||
if pixel[2] == color:
|
||||
return
|
||||
#If the color we are setting is 0, 0, 0, 0 then there is no reason to keep the information about the pixel
|
||||
#so we remove it from the layer data
|
||||
if color == Color(0, 0, 0, 0):
|
||||
layer_data.remove(index)
|
||||
else:
|
||||
pixel[2] = color
|
||||
#TODO: The new system is going to allow chunks to each have their own TextureRect and Image
|
||||
#nodes so what we are doing in here is that we are setting the local cell in the region of that image
|
||||
set_global_cell_in_chunk(x, y, color)
|
||||
last_pixel = [x, y, color]
|
||||
return true
|
||||
index += 1
|
||||
#don't append any data if the color is 0, 0, 0, 0
|
||||
if color != Color(0, 0, 0, 0):
|
||||
#if the pixel data doesn't exist then we add it in
|
||||
layer_data.append([x, y, color])
|
||||
set_global_cell_in_chunk(x, y, color)
|
||||
last_pixel = [x, y, color]
|
||||
return true
|
||||
|
||||
func set_pixel_cell_v(vec2, color):
|
||||
return set_pixel_cell(vec2.x, vec2.y, color)
|
||||
|
||||
func set_pixels_from_line(vec2_1, vec2_2, color):
|
||||
var points = get_pixels_from_line(vec2_1, vec2_2)
|
||||
for i in points:
|
||||
set_pixel_cell_v(i, color)
|
||||
|
||||
func set_random_pixels_from_line(vec2_1, vec2_2):
|
||||
var points = get_pixels_from_line(vec2_1, vec2_2)
|
||||
for i in points:
|
||||
set_pixel_cell_v(i, util.random_color_alt())
|
||||
|
||||
func get_pixels_from_line(vec2_1, vec2_2):
|
||||
var points = PoolVector2Array()
|
||||
|
||||
var dx = abs(vec2_2.x - vec2_1.x)
|
||||
var dy = abs(vec2_2.y - vec2_1.y)
|
||||
|
||||
var x = vec2_1.x
|
||||
var y = vec2_1.y
|
||||
|
||||
var sx = 0
|
||||
if vec2_1.x > vec2_2.x:
|
||||
sx = -1
|
||||
else:
|
||||
sx = 1
|
||||
|
||||
var sy = 0
|
||||
if vec2_1.y > vec2_2.y:
|
||||
sy = -1
|
||||
else:
|
||||
sy = 1
|
||||
|
||||
if dx > dy:
|
||||
var err = dx / 2
|
||||
while(true):
|
||||
if x == vec2_2.x:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dy
|
||||
if err < 0:
|
||||
y += sy
|
||||
err += dx
|
||||
x += sx
|
||||
else:
|
||||
var err = dy / 2
|
||||
while (true):
|
||||
if y == vec2_2.y:
|
||||
break
|
||||
points.push_back(Vector2(x, y))
|
||||
|
||||
err -= dx
|
||||
if err < 0:
|
||||
x += sx
|
||||
err += dy
|
||||
y += sy
|
||||
points.push_back(Vector2(x, y))
|
||||
return points
|
||||
|
||||
#even though the function checks for it, we can't afford adding more functions to the call stack
|
||||
#because godot has a limit until it crashes
|
||||
var flood_fill_queue = 0
|
||||
func flood_fill(x, y, target_color, replacement_color):
|
||||
#yield(get_tree().create_timer(1), "timeout")
|
||||
flood_fill_queue += 1
|
||||
if not cell_in_canvas_region(x, y):
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
if target_color == replacement_color:
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
elif not get_pixel_cell_color(x, y) == target_color:
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
else:
|
||||
set_pixel_cell(x, y, replacement_color)
|
||||
if flood_fill_queue >= 500:
|
||||
print(flood_fill_queue)
|
||||
yield(get_tree().create_timer(0.01), "timeout")
|
||||
#up
|
||||
if get_pixel_cell_color(x, y - 1) == target_color:
|
||||
flood_fill(x, y - 1, target_color, replacement_color)
|
||||
#down
|
||||
if get_pixel_cell_color(x, y + 1) == target_color:
|
||||
flood_fill(x, y + 1, target_color, replacement_color)
|
||||
#left
|
||||
if get_pixel_cell_color(x - 1, y) == target_color:
|
||||
flood_fill(x - 1, y, target_color, replacement_color)
|
||||
#right
|
||||
if get_pixel_cell_color(x + 1, y) == target_color:
|
||||
flood_fill(x + 1, y, target_color, replacement_color)
|
||||
flood_fill_queue -= 1
|
||||
return
|
||||
|
||||
#func flood_fill_erase(x, y, target_color):
|
||||
# yield(get_tree().create_timer(0.001), "timeout")
|
||||
# if not cell_in_canvas_region(x, y):
|
||||
# print("cell not in canvas")
|
||||
# return
|
||||
# #if target_color == replacement_color:
|
||||
# # return
|
||||
# elif not get_pixel_cell_color(x, y) == target_color:
|
||||
# print("cell doesn't match pixel color")
|
||||
# return
|
||||
# elif not get_pixel_cell(x, y):
|
||||
# print("cell already erased")
|
||||
# return
|
||||
# else:
|
||||
# print("removed pixel")
|
||||
# remove_pixel_cell(x, y)
|
||||
# print("x: ", x, " y: ", y, " color: ", target_color)
|
||||
# #up
|
||||
# flood_fill_erase(x, y - 1, target_color)
|
||||
# #down
|
||||
# flood_fill_erase(x, y + 1, target_color)
|
||||
# #left
|
||||
# flood_fill_erase(x - 1, y, target_color)
|
||||
# #right
|
||||
# flood_fill_erase(x + 1, y, target_color)
|
||||
# return
|
||||
|
||||
func cell_in_canvas_region(x, y):
|
||||
if x > canvas_size.x - 1 or x < 0 or y > canvas_size.y - 1 or y < 0:
|
||||
#out of bounds, return false
|
||||
return false
|
||||
else:
|
||||
return true
|
||||
|
||||
#Both of these functions right now just return the starting position of the canvas and the last position of the canvas
|
||||
func get_all_used_regions_in_canvas():
|
||||
var first_used_region = get_first_used_region_in_canvas()
|
||||
var last_used_region = get_last_used_region_in_canvas()
|
||||
var chunk_pool = PoolVector2Array()
|
||||
for chunk_x in range(first_used_region.x, last_used_region.x):
|
||||
for chunk_y in range(first_used_region.y, last_used_region.y):
|
||||
chunk_pool.append(Vector2(chunk_x, chunk_y))
|
||||
return chunk_pool
|
||||
|
||||
func get_first_used_region_in_canvas():
|
||||
return get_region_from_cell(0, 0)
|
||||
|
||||
func get_last_used_region_in_canvas():
|
||||
return get_region_from_cell(canvas_size.x - 1, canvas_size.y - 1)
|
||||
|
||||
func get_cells_in_region(x, y):
|
||||
var start_cell = Vector2(x * region_size, y * region_size)
|
||||
var end_cell = Vector2((x * region_size) + region_size, (y * region_size) + region_size)
|
||||
var cell_array = []
|
||||
for cx in range(start_cell.x, end_cell.x):
|
||||
for cy in range(start_cell.y, end_cell.y):
|
||||
var pixel_cell = get_pixel_cell(cx, cy)
|
||||
if pixel_cell == null:
|
||||
pixel_cell = [cx, cy, Color(0, 0, 0, 0)]
|
||||
cell_array.append(pixel_cell)
|
||||
return cell_array
|
22
addons/graphics_editor/PaintCanvas.tscn
Normal file
22
addons/graphics_editor/PaintCanvas.tscn
Normal file
@ -0,0 +1,22 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/PaintCanvas.gd" type="Script" id=1]
|
||||
|
||||
[node name="PaintCanvas" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Chunks" type="Control" parent="."]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
|
||||
[node name="CanvasImage" type="TextureRect" parent="."]
|
||||
visible = false
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
mouse_filter = 2
|
||||
expand = true
|
||||
stretch_mode = 3
|
27
addons/graphics_editor/PaintCanvasChunk.gd
Normal file
27
addons/graphics_editor/PaintCanvasChunk.gd
Normal file
@ -0,0 +1,27 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var image = Image.new()
|
||||
var image_texture = ImageTexture.new()
|
||||
|
||||
func _ready():
|
||||
self.mouse_filter = Control.MOUSE_FILTER_IGNORE
|
||||
|
||||
func setup(region_size):
|
||||
image.create(region_size, region_size, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
|
||||
func update_chunk():
|
||||
image_texture.create_from_image(image)
|
||||
image_texture.set_flags(0)
|
||||
self.texture = image_texture
|
||||
|
||||
func set_cell(x, y, color):
|
||||
image.set_pixel(x, y, color)
|
||||
update_chunk()
|
||||
|
||||
func _on_VisibilityNotifier2D_screen_entered():
|
||||
self.visible = true
|
||||
|
||||
func _on_VisibilityNotifier2D_screen_exited():
|
||||
self.visible = false
|
12
addons/graphics_editor/PaintCanvasChunk.tscn
Normal file
12
addons/graphics_editor/PaintCanvasChunk.tscn
Normal file
@ -0,0 +1,12 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/PaintCanvasChunk.gd" type="Script" id=1]
|
||||
|
||||
[node name="PaintCanvasChunk" type="TextureRect"]
|
||||
margin_right = 10.0
|
||||
margin_bottom = 10.0
|
||||
rect_scale = Vector2( 16, 16 )
|
||||
mouse_filter = 2
|
||||
expand = true
|
||||
stretch_mode = 1
|
||||
script = ExtResource( 1 )
|
19
addons/graphics_editor/PaintCanvasContainer.gd
Normal file
19
addons/graphics_editor/PaintCanvasContainer.gd
Normal file
@ -0,0 +1,19 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var mouse_in_region
|
||||
var mouse_on_top
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _process(delta):
|
||||
var mouse_position = get_local_mouse_position()
|
||||
var rect = Rect2(Vector2(0, 0), self.rect_size)
|
||||
mouse_in_region = rect.has_point(mouse_position)
|
||||
|
||||
func _on_PaintCanvasContainer_mouse_entered():
|
||||
mouse_on_top = true
|
||||
|
||||
func _on_PaintCanvasContainer_mouse_exited():
|
||||
mouse_on_top = false
|
4
addons/graphics_editor/PaintTool.gd
Normal file
4
addons/graphics_editor/PaintTool.gd
Normal file
@ -0,0 +1,4 @@
|
||||
extends "Brush.gd"
|
||||
|
||||
func _ready():
|
||||
draw_pixel()
|
51
addons/graphics_editor/SaveFileDialog.gd
Normal file
51
addons/graphics_editor/SaveFileDialog.gd
Normal file
@ -0,0 +1,51 @@
|
||||
tool
|
||||
extends FileDialog
|
||||
|
||||
onready var canvas = get_parent().get_node("PaintCanvasContainer/PaintCanvas")
|
||||
|
||||
var file_path = ""
|
||||
|
||||
func _ready():
|
||||
# warning-ignore:return_value_discarded
|
||||
get_line_edit().connect("text_entered", self, "_on_LineEdit_text_entered")
|
||||
invalidate()
|
||||
clear_filters()
|
||||
add_filter("*.png ; PNG Images")
|
||||
|
||||
func _on_SaveFileDialog_file_selected(path):
|
||||
file_path = path
|
||||
|
||||
# warning-ignore:unused_argument
|
||||
func _on_LineEdit_text_entered(text):
|
||||
save_file()
|
||||
|
||||
func _on_SaveFileDialog_confirmed():
|
||||
save_file()
|
||||
|
||||
func save_file():
|
||||
var image = Image.new()
|
||||
image.create(canvas.canvas_size.x, canvas.canvas_size.y, true, Image.FORMAT_RGBA8)
|
||||
image.lock()
|
||||
for i in canvas.get_node("Chunks").get_children():
|
||||
var chunk_name = i.name
|
||||
var chunk_name_split = chunk_name.split("-")
|
||||
var chunk_x = int(chunk_name_split[1])
|
||||
var chunk_y = int(chunk_name_split[2])
|
||||
var chunk_image = i.image.duplicate()
|
||||
chunk_image.lock()
|
||||
var chunk_image_size = chunk_image.get_size()
|
||||
for x in chunk_image_size.x:
|
||||
for y in chunk_image_size.y:
|
||||
var pixel_color = chunk_image.get_pixel(x, y)
|
||||
var global_cell_x = (chunk_x * canvas.region_size) + x
|
||||
var global_cell_y = (chunk_y * canvas.region_size) + y
|
||||
image.lock()
|
||||
image.set_pixel(global_cell_x, global_cell_y, pixel_color)
|
||||
image.unlock()
|
||||
image.save_png(file_path)
|
||||
|
||||
func _on_SaveFileDialog_about_to_show():
|
||||
invalidate()
|
||||
|
||||
func _on_SaveFileDialog_visibility_changed():
|
||||
invalidate()
|
24
addons/graphics_editor/SelectionBox.gd
Normal file
24
addons/graphics_editor/SelectionBox.gd
Normal file
@ -0,0 +1,24 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
export var outline_size = 3
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _process(delta):
|
||||
update()
|
||||
|
||||
func _draw():
|
||||
if not rect_size == Vector2():
|
||||
draw_outline_box(rect_size, Color.gray, outline_size)
|
||||
|
||||
func draw_outline_box(size, color, width):
|
||||
#Top line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(size.x, 0), color, width)
|
||||
#Left line
|
||||
draw_line(Vector2(0 + 1, 0), Vector2(0, size.y), color, width)
|
||||
#Bottom line
|
||||
draw_line(Vector2(0 + 1, size.y), Vector2(size.x, size.y), color, width)
|
||||
#Right line
|
||||
draw_line(Vector2(size.x, 0), Vector2(size.x, size.y), color, width)
|
29
addons/graphics_editor/Settings.gd
Normal file
29
addons/graphics_editor/Settings.gd
Normal file
@ -0,0 +1,29 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
onready var editor = get_parent()
|
||||
onready var canvas_outline = get_parent().get_node("PaintCanvasContainer/PaintCanvas/CanvasOutline")
|
||||
var start_time
|
||||
var end_time
|
||||
|
||||
func _ready():
|
||||
#start_time = OS.get_ticks_msec()
|
||||
get_node("CanvasOutlineToggle/CheckButton").pressed = canvas_outline.visible
|
||||
get_node("CanvasOutlineColor/ColorPickerButton").color = canvas_outline.color
|
||||
|
||||
func _process(delta):
|
||||
# if get_parent().paint_canvas_node != null:
|
||||
# canvas_outline = get_parent().paint_canvas_node.get_node("CanvasOutline")
|
||||
# end_time = OS.get_ticks_msec()
|
||||
# print("[Settings] Found Editor node in %s seconds!" % [(end_time - start_time) / float(1000)])
|
||||
# set_process(false)
|
||||
pass
|
||||
|
||||
func _on_ColorPickerButton_color_changed(color):
|
||||
canvas_outline.color = color
|
||||
|
||||
func _on_CheckButton_toggled(button_pressed):
|
||||
canvas_outline.visible = button_pressed
|
||||
|
||||
func _on_Ok_pressed():
|
||||
self.hide()
|
62
addons/graphics_editor/Settings.tscn
Normal file
62
addons/graphics_editor/Settings.tscn
Normal file
@ -0,0 +1,62 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/Settings.gd" type="Script" id=1]
|
||||
|
||||
[node name="Settings" type="WindowDialog"]
|
||||
margin_top = 20.0
|
||||
margin_right = 300.0
|
||||
margin_bottom = 120.0
|
||||
window_title = "Settings"
|
||||
script = ExtResource( 1 )
|
||||
|
||||
[node name="Ok" type="Button" parent="."]
|
||||
margin_left = 210.0
|
||||
margin_top = 70.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 90.0
|
||||
text = "Ok"
|
||||
|
||||
[node name="CanvasOutlineToggle" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 10.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 30.0
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="CanvasOutlineToggle"]
|
||||
margin_right = 130.0
|
||||
margin_bottom = 20.0
|
||||
text = "Canvas Outline:"
|
||||
valign = 1
|
||||
|
||||
[node name="CheckButton" type="CheckButton" parent="CanvasOutlineToggle"]
|
||||
margin_left = 210.0
|
||||
margin_top = -10.0
|
||||
margin_right = 286.0
|
||||
margin_bottom = 30.0
|
||||
pressed = true
|
||||
|
||||
[node name="CanvasOutlineColor" type="Control" parent="."]
|
||||
margin_left = 10.0
|
||||
margin_top = 40.0
|
||||
margin_right = 290.0
|
||||
margin_bottom = 60.0
|
||||
__meta__ = {
|
||||
"_edit_group_": true
|
||||
}
|
||||
|
||||
[node name="Label" type="Label" parent="CanvasOutlineColor"]
|
||||
margin_right = 130.0
|
||||
margin_bottom = 20.0
|
||||
text = "Canvas Outline Color:"
|
||||
valign = 1
|
||||
|
||||
[node name="ColorPickerButton" type="ColorPickerButton" parent="CanvasOutlineColor"]
|
||||
margin_left = 170.0
|
||||
margin_right = 280.0
|
||||
margin_bottom = 20.0
|
||||
[connection signal="pressed" from="Ok" to="." method="_on_Ok_pressed"]
|
||||
[connection signal="toggled" from="CanvasOutlineToggle/CheckButton" to="." method="_on_CheckButton_toggled"]
|
||||
[connection signal="color_changed" from="CanvasOutlineColor/ColorPickerButton" to="." method="_on_ColorPickerButton_color_changed"]
|
39
addons/graphics_editor/TextInfo.gd
Normal file
39
addons/graphics_editor/TextInfo.gd
Normal file
@ -0,0 +1,39 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
var size = 240
|
||||
|
||||
#TODO: To make reading the text easier, the text info with the longest text should have it's length applied to all the
|
||||
#the other text infos
|
||||
|
||||
func add_text_info(text_name, custom_node = null):
|
||||
var last_text_info_child = null
|
||||
var child_count = self.get_child_count()
|
||||
if not child_count <= 0:
|
||||
last_text_info_child = self.get_children()[self.get_children().size() - 1]
|
||||
var label = Label.new()
|
||||
label.name = text_name
|
||||
label.rect_size = Vector2(size, 14)
|
||||
if not last_text_info_child == null:
|
||||
var x = last_text_info_child.rect_position.x
|
||||
var y = last_text_info_child.rect_position.y
|
||||
var temp_size = size
|
||||
if child_count == 4:
|
||||
x = 0
|
||||
y = 20
|
||||
temp_size = 0
|
||||
label.rect_position = Vector2(x + temp_size, y)
|
||||
if not custom_node == null:
|
||||
label.add_child(custom_node)
|
||||
self.add_child(label)
|
||||
|
||||
func update_text_info(text_name, text_value = null, node = null, node_target_value = null, node_value = null):
|
||||
var text_label = self.get_node(text_name)
|
||||
if text_label == null:
|
||||
return
|
||||
if not node == null:
|
||||
self.get_node(text_name).get_node(node).set(node_target_value, node_value)
|
||||
if text_value == null:
|
||||
text_label.text = "%s: %s" % [text_name, null]
|
||||
else:
|
||||
text_label.text = "%s: %s" % [text_name, String(text_value)]
|
52
addons/graphics_editor/Util.gd
Normal file
52
addons/graphics_editor/Util.gd
Normal file
@ -0,0 +1,52 @@
|
||||
tool
|
||||
extends Node
|
||||
|
||||
static func color_from_array(color_array):
|
||||
var r = color_array[0]
|
||||
var g = color_array[1]
|
||||
var b = color_array[2]
|
||||
var a = color_array[3]
|
||||
return Color(r, g, b, a)
|
||||
|
||||
static func random_color():
|
||||
return Color(randf(), randf(), randf())
|
||||
|
||||
static func random_color_alt():
|
||||
var rand = randi() % 6
|
||||
|
||||
match rand:
|
||||
#red
|
||||
0:
|
||||
return Color.red
|
||||
#blue
|
||||
1:
|
||||
return Color.blue
|
||||
#green
|
||||
2:
|
||||
return Color.green
|
||||
#orange
|
||||
3:
|
||||
return Color.orange
|
||||
#yellow
|
||||
4:
|
||||
return Color.yellow
|
||||
#purple
|
||||
5:
|
||||
return Color.purple
|
||||
|
||||
static func get_line_string(file, number):
|
||||
return file.get_as_text().split("\n")[number - 1].strip_edges()
|
||||
|
||||
static func printv(variable):
|
||||
var stack = get_stack()[get_stack().size() - 1]
|
||||
var line = stack.line
|
||||
var source = stack.source
|
||||
var file = File.new()
|
||||
file.open(source, File.READ)
|
||||
var line_string = get_line_string(file, line)
|
||||
file.close()
|
||||
var left_p = line_string.find("(")
|
||||
var left_p_string = line_string.right(left_p + 1)
|
||||
var right_p = left_p_string.find(")")
|
||||
var variable_name = left_p_string.left(right_p)
|
||||
print("%s: %s" % [variable_name, variable])
|
9
addons/graphics_editor/ViewportContainer.gd
Normal file
9
addons/graphics_editor/ViewportContainer.gd
Normal file
@ -0,0 +1,9 @@
|
||||
extends ViewportContainer
|
||||
|
||||
func _ready():
|
||||
pass
|
||||
|
||||
func _notification(what):
|
||||
if what == Control.NOTIFICATION_RESIZED:
|
||||
get_node("Viewport").size = self.rect_size
|
||||
get_node("Viewport/Node2D/Camera2D").position = Vector2(self.rect_size.x / 2, self.rect_size.y / 2)
|
31
addons/graphics_editor/VisualGrid.gd
Normal file
31
addons/graphics_editor/VisualGrid.gd
Normal file
@ -0,0 +1,31 @@
|
||||
tool
|
||||
extends Control
|
||||
|
||||
export var color = Color()
|
||||
export var size = 16
|
||||
export var zoom = 0
|
||||
export var offset = Vector2(0, 0)
|
||||
|
||||
func _draw():
|
||||
if size == 0:
|
||||
size = 1
|
||||
|
||||
var temp_size = size + zoom
|
||||
|
||||
var wrap_offset = Vector2(wrapf(offset.x, 0, temp_size), wrapf(offset.y, 0, temp_size))
|
||||
|
||||
var ceil_x = ceil(self.rect_size.x / temp_size) + 0.01
|
||||
var ceil_y = ceil(self.rect_size.y / temp_size) + 0.01
|
||||
|
||||
for i in ceil_y:
|
||||
var start_x = Vector2(0, (i * temp_size) + wrap_offset.y)
|
||||
var end_x = Vector2(self.rect_size.x, (i * temp_size) + wrap_offset.y)
|
||||
draw_line(start_x, end_x, color, 1)
|
||||
|
||||
for i in ceil_x:
|
||||
var start_y = Vector2((i * temp_size) + wrap_offset.x, 0)
|
||||
var end_y = Vector2((i * temp_size) + (wrap_offset.x + 0.01), self.rect_size.y)
|
||||
draw_line(start_y, end_y, color, 1)
|
||||
|
||||
func _process(delta):
|
||||
update()
|
8
addons/graphics_editor/VisualGrid.tscn
Normal file
8
addons/graphics_editor/VisualGrid.tscn
Normal file
@ -0,0 +1,8 @@
|
||||
[gd_scene load_steps=2 format=2]
|
||||
|
||||
[ext_resource path="res://addons/graphics_editor/VisualGrid.gd" type="Script" id=1]
|
||||
|
||||
[node name="VisualGrid" type="Control"]
|
||||
anchor_right = 1.0
|
||||
anchor_bottom = 1.0
|
||||
script = ExtResource( 1 )
|
7
addons/graphics_editor/plugin.cfg
Normal file
7
addons/graphics_editor/plugin.cfg
Normal file
@ -0,0 +1,7 @@
|
||||
[plugin]
|
||||
|
||||
name="GraphicsEditor"
|
||||
description=""
|
||||
author=""
|
||||
version=""
|
||||
script="plugin.gd"
|
10
addons/graphics_editor/plugin.gd
Normal file
10
addons/graphics_editor/plugin.gd
Normal file
@ -0,0 +1,10 @@
|
||||
tool
|
||||
extends EditorPlugin
|
||||
|
||||
var editor_scene = load("res://addons/graphics_editor/Editor.tscn").instance()
|
||||
|
||||
func _enter_tree():
|
||||
add_control_to_bottom_panel(editor_scene, "Graphics Editor")
|
||||
|
||||
func _exit_tree():
|
||||
remove_control_from_bottom_panel(editor_scene)
|
7
default_env.tres
Normal file
7
default_env.tres
Normal file
@ -0,0 +1,7 @@
|
||||
[gd_resource type="Environment" load_steps=2 format=2]
|
||||
|
||||
[sub_resource type="ProceduralSky" id=1]
|
||||
|
||||
[resource]
|
||||
background_mode = 2
|
||||
background_sky = SubResource( 1 )
|
34
icon.png.import
Normal file
34
icon.png.import
Normal file
@ -0,0 +1,34 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="StreamTexture"
|
||||
path="res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex"
|
||||
metadata={
|
||||
"vram_texture": false
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://icon.png"
|
||||
dest_files=[ "res://.import/icon.png-487276ed1e3a0c39cad0279d744ee560.stex" ]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=0
|
||||
compress/lossy_quality=0.7
|
||||
compress/hdr_mode=0
|
||||
compress/bptc_ldr=0
|
||||
compress/normal_map=0
|
||||
flags/repeat=0
|
||||
flags/filter=true
|
||||
flags/mipmaps=false
|
||||
flags/anisotropic=false
|
||||
flags/srgb=2
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/HDR_as_SRGB=false
|
||||
process/invert_color=false
|
||||
stream=false
|
||||
size_limit=0
|
||||
detect_3d=true
|
||||
svg/scale=1.0
|
28
project.godot
Normal file
28
project.godot
Normal file
@ -0,0 +1,28 @@
|
||||
; Engine configuration file.
|
||||
; It's best edited using the editor UI and not directly,
|
||||
; since the parameters that go here are not all obvious.
|
||||
;
|
||||
; Format:
|
||||
; [section] ; section goes between []
|
||||
; param=value ; assign values to parameters
|
||||
|
||||
config_version=4
|
||||
|
||||
_global_script_classes=[ ]
|
||||
_global_script_class_icons={
|
||||
|
||||
}
|
||||
|
||||
[application]
|
||||
|
||||
config/name="GraphicsEditor"
|
||||
run/main_scene="res://addons/graphics_editor/Editor.tscn"
|
||||
config/icon="res://icon.png"
|
||||
|
||||
[editor_plugins]
|
||||
|
||||
enabled=PoolStringArray( "graphics_editor", "scene_notes", "todo" )
|
||||
|
||||
[rendering]
|
||||
|
||||
environment/default_environment="res://default_env.tres"
|
Loading…
Reference in New Issue
Block a user