mirror of
https://github.com/Orama-Interactive/Pixelorama.git
synced 2025-01-18 09:09:47 +00:00
Compare commits
3 commits
bbc93e3f82
...
1f6998e723
Author | SHA1 | Date | |
---|---|---|---|
1f6998e723 | |||
48130809c9 | |||
952498a2b8 |
|
@ -1,105 +1,111 @@
|
||||||
class_name ObjParse
|
class_name ObjParse
|
||||||
|
extends Object
|
||||||
|
|
||||||
## Obj parser made by Ezcha, updated by Deakcor
|
const DEBUG: bool = false
|
||||||
## Created on 7/11/2018
|
|
||||||
## https://ezcha.net
|
|
||||||
## https://github.com/Ezcha/gd-obj
|
|
||||||
## MIT License
|
|
||||||
## https://github.com/Ezcha/gd-obj/blob/master/LICENSE
|
|
||||||
## Returns an array of materials from a MTL file
|
|
||||||
|
|
||||||
const DEBUG := false
|
# gd-obj
|
||||||
|
#
|
||||||
# Public methods
|
# Created on 7/11/2018
|
||||||
|
#
|
||||||
|
# Originally made by Ezcha
|
||||||
|
# Contributors: deakcor, kb173, jeffgamedev
|
||||||
|
#
|
||||||
|
# https://ezcha.net
|
||||||
|
# https://github.com/Ezcha/gd-obj
|
||||||
|
#
|
||||||
|
# MIT License
|
||||||
|
# https://github.com/Ezcha/gd-obj/blob/master/LICENSE
|
||||||
|
|
||||||
|
|
||||||
## Create mesh from obj and mtl paths
|
# Create mesh from obj and mtl paths
|
||||||
static func load_obj(obj_path: String, mtl_path: String = "") -> Mesh:
|
static func load_obj(obj_path: String, mtl_path: String = "") -> Mesh:
|
||||||
|
var obj_str: String = _read_file_str(obj_path)
|
||||||
if mtl_path == "":
|
if mtl_path == "":
|
||||||
mtl_path = search_mtl_path(obj_path)
|
var mtl_filename: String = _get_mtl_filename(obj_str)
|
||||||
var obj := get_data(obj_path)
|
mtl_path = "%s/%s" % [obj_path.get_base_dir(), mtl_filename]
|
||||||
var mats := {}
|
var mats: Dictionary = {}
|
||||||
if mtl_path != "":
|
if mtl_path != "":
|
||||||
mats = _create_mtl(get_data(mtl_path), get_mtl_tex(mtl_path))
|
mats = _create_mtl(_read_file_str(mtl_path), _get_mtl_tex(mtl_path))
|
||||||
return _create_obj(obj, mats) if obj and mats else null
|
if obj_str.is_empty():
|
||||||
|
return null
|
||||||
|
return _create_obj(obj_str, mats)
|
||||||
|
|
||||||
|
|
||||||
## Create mesh from obj, materials. Materials should be {"matname":data}
|
# Create mesh from obj, materials. Materials should be { "matname": data }
|
||||||
static func load_obj_from_buffer(obj_data: String, materials: Dictionary) -> Mesh:
|
static func load_obj_from_buffer(obj_data: String, materials: Dictionary) -> Mesh:
|
||||||
return _create_obj(obj_data, materials)
|
return _create_obj(obj_data, materials)
|
||||||
|
|
||||||
|
|
||||||
## Create materials
|
# Create materials
|
||||||
static func load_mtl_from_buffer(mtl_data: String, textures: Dictionary) -> Dictionary:
|
static func load_mtl_from_buffer(mtl_data: String, textures: Dictionary) -> Dictionary:
|
||||||
return _create_mtl(mtl_data, textures)
|
return _create_mtl(mtl_data, textures)
|
||||||
|
|
||||||
|
|
||||||
## Get data from file path
|
# Get data from file path
|
||||||
static func get_data(path: String) -> String:
|
static func _read_file_str(path: String) -> String:
|
||||||
if path != "":
|
if path == "":
|
||||||
var file := FileAccess.open(path, FileAccess.READ)
|
return ""
|
||||||
if FileAccess.get_open_error() == OK:
|
var file: FileAccess = FileAccess.open(path, FileAccess.READ)
|
||||||
var res := file.get_as_text()
|
if file == null:
|
||||||
file.close()
|
return ""
|
||||||
return res
|
return file.get_as_text()
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
## Get textures from mtl path (return {"tex_path":data})
|
# Internal functions
|
||||||
static func get_mtl_tex(mtl_path: String) -> Dictionary:
|
|
||||||
var file_paths := get_mtl_tex_paths(mtl_path)
|
|
||||||
var textures := {}
|
# Get textures from mtl path (returns { "tex_path": data })
|
||||||
|
static func _get_mtl_tex(mtl_path: String) -> Dictionary:
|
||||||
|
var file_paths: Array[String] = _get_mtl_tex_paths(mtl_path)
|
||||||
|
var textures: Dictionary = {}
|
||||||
for k in file_paths:
|
for k in file_paths:
|
||||||
textures[k] = _get_image(mtl_path, k).save_png_to_buffer()
|
textures[k] = _get_image(mtl_path, k).save_png_to_buffer()
|
||||||
return textures
|
return textures
|
||||||
|
|
||||||
|
|
||||||
## Get textures paths from mtl path
|
# Get textures paths from mtl path
|
||||||
static func get_mtl_tex_paths(mtl_path: String) -> Array:
|
static func _get_mtl_tex_paths(mtl_path: String) -> Array[String]:
|
||||||
var file := FileAccess.open(mtl_path, FileAccess.READ)
|
var file: FileAccess = FileAccess.open(mtl_path, FileAccess.READ)
|
||||||
var paths := []
|
if file == null:
|
||||||
if FileAccess.get_open_error() == OK:
|
return []
|
||||||
var lines := file.get_as_text().split("\n", false)
|
|
||||||
file.close()
|
var paths: Array[String] = []
|
||||||
for line in lines:
|
var lines: PackedStringArray = file.get_as_text().split("\n", false)
|
||||||
var parts := line.split(" ", false, 1)
|
for line in lines:
|
||||||
if parts[0] in ["map_Kd", "map_Ks", "map_Ka"]:
|
var parts: PackedStringArray = line.split(" ", false, 1)
|
||||||
if !parts[1] in paths:
|
if ["map_Kd", "map_Ks", "map_Ka"].has(parts[0]):
|
||||||
paths.push_back(parts[1])
|
if !paths.has(parts[1]):
|
||||||
|
paths.push_back(parts[1])
|
||||||
return paths
|
return paths
|
||||||
|
|
||||||
|
|
||||||
## Try to find mtl path from obj path
|
static func _get_mtl_filename(obj: String) -> String:
|
||||||
static func search_mtl_path(obj_path: String) -> String:
|
var lines: PackedStringArray = obj.split("\n")
|
||||||
var mtl_path := obj_path.get_base_dir().path_join(
|
for line in lines:
|
||||||
obj_path.get_file().rsplit(".", false, 1)[0] + ".mtl"
|
var split: PackedStringArray = line.split(" ", false)
|
||||||
)
|
if split.size() < 2:
|
||||||
if !FileAccess.file_exists(mtl_path):
|
continue
|
||||||
mtl_path = obj_path.get_base_dir().path_join(obj_path.get_file() + ".mtl")
|
if split[0] != "mtllib":
|
||||||
if !FileAccess.file_exists(mtl_path):
|
continue
|
||||||
return ""
|
return split[1].strip_edges()
|
||||||
return mtl_path
|
return ""
|
||||||
|
|
||||||
|
|
||||||
# Private methods
|
|
||||||
|
|
||||||
|
|
||||||
static func _create_mtl(obj: String, textures: Dictionary) -> Dictionary:
|
static func _create_mtl(obj: String, textures: Dictionary) -> Dictionary:
|
||||||
var mats := {}
|
var mats: Dictionary = {}
|
||||||
var current_mat: StandardMaterial3D = null
|
var current_mat: StandardMaterial3D = null
|
||||||
|
|
||||||
var lines := obj.split("\n", false)
|
var lines: PackedStringArray = obj.split("\n", false)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
var parts := line.split(" ", false)
|
var parts: PackedStringArray = line.split(" ", false)
|
||||||
match parts[0]:
|
match parts[0]:
|
||||||
"#":
|
"#":
|
||||||
# Comment
|
# Comment
|
||||||
#print("Comment: "+line)
|
|
||||||
pass
|
pass
|
||||||
"newmtl":
|
"newmtl":
|
||||||
# Create a new material
|
# Create a new material
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("Adding new material " + parts[1])
|
prints("Adding new material", parts[1])
|
||||||
current_mat = StandardMaterial3D.new()
|
current_mat = StandardMaterial3D.new()
|
||||||
mats[parts[1]] = current_mat
|
mats[parts[1]] = current_mat
|
||||||
"Ka":
|
"Ka":
|
||||||
|
@ -108,117 +114,134 @@ static func _create_mtl(obj: String, textures: Dictionary) -> Dictionary:
|
||||||
pass
|
pass
|
||||||
"Kd":
|
"Kd":
|
||||||
# Diffuse color
|
# Diffuse color
|
||||||
current_mat.albedo_color = Color(float(parts[1]), float(parts[2]), float(parts[3]))
|
current_mat.albedo_color = Color(
|
||||||
|
parts[1].to_float(), parts[2].to_float(), parts[3].to_float()
|
||||||
|
)
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print("Setting material color " + str(current_mat.albedo_color))
|
prints("Setting material color", str(current_mat.albedo_color))
|
||||||
_:
|
_:
|
||||||
if parts[0] in ["map_Kd", "map_Ks", "map_Ka"]:
|
if parts[0] in ["map_Kd", "map_Ks", "map_Ka"]:
|
||||||
var path := line.split(" ", false, 1)[1]
|
var path: String = line.split(" ", false, 1)[1]
|
||||||
if textures.has(path):
|
if textures.has(path):
|
||||||
current_mat.albedo_texture = _create_texture(textures[path])
|
current_mat.albedo_texture = _create_texture(textures[path])
|
||||||
return mats
|
return mats
|
||||||
|
|
||||||
|
|
||||||
|
static func _parse_mtl_file(path) -> Dictionary:
|
||||||
|
return _create_mtl(_read_file_str(path), _get_mtl_tex(path))
|
||||||
|
|
||||||
|
|
||||||
static func _get_image(mtl_filepath: String, tex_filename: String) -> Image:
|
static func _get_image(mtl_filepath: String, tex_filename: String) -> Image:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" Debug: Mapping texture file " + tex_filename)
|
prints("Debug: Mapping texture file", tex_filename)
|
||||||
var texfilepath := tex_filename
|
var tex_filepath: String = tex_filename
|
||||||
if tex_filename.is_relative_path():
|
if tex_filename.is_relative_path():
|
||||||
texfilepath = mtl_filepath.get_base_dir().path_join(tex_filename)
|
tex_filepath = "%s/%s" % [mtl_filepath.get_base_dir(), tex_filename]
|
||||||
var filetype := texfilepath.get_extension()
|
var file_type: String = tex_filepath.get_extension()
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(" Debug: texture file path: " + texfilepath + " of type " + filetype)
|
prints("Debug: texture file path:", tex_filepath, "of type", file_type)
|
||||||
|
|
||||||
var img := Image.new()
|
var img: Image = Image.new()
|
||||||
img.load(texfilepath)
|
img.load(tex_filepath)
|
||||||
return img
|
return img
|
||||||
|
|
||||||
|
|
||||||
static func _create_texture(data: PackedByteArray) -> ImageTexture:
|
static func _create_texture(data: PackedByteArray) -> ImageTexture:
|
||||||
var img := Image.new()
|
var img: Image = Image.new()
|
||||||
img.load_png_from_buffer(data)
|
img.load_png_from_buffer(data)
|
||||||
return ImageTexture.create_from_image(img)
|
return ImageTexture.create_from_image(img)
|
||||||
|
|
||||||
|
|
||||||
|
static func _get_texture(mtl_filepath, tex_filename) -> ImageTexture:
|
||||||
|
var tex = ImageTexture.create_from_image(_get_image(mtl_filepath, tex_filename))
|
||||||
|
if DEBUG:
|
||||||
|
prints("Debug: texture is", str(tex))
|
||||||
|
return tex
|
||||||
|
|
||||||
|
|
||||||
static func _create_obj(obj: String, mats: Dictionary) -> Mesh:
|
static func _create_obj(obj: String, mats: Dictionary) -> Mesh:
|
||||||
# Setup
|
# Setup
|
||||||
var mesh := ArrayMesh.new()
|
var mesh: ArrayMesh = ArrayMesh.new()
|
||||||
var vertices := PackedVector3Array()
|
var vertices: PackedVector3Array = PackedVector3Array()
|
||||||
var normals := PackedVector3Array()
|
var normals: PackedVector3Array = PackedVector3Array()
|
||||||
var uvs := PackedVector2Array()
|
var uvs: PackedVector2Array = PackedVector2Array()
|
||||||
var faces := {}
|
var faces: Dictionary = {}
|
||||||
|
|
||||||
var mat_name := "default"
|
var mat_name: String = "default"
|
||||||
var count_mtl := 0
|
var count_mtl: int = 0
|
||||||
|
|
||||||
# Parse
|
# Parse
|
||||||
var lines := obj.split("\n", false)
|
var lines: PackedStringArray = obj.split("\n", false)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
var parts := line.split(" ", false)
|
var parts: PackedStringArray = line.split(" ", false)
|
||||||
match parts[0]:
|
match parts[0]:
|
||||||
"#":
|
"#":
|
||||||
# Comment
|
# Comment
|
||||||
#print("Comment: "+line)
|
|
||||||
pass
|
pass
|
||||||
"v":
|
"v":
|
||||||
# Vertex
|
# Vertice
|
||||||
var n_v := Vector3(float(parts[1]), float(parts[2]), float(parts[3]))
|
var n_v: Vector3 = Vector3(
|
||||||
|
parts[1].to_float(), parts[2].to_float(), parts[3].to_float()
|
||||||
|
)
|
||||||
vertices.append(n_v)
|
vertices.append(n_v)
|
||||||
"vn":
|
"vn":
|
||||||
# Normal
|
# Normal
|
||||||
var n_vn := Vector3(float(parts[1]), float(parts[2]), float(parts[3]))
|
var n_vn: Vector3 = Vector3(
|
||||||
|
parts[1].to_float(), parts[2].to_float(), parts[3].to_float()
|
||||||
|
)
|
||||||
normals.append(n_vn)
|
normals.append(n_vn)
|
||||||
"vt":
|
"vt":
|
||||||
# UV
|
# UV
|
||||||
var n_uv := Vector2(float(parts[1]), 1 - float(parts[2]))
|
var n_uv: Vector2 = Vector2(parts[1].to_float(), 1 - parts[2].to_float())
|
||||||
uvs.append(n_uv)
|
uvs.append(n_uv)
|
||||||
"usemtl":
|
"usemtl":
|
||||||
# Material group
|
# Material group
|
||||||
count_mtl += 1
|
count_mtl += 1
|
||||||
mat_name = parts[1]
|
mat_name = parts[1].strip_edges()
|
||||||
if not faces.has(mat_name):
|
if !faces.has(mat_name):
|
||||||
var mats_keys := mats.keys()
|
var mats_keys: Array = mats.keys()
|
||||||
if !mats.has(mat_name):
|
if !mats.has(mat_name):
|
||||||
if mats_keys.size() > count_mtl:
|
if mats_keys.size() > count_mtl:
|
||||||
mat_name = mats_keys[count_mtl]
|
mat_name = mats_keys[count_mtl]
|
||||||
faces[mat_name] = []
|
faces[mat_name] = []
|
||||||
"f":
|
"f":
|
||||||
if not faces.has(mat_name):
|
if !faces.has(mat_name):
|
||||||
var mats_keys := mats.keys()
|
var mats_keys: Array = mats.keys()
|
||||||
if mats_keys.size() > count_mtl:
|
if mats_keys.size() > count_mtl:
|
||||||
mat_name = mats_keys[count_mtl]
|
mat_name = mats_keys[count_mtl]
|
||||||
faces[mat_name] = []
|
faces[mat_name] = []
|
||||||
# Face
|
# Face
|
||||||
if parts.size() == 4:
|
if parts.size() == 4:
|
||||||
# Tri
|
# Tri
|
||||||
var face := {"v": [], "vt": [], "vn": []}
|
var face: Dictionary = {"v": [], "vt": [], "vn": []}
|
||||||
for map in parts:
|
for map in parts:
|
||||||
var vertices_index := map.split("/")
|
var vertices_index: PackedStringArray = map.split("/")
|
||||||
if str(vertices_index[0]) != "f":
|
if vertices_index[0] != "f":
|
||||||
face["v"].append(int(vertices_index[0]) - 1)
|
face["v"].append(vertices_index[0].to_int() - 1)
|
||||||
face["vt"].append(int(vertices_index[1]) - 1)
|
if vertices_index.size() > 1:
|
||||||
if vertices_index.size() > 2:
|
face["vt"].append(vertices_index[1].to_int() - 1)
|
||||||
face["vn"].append(int(vertices_index[2]) - 1)
|
if vertices_index.size() > 2:
|
||||||
|
face["vn"].append(vertices_index[2].to_int() - 1)
|
||||||
if faces.has(mat_name):
|
if faces.has(mat_name):
|
||||||
faces[mat_name].append(face)
|
faces[mat_name].append(face)
|
||||||
elif parts.size() > 4:
|
elif parts.size() > 4:
|
||||||
# Triangulate
|
# Triangulate
|
||||||
var points: Array[PackedInt64Array] = []
|
var points: Array[Array] = []
|
||||||
for map in parts:
|
for map in parts:
|
||||||
var vertices_index = map.split("/")
|
var vertices_index: PackedStringArray = map.split("/")
|
||||||
if str(vertices_index[0]) != "f":
|
if vertices_index[0] != "f":
|
||||||
var point: PackedInt64Array = []
|
var point: Array[int] = []
|
||||||
point.append(int(vertices_index[0]) - 1)
|
point.append(vertices_index[0].to_int() - 1)
|
||||||
point.append(int(vertices_index[1]) - 1)
|
point.append(vertices_index[1].to_int() - 1)
|
||||||
if vertices_index.size() > 2:
|
if vertices_index.size() > 2:
|
||||||
point.append(int(vertices_index[2]) - 1)
|
point.append(vertices_index[2].to_int() - 1)
|
||||||
points.append(point)
|
points.append(point)
|
||||||
for i in points.size():
|
for i in points.size():
|
||||||
if i != 0:
|
if i != 0:
|
||||||
var face = {"v": [], "vt": [], "vn": []}
|
var face = {"v": [], "vt": [], "vn": []}
|
||||||
var point0 := points[0]
|
var point0: Array[int] = points[0]
|
||||||
var point1 := points[i]
|
var point1: Array[int] = points[i]
|
||||||
var point2 := points[i - 1]
|
var point2: Array[int] = points[i - 1]
|
||||||
face["v"].append(point0[0])
|
face["v"].append(point0[0])
|
||||||
face["v"].append(point2[0])
|
face["v"].append(point2[0])
|
||||||
face["v"].append(point1[0])
|
face["v"].append(point1[0])
|
||||||
|
@ -236,18 +259,16 @@ static func _create_obj(obj: String, mats: Dictionary) -> Mesh:
|
||||||
# Make tri
|
# Make tri
|
||||||
for matgroup in faces.keys():
|
for matgroup in faces.keys():
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
print(
|
prints(
|
||||||
(
|
"Creating surface for matgroup",
|
||||||
"Creating surface for matgroup "
|
matgroup,
|
||||||
+ matgroup
|
"with",
|
||||||
+ " with "
|
str(faces[matgroup].size()),
|
||||||
+ str(faces[matgroup].size())
|
"faces"
|
||||||
+ " faces"
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
|
|
||||||
# Mesh Assembler
|
# Mesh Assembler
|
||||||
var st := SurfaceTool.new()
|
var st: SurfaceTool = SurfaceTool.new()
|
||||||
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
st.begin(Mesh.PRIMITIVE_TRIANGLES)
|
||||||
if !mats.has(matgroup):
|
if !mats.has(matgroup):
|
||||||
mats[matgroup] = StandardMaterial3D.new()
|
mats[matgroup] = StandardMaterial3D.new()
|
||||||
|
@ -255,37 +276,38 @@ static func _create_obj(obj: String, mats: Dictionary) -> Mesh:
|
||||||
for face in faces[matgroup]:
|
for face in faces[matgroup]:
|
||||||
if face["v"].size() == 3:
|
if face["v"].size() == 3:
|
||||||
# Vertices
|
# Vertices
|
||||||
var fan_v := PackedVector3Array()
|
var fan_v: PackedVector3Array = PackedVector3Array()
|
||||||
fan_v.append(vertices[face["v"][0]])
|
fan_v.append(vertices[face["v"][0]])
|
||||||
fan_v.append(vertices[face["v"][2]])
|
fan_v.append(vertices[face["v"][2]])
|
||||||
fan_v.append(vertices[face["v"][1]])
|
fan_v.append(vertices[face["v"][1]])
|
||||||
|
|
||||||
# Normals
|
# Normals
|
||||||
var fan_vn := PackedVector3Array()
|
var fan_vn: PackedVector3Array = PackedVector3Array()
|
||||||
if face["vn"].size() > 0:
|
if face["vn"].size() > 0:
|
||||||
fan_vn.append(normals[face["vn"][0]])
|
fan_vn.append(normals[face["vn"][0]])
|
||||||
fan_vn.append(normals[face["vn"][2]])
|
fan_vn.append(normals[face["vn"][2]])
|
||||||
fan_vn.append(normals[face["vn"][1]])
|
fan_vn.append(normals[face["vn"][1]])
|
||||||
|
|
||||||
# Textures
|
# Textures
|
||||||
var fan_vt := PackedVector2Array()
|
var fan_vt: PackedVector2Array = PackedVector2Array()
|
||||||
if face["vt"].size() > 0:
|
if face["vt"].size() > 0:
|
||||||
for k in [0, 2, 1]:
|
for k in [0, 2, 1]:
|
||||||
var f = face["vt"][k]
|
var f = face["vt"][k]
|
||||||
if f > -1:
|
if f > -1:
|
||||||
var uv = uvs[f]
|
var uv = uvs[f]
|
||||||
fan_vt.append(uv)
|
fan_vt.append(uv)
|
||||||
|
|
||||||
st.add_triangle_fan(
|
st.add_triangle_fan(
|
||||||
fan_v, fan_vt, PackedColorArray(), PackedVector2Array(), fan_vn, []
|
fan_v, fan_vt, PackedColorArray(), PackedVector2Array(), fan_vn, []
|
||||||
)
|
)
|
||||||
mesh = st.commit(mesh)
|
mesh = st.commit(mesh)
|
||||||
|
|
||||||
for k in mesh.get_surface_count():
|
for k in mesh.get_surface_count():
|
||||||
var mat := mesh.surface_get_material(k)
|
var mat: Material = mesh.surface_get_material(k)
|
||||||
mat_name = ""
|
mat_name = ""
|
||||||
for m in mats:
|
for m in mats:
|
||||||
if mats[m] == mat:
|
if mats[m] == mat:
|
||||||
mat_name = m
|
mat_name = m
|
||||||
mesh.surface_set_name(k, mat_name)
|
mesh.surface_set_name(k, mat_name)
|
||||||
|
|
||||||
# Finish
|
# Finish
|
||||||
return mesh
|
return mesh
|
||||||
|
|
|
@ -367,7 +367,7 @@ func _set_node_values(to_edit: Object, properties: Dictionary) -> void:
|
||||||
if property_path.ends_with("v2"):
|
if property_path.ends_with("v2"):
|
||||||
property_path = property_path.replace("v2", "")
|
property_path = property_path.replace("v2", "")
|
||||||
var value = to_edit.get_indexed(property_path)
|
var value = to_edit.get_indexed(property_path)
|
||||||
if value == null:
|
if not is_instance_valid(value):
|
||||||
continue
|
continue
|
||||||
if "scale" in prop:
|
if "scale" in prop:
|
||||||
value *= 100
|
value *= 100
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1"]
|
[ext_resource type="PackedScene" uid="uid://ctfgfelg0sho8" path="res://src/Tools/BaseTool.tscn" id="1"]
|
||||||
[ext_resource type="Script" path="res://src/Tools/3DTools/3DShapeEdit.gd" id="2"]
|
[ext_resource type="Script" path="res://src/Tools/3DTools/3DShapeEdit.gd" id="2"]
|
||||||
[ext_resource type="PackedScene" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="3"]
|
[ext_resource type="PackedScene" uid="uid://bbnqcxa20a5a5" path="res://src/UI/Nodes/Sliders/ValueSliderV2.tscn" id="3"]
|
||||||
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="4"]
|
[ext_resource type="PackedScene" uid="uid://yjhp0ssng2mp" path="res://src/UI/Nodes/Sliders/ValueSlider.tscn" id="4"]
|
||||||
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="5"]
|
[ext_resource type="Script" path="res://src/UI/Nodes/Sliders/ValueSlider.gd" id="5"]
|
||||||
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="6"]
|
[ext_resource type="Script" path="res://src/UI/Nodes/CollapsibleContainer.gd" id="6"]
|
||||||
|
@ -521,7 +521,6 @@ unique_name_in_owner = true
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
selected = 0
|
|
||||||
|
|
||||||
[node name="MeshPixelSizeLabel" type="Label" parent="ObjectOptions/MeshOptions/GridContainer" index="24"]
|
[node name="MeshPixelSizeLabel" type="Label" parent="ObjectOptions/MeshOptions/GridContainer" index="24"]
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
|
|
@ -19,9 +19,14 @@ var active_cursor: GradientCursor: ## Showing a color picker popup to change a
|
||||||
i.queue_redraw()
|
i.queue_redraw()
|
||||||
var texture := GradientTexture2D.new()
|
var texture := GradientTexture2D.new()
|
||||||
var gradient := Gradient.new()
|
var gradient := Gradient.new()
|
||||||
|
var presets: Array[Gradient] = []
|
||||||
|
|
||||||
@onready var x_offset: float = size.x - GradientCursor.WIDTH
|
@onready var x_offset: float = size.x - GradientCursor.WIDTH
|
||||||
@onready var offset_value_slider := %OffsetValueSlider as ValueSlider
|
@onready var offset_value_slider := %OffsetValueSlider as ValueSlider
|
||||||
|
@onready var interpolation_option_button: OptionButton = %InterpolationOptionButton
|
||||||
|
@onready var color_space_option_button: OptionButton = %ColorSpaceOptionButton
|
||||||
|
@onready var tools_menu_button: MenuButton = %ToolsMenuButton
|
||||||
|
@onready var presets_menu_button: MenuButton = %PresetsMenuButton
|
||||||
@onready var texture_rect := $TextureRect as TextureRect
|
@onready var texture_rect := $TextureRect as TextureRect
|
||||||
@onready var color_picker := $Popup.get_node("ColorPicker") as ColorPicker
|
@onready var color_picker := $Popup.get_node("ColorPicker") as ColorPicker
|
||||||
@onready var divide_dialog := $DivideConfirmationDialog as ConfirmationDialog
|
@onready var divide_dialog := $DivideConfirmationDialog as ConfirmationDialog
|
||||||
|
@ -131,14 +136,23 @@ class GradientCursor:
|
||||||
|
|
||||||
func _init() -> void:
|
func _init() -> void:
|
||||||
texture.gradient = gradient
|
texture.gradient = gradient
|
||||||
|
presets.append(Gradient.new()) # Left to right
|
||||||
|
presets.append(Gradient.new()) # Left to transparent
|
||||||
|
presets.append(Gradient.new()) # Black to white
|
||||||
|
|
||||||
|
|
||||||
func _ready() -> void:
|
func _ready() -> void:
|
||||||
texture_rect.texture = texture
|
texture_rect.texture = texture
|
||||||
_create_cursors()
|
_create_cursors()
|
||||||
%InterpolationOptionButton.select(gradient.interpolation_mode)
|
interpolation_option_button.select(gradient.interpolation_mode)
|
||||||
%ColorSpaceOptionButton.select(gradient.interpolation_color_space)
|
color_space_option_button.select(gradient.interpolation_color_space)
|
||||||
%ToolsMenuButton.get_popup().index_pressed.connect(_on_tools_menu_button_index_pressed)
|
tools_menu_button.get_popup().index_pressed.connect(_on_tools_menu_button_index_pressed)
|
||||||
|
presets_menu_button.get_popup().index_pressed.connect(_on_presets_menu_button_index_pressed)
|
||||||
|
for preset in presets:
|
||||||
|
var grad_texture := GradientTexture2D.new()
|
||||||
|
grad_texture.height = 32
|
||||||
|
grad_texture.gradient = preset
|
||||||
|
presets_menu_button.get_popup().add_icon_item(grad_texture, "")
|
||||||
|
|
||||||
|
|
||||||
func _create_cursors() -> void:
|
func _create_cursors() -> void:
|
||||||
|
@ -256,6 +270,22 @@ func _on_tools_menu_button_index_pressed(index: int) -> void:
|
||||||
divide_dialog.popup_centered()
|
divide_dialog.popup_centered()
|
||||||
|
|
||||||
|
|
||||||
|
func _on_presets_menu_button_about_to_popup() -> void:
|
||||||
|
# Update left to right and left to transparent gradients
|
||||||
|
presets[0].set_color(0, Tools.get_assigned_color(MOUSE_BUTTON_LEFT))
|
||||||
|
presets[0].set_color(1, Tools.get_assigned_color(MOUSE_BUTTON_RIGHT))
|
||||||
|
presets[1].set_color(0, Tools.get_assigned_color(MOUSE_BUTTON_LEFT))
|
||||||
|
presets[1].set_color(1, Color(0, 0, 0, 0))
|
||||||
|
|
||||||
|
|
||||||
|
func _on_presets_menu_button_index_pressed(index: int) -> void:
|
||||||
|
var item_icon := presets_menu_button.get_popup().get_item_icon(index) as GradientTexture2D
|
||||||
|
gradient = item_icon.gradient.duplicate()
|
||||||
|
texture.gradient = gradient
|
||||||
|
_create_cursors()
|
||||||
|
updated.emit(gradient, continuous_change)
|
||||||
|
|
||||||
|
|
||||||
func _on_DivideConfirmationDialog_confirmed() -> void:
|
func _on_DivideConfirmationDialog_confirmed() -> void:
|
||||||
var add_point_to_end := add_point_end_check_box.button_pressed
|
var add_point_to_end := add_point_end_check_box.button_pressed
|
||||||
var parts := number_of_parts_spin_box.value
|
var parts := number_of_parts_spin_box.value
|
||||||
|
|
|
@ -15,6 +15,7 @@ layout_mode = 2
|
||||||
|
|
||||||
[node name="OffsetValueSlider" type="TextureProgressBar" parent="InterpolationContainer"]
|
[node name="OffsetValueSlider" type="TextureProgressBar" parent="InterpolationContainer"]
|
||||||
unique_name_in_owner = true
|
unique_name_in_owner = true
|
||||||
|
custom_minimum_size = Vector2(64, 0)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
size_flags_horizontal = 3
|
size_flags_horizontal = 3
|
||||||
focus_mode = 2
|
focus_mode = 2
|
||||||
|
@ -38,6 +39,7 @@ size_flags_horizontal = 3
|
||||||
tooltip_text = "Interpolation"
|
tooltip_text = "Interpolation"
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
selected = 0
|
selected = 0
|
||||||
|
fit_to_longest_item = false
|
||||||
item_count = 3
|
item_count = 3
|
||||||
popup/item_0/text = "Linear"
|
popup/item_0/text = "Linear"
|
||||||
popup/item_1/text = "Constant"
|
popup/item_1/text = "Constant"
|
||||||
|
@ -52,6 +54,7 @@ size_flags_horizontal = 3
|
||||||
tooltip_text = "Color space"
|
tooltip_text = "Color space"
|
||||||
mouse_default_cursor_shape = 2
|
mouse_default_cursor_shape = 2
|
||||||
selected = 0
|
selected = 0
|
||||||
|
fit_to_longest_item = false
|
||||||
item_count = 3
|
item_count = 3
|
||||||
popup/item_0/text = "sRGB"
|
popup/item_0/text = "sRGB"
|
||||||
popup/item_1/text = "Linear sRGB"
|
popup/item_1/text = "Linear sRGB"
|
||||||
|
@ -74,6 +77,14 @@ popup/item_1/id = 1
|
||||||
popup/item_2/text = "Divide into equal parts"
|
popup/item_2/text = "Divide into equal parts"
|
||||||
popup/item_2/id = 2
|
popup/item_2/id = 2
|
||||||
|
|
||||||
|
[node name="PresetsMenuButton" type="MenuButton" parent="InterpolationContainer"]
|
||||||
|
unique_name_in_owner = true
|
||||||
|
layout_mode = 2
|
||||||
|
size_flags_horizontal = 3
|
||||||
|
mouse_default_cursor_shape = 2
|
||||||
|
text = "Presets"
|
||||||
|
flat = false
|
||||||
|
|
||||||
[node name="TextureRect" type="TextureRect" parent="."]
|
[node name="TextureRect" type="TextureRect" parent="."]
|
||||||
custom_minimum_size = Vector2(0, 30)
|
custom_minimum_size = Vector2(0, 30)
|
||||||
layout_mode = 2
|
layout_mode = 2
|
||||||
|
@ -129,5 +140,6 @@ text = "Add point at the end"
|
||||||
[connection signal="value_changed" from="InterpolationContainer/OffsetValueSlider" to="." method="_on_offset_value_slider_value_changed"]
|
[connection signal="value_changed" from="InterpolationContainer/OffsetValueSlider" to="." method="_on_offset_value_slider_value_changed"]
|
||||||
[connection signal="item_selected" from="InterpolationContainer/InterpolationOptionButton" to="." method="_on_InterpolationOptionButton_item_selected"]
|
[connection signal="item_selected" from="InterpolationContainer/InterpolationOptionButton" to="." method="_on_InterpolationOptionButton_item_selected"]
|
||||||
[connection signal="item_selected" from="InterpolationContainer/ColorSpaceOptionButton" to="." method="_on_color_space_option_button_item_selected"]
|
[connection signal="item_selected" from="InterpolationContainer/ColorSpaceOptionButton" to="." method="_on_color_space_option_button_item_selected"]
|
||||||
|
[connection signal="about_to_popup" from="InterpolationContainer/PresetsMenuButton" to="." method="_on_presets_menu_button_about_to_popup"]
|
||||||
[connection signal="color_changed" from="Popup/ColorPicker" to="." method="_on_ColorPicker_color_changed"]
|
[connection signal="color_changed" from="Popup/ColorPicker" to="." method="_on_ColorPicker_color_changed"]
|
||||||
[connection signal="confirmed" from="DivideConfirmationDialog" to="." method="_on_DivideConfirmationDialog_confirmed"]
|
[connection signal="confirmed" from="DivideConfirmationDialog" to="." method="_on_DivideConfirmationDialog_confirmed"]
|
||||||
|
|
Loading…
Reference in a new issue