15var warm_profiles := {}
16var requested_sprites := {}
17var texture_cache := {}
18var scaled_texture_cache := {}
19var animation_frame_cache := {}
20var path_texture_cache := {}
21var sheet_cell_cache := {}
22var source_image_cache := {}
23var greyscale_material_cache:ShaderMaterial = null
25const SpriteAnimationRect = preload(
"res://scripts/systems/spriteManager/sprite_animation_rect.gd")
29func load_pack(file_path:String) -> void:
30 var file = FileAccess.open(file_path, FileAccess.READ)
33 var data = JSON.parse_string(file.get_as_text())
34 if not data
is Dictionary:
36 load_pack_data(data, file_path.get_file().get_basename())
40func load_pack_data(data:Dictionary, fallback_pack_id:String =
"sprite_pack") -> void:
41 var pack_id = str(data.get(
"id", fallback_pack_id))
42 packs[pack_id] = data.duplicate(true)
43 if data.has(
"sprite_sets"):
44 _clear_sheet_dependent_cache()
45 for set_id
in data.get(
"sprite_sets", {}).keys():
46 var set_definition = data[
"sprite_sets"][set_id].duplicate(true)
47 set_definition[
"id"] = str(set_id)
48 set_definition[
"pack_id"] = pack_id
49 sprite_sets[str(set_id)] = set_definition
50 for profile_id
in data.get(
"warm_profiles", {}).keys():
51 var warm_profile = data[
"warm_profiles"][profile_id].duplicate(true)
52 warm_profile[
"id"] = str(profile_id)
53 warm_profile[
"pack_id"] = pack_id
54 warm_profiles[str(profile_id)] = warm_profile
55 for required
in data.get(
"required_sprites", []):
56 if required
is Dictionary:
57 ensure_required_sprites(required)
58 for sprite_id
in data.get(
"sprites", {}).keys():
59 var sprite = data[
"sprites"][sprite_id].duplicate(true)
60 sprite[
"id"] = str(sprite_id)
61 sprite[
"pack_id"] = pack_id
62 _invalidate_sprite_cache(str(sprite_id))
63 sprites[str(sprite_id)] = sprite
67func manifest_with_required_sprites(data:Dictionary) -> Dictionary:
68 var next_data = data.duplicate(true)
69 var next_sprites = next_data.get(
"sprites", {})
70 if not next_sprites
is Dictionary:
72 for required
in next_data.get(
"required_sprites", []):
73 if not required
is Dictionary:
75 for entry
in required_sprite_entries(required):
76 var id = str(entry.get(
"id",
""))
77 if id !=
"" and not next_sprites.has(id):
78 next_sprites[id] = entry
79 next_data[
"sprites"] = next_sprites
84func load_packs(file_paths:Array) -> void:
85 for file_path
in file_paths:
86 load_pack(str(file_path))
90func get_sprite(sprite_id:String) -> Dictionary:
91 return sprites.get(sprite_id, {}).duplicate(true)
95func get_sprite_set(set_id:String) -> Dictionary:
96 return sprite_sets.get(set_id, {}).duplicate(true)
100func get_sprite_path(sprite_id:String, default_path:String =
"") -> String:
101 var sprite = sprites.get(sprite_id, {})
102 if not sprite
is Dictionary:
104 return str(sprite.get(
"path", default_path))
108func get_texture(sprite_id:String):
109 if texture_cache.has(sprite_id):
110 return texture_cache[sprite_id]
111 var sprite = sprites.get(sprite_id, {})
112 if not sprite
is Dictionary
or sprite.is_empty():
115 if sprite.has(
"animation"):
116 var frames = get_animation_frames(sprite_id)
117 texture = frames[0]
if not frames.is_empty()
else null
118 elif sprite.has(
"sheet")
or sprite.has(
"cell"):
119 texture = _texture_from_sheet(sprite)
121 var path = str(sprite.get(
"path",
""))
124 texture = get_texture_for_path(path)
126 texture_cache[sprite_id] = texture
131func get_scaled_texture(sprite_id:String, size:int = 32):
132 var cache_key =
"%s|%d" % [sprite_id, size]
133 if scaled_texture_cache.has(cache_key):
134 return scaled_texture_cache[cache_key]
135 var texture = get_texture(sprite_id)
136 if texture == null
or not texture
is Texture2D:
138 var sprite = sprites.get(sprite_id, {})
139 var path = str(sprite.get(
"path",
""))
if sprite
is Dictionary
else ""
140 var image = _image_from_texture_or_path(texture, path)
141 if image == null
or image.is_empty():
143 image.resize(size, size, Image.INTERPOLATE_NEAREST)
144 var scaled = ImageTexture.create_from_image(image)
145 scaled_texture_cache[cache_key] = scaled
150func get_texture_with_fallback(sprite_ids:Array):
151 for sprite_id
in sprite_ids:
152 var texture = get_texture(str(sprite_id))
159func rotation_for_vector(direction:Vector2, base_direction:String =
"right") -> float:
160 if direction.length_squared() <= 0.0001:
162 return direction.angle() - _angle_for_direction(base_direction)
166func get_texture_for_definition(definition:Dictionary, options:Dictionary = {}):
167 var sprite_key = str(options.get(
"sprite_key",
"sprite_id"))
168 var path_key = str(options.get(
"path_key",
"image_path"))
169 var fallback_sprite_id = str(options.get(
"fallback_sprite_id",
""))
170 var sprite_id = str(definition.get(sprite_key, fallback_sprite_id))
172 var texture = get_texture(sprite_id)
175 var path = str(definition.get(path_key, definition.get(
"icon_path", definition.get(
"path",
""))))
177 return get_texture_for_path(path)
182func get_scaled_texture_for_definition(definition:Dictionary, size:int = 32, options:Dictionary = {}):
183 var sprite_key = str(options.get(
"sprite_key",
"sprite_id"))
184 var path_key = str(options.get(
"path_key",
"image_path"))
185 var fallback_sprite_id = str(options.get(
"fallback_sprite_id",
""))
186 var sprite_id = str(definition.get(sprite_key, fallback_sprite_id))
188 var texture = get_scaled_texture(sprite_id, size)
191 var path = str(definition.get(path_key, definition.get(
"icon_path", definition.get(
"path",
""))))
192 var cache_key =
"definition:%s|%d" % [path, size]
193 if scaled_texture_cache.has(cache_key):
194 return scaled_texture_cache[cache_key]
195 var texture = get_texture_for_definition(definition, {
"path_key": path_key})
196 if texture == null
or not texture
is Texture2D:
198 var image = _image_from_texture_or_path(texture, path)
199 if image == null
or image.is_empty():
201 image.resize(size, size, Image.INTERPOLATE_NEAREST)
202 var scaled = ImageTexture.create_from_image(image)
203 scaled_texture_cache[cache_key] = scaled
208func get_animation_frames(sprite_id:String) -> Array:
209 if animation_frame_cache.has(sprite_id):
210 return animation_frame_cache[sprite_id].duplicate()
211 var sprite = sprites.get(sprite_id, {})
212 if not sprite
is Dictionary
or sprite.is_empty():
214 if not sprite.has(
"animation"):
215 var texture = get_texture(sprite_id)
216 var single = [texture]
if texture != null
else []
217 animation_frame_cache[sprite_id] = single
218 return single.duplicate()
220 var animation = sprite.get(
"animation", {})
221 for cell
in _animation_cells(animation):
222 var frame_definition = sprite.duplicate(true)
223 frame_definition.erase(
"animation")
224 frame_definition[
"cell"] = cell
225 var texture = _texture_from_sheet(frame_definition)
227 frames.append(texture)
228 animation_frame_cache[sprite_id] = frames
229 return frames.duplicate()
233func get_animation_definition(sprite_id:String) -> Dictionary:
234 var sprite = sprites.get(sprite_id, {})
235 if not sprite
is Dictionary:
237 var animation = sprite.get(
"animation", {}).duplicate(true)
238 if animation.is_empty():
239 animation[
"fps"] = float(sprite.get(
"fps", 0.0))
241 animation[
"fps"] = float(animation.get(
"fps", sprite.get(
"fps", 8.0)))
242 animation[
"frames"] = _animation_cells(animation)
250func create_texture_node(sprite_id:String, options:Dictionary = {}) -> TextureRect:
251 var request_metadata = options.get(
"manifest", options)
252 record_sprite_request(sprite_id, request_metadata
if request_metadata
is Dictionary
else {})
253 var sprite = sprites.get(sprite_id, {})
254 if not sprite
is Dictionary:
256 var frames = get_animation_frames(sprite_id)
257 if frames.is_empty():
259 if frames.size() > 1:
260 var animation = get_animation_definition(sprite_id)
261 var node = SpriteAnimationRect.new()
262 var animation_options = options.duplicate()
263 animation_options[
"fps"] = float(options.get(
"fps", animation.get(
"fps", 8.0)))
264 node.configure(frames, animation_options)
265 _apply_texture_node_options(node, sprite, options)
267 var node = TextureRect.new()
268 node.texture = frames[0]
269 node.stretch_mode = TextureRect.STRETCH_KEEP_ASPECT_CENTERED
270 node.expand_mode = TextureRect.EXPAND_IGNORE_SIZE
271 node.mouse_filter = Control.MOUSE_FILTER_IGNORE
272 _apply_texture_node_options(node, sprite, options)
277func ensure_required_sprites(config:Dictionary) -> Array:
279 for sprite
in required_sprite_entries(config):
280 var id = str(sprite.get(
"id",
""))
293func record_sprite_request(sprite_id:String, metadata:Dictionary = {}) -> void:
294 sprite_id = sprite_id.strip_edges()
297 var request = requested_sprites.get(sprite_id, {})
298 request[
"id"] = sprite_id
299 request[
"required"] =
bool(metadata.get(
"required", true))
300 request[
"placeholder"] =
bool(metadata.get(
"placeholder", true))
301 for key
in [
"display_name",
"category",
"direction",
"tags"]:
302 if metadata.has(key):
303 request[key] = metadata[key]
304 if not request.has(
"display_name"):
305 request[
"display_name"] = sprite_id.capitalize().replace(
"_",
" ")
306 if not request.has(
"tags"):
308 requested_sprites[sprite_id] = request
312func get_requested_sprite_entries() -> Array:
314 var ids = requested_sprites.keys()
317 entries.append(requested_sprites[id].duplicate(true))
322func clear_requested_sprites() -> void:
323 requested_sprites.clear()
327func manifest_with_requested_sprites(data:Dictionary) -> Dictionary:
328 var next_data = data.duplicate(true)
329 var next_sprites = next_data.get(
"sprites", {})
330 if not next_sprites
is Dictionary:
332 for entry
in get_requested_sprite_entries():
333 var id = str(entry.get(
"id",
""))
334 if id ==
"" or next_sprites.has(id):
336 next_sprites[id] = entry
337 next_data[
"sprites"] = next_sprites
345func warm_texture_cache(sprite_ids:Array = []) -> Dictionary:
346 var ids := sprite_ids.duplicate()
350 "requested": ids.size(),
356 var sprite_id = str(id_value)
357 var frames = get_animation_frames(sprite_id)
358 if frames.is_empty():
359 warmed[
"missing"].append(sprite_id)
361 warmed[
"textures"] =
int(warmed[
"textures"]) + 1
362 if frames.size() > 1:
363 warmed[
"animations"] =
int(warmed[
"animations"]) + 1
367func warm_texture_cache_for_profile(profile_id:String, options:Dictionary = {}) -> Dictionary:
368 var profile:Dictionary = get_warm_profile(profile_id)
369 if profile.is_empty():
375 "scaled_textures": 0,
376 "skipped_optional": 0,
377 "missing": [profile_id]
379 var sprites_to_warm:Array = _profile_sprite_ids(profile, options)
380 var warmed:Dictionary = warm_texture_cache(sprites_to_warm)
381 warmed[
"skipped_optional"] =
int(profile.get(
"_skipped_optional", 0))
382 var scaled_count:int = 0
383 var skipped_scaled_optional:int = 0
384 for scaled_entry
in _profile_scaled_entries(profile, options):
385 if _should_skip_optional_profile_entry(scaled_entry, options):
386 skipped_scaled_optional += 1
388 var sprite_id:String = str(scaled_entry.get(
"id", scaled_entry.get(
"sprite_id",
"")))
389 var size:int = max(1,
int(scaled_entry.get(
"size", options.get(
"size", 32))))
390 if sprite_id.is_empty():
392 if get_scaled_texture(sprite_id, size) != null:
394 elif not warmed.get(
"missing", []).has(sprite_id):
395 warmed[
"missing"].append(sprite_id)
396 warmed[
"id"] = profile_id
397 warmed[
"scaled_textures"] = scaled_count
398 warmed[
"skipped_optional"] =
int(warmed.get(
"skipped_optional", 0)) + skipped_scaled_optional
402func get_warm_profile(profile_id:String) -> Dictionary:
403 return warm_profiles.get(profile_id, {}).duplicate(true)
406func get_warm_profile_ids() -> Array:
407 var ids:Array = warm_profiles.keys()
413func clear_texture_cache() -> void:
414 texture_cache.clear()
415 scaled_texture_cache.clear()
416 animation_frame_cache.clear()
417 path_texture_cache.clear()
418 sheet_cell_cache.clear()
419 source_image_cache.clear()
428func clear_transient_cache(options:Dictionary = {}) -> Dictionary:
429 var preserve_source_images:bool =
bool(options.get(
"preserve_source_images", true))
430 var preserve_path_textures:bool =
bool(options.get(
"preserve_path_textures", false))
431 var before:Dictionary = get_cache_stats()
432 texture_cache.clear()
433 scaled_texture_cache.clear()
434 animation_frame_cache.clear()
435 sheet_cell_cache.clear()
436 if not preserve_path_textures:
437 path_texture_cache.clear()
438 if not preserve_source_images:
439 source_image_cache.clear()
440 var after:Dictionary = get_cache_stats()
441 return _cache_clear_result(before, after)
448func trim_texture_cache(keep_sprite_ids:Array = [], options:Dictionary = {}) -> Dictionary:
449 var preserve_source_images:bool =
bool(options.get(
"preserve_source_images", true))
450 var preserve_path_textures:bool =
bool(options.get(
"preserve_path_textures", false))
451 var clear_sheet_cells:bool =
bool(options.get(
"clear_sheet_cells", true))
452 var keep_ids:Dictionary = {}
453 for id_value
in keep_sprite_ids:
454 var sprite_id:String = str(id_value)
456 keep_ids[sprite_id] = true
457 var before:Dictionary = get_cache_stats()
458 for sprite_id
in texture_cache.keys().duplicate():
459 if not keep_ids.has(str(sprite_id)):
460 texture_cache.erase(sprite_id)
461 for sprite_id
in animation_frame_cache.keys().duplicate():
462 if not keep_ids.has(str(sprite_id)):
463 animation_frame_cache.erase(sprite_id)
464 for cache_key
in scaled_texture_cache.keys().duplicate():
465 var owner_id:String = str(cache_key).split(
"|")[0]
466 if owner_id.begins_with(
"definition:")
or not keep_ids.has(owner_id):
467 scaled_texture_cache.erase(cache_key)
468 if clear_sheet_cells:
469 sheet_cell_cache.clear()
470 if not preserve_path_textures:
471 path_texture_cache.clear()
472 if not preserve_source_images:
473 source_image_cache.clear()
474 var after:Dictionary = get_cache_stats()
475 return _cache_clear_result(before, after)
479func _invalidate_sprite_cache(sprite_id:String) -> void:
480 texture_cache.erase(sprite_id)
481 animation_frame_cache.erase(sprite_id)
482 var existing_sprite = sprites.get(sprite_id, {})
483 if existing_sprite
is Dictionary:
484 var existing_path = str(existing_sprite.get(
"path",
""))
485 if existing_path !=
"":
486 source_image_cache.erase(existing_path)
487 for key
in scaled_texture_cache.keys():
488 if str(key).begins_with(
"%s|" % sprite_id):
489 scaled_texture_cache.erase(key)
493func _clear_sheet_dependent_cache() -> void:
494 sheet_cell_cache.clear()
495 animation_frame_cache.clear()
496 for id
in sprites.keys():
497 var sprite = sprites[id]
498 if sprite
is Dictionary
and (sprite.has(
"sheet")
or sprite.has(
"cell")
or sprite.has(
"animation")
or sprite.has(
"set")):
499 texture_cache.erase(str(id))
503func get_cache_stats() -> Dictionary:
505 "textures": texture_cache.size(),
506 "scaled_textures": scaled_texture_cache.size(),
507 "animations": animation_frame_cache.size(),
508 "path_textures": path_texture_cache.size(),
509 "sheet_cells": sheet_cell_cache.size(),
510 "source_images": source_image_cache.size()
514func _cache_clear_result(before:Dictionary, after:Dictionary) -> Dictionary:
516 for key
in before.keys():
517 cleared[key] = max(0,
int(before.get(key, 0)) -
int(after.get(key, 0)))
526func required_sprite_entries(config:Dictionary) -> Array:
527 var prefix = str(config.get(
"prefix", config.get(
"thing_id",
"")))
528 var states = config.get(
"states", [])
530 if prefix ==
"" or not states
is Array:
532 var directions = config.get(
"directions", [])
533 var directional_states = config.get(
"directional_states", states)
534 var tags = config.get(
"tags", [])
535 var category = str(config.get(
"category",
""))
537 var state_id = str(state)
538 var state_directions = directions
if _state_is_directional(state_id, directional_states)
else []
539 if state_directions
is Array
and not state_directions.is_empty():
540 for direction
in state_directions:
541 entries.append(_required_sprite_entry(config, prefix, state_id, str(direction), tags, category))
543 entries.append(_required_sprite_entry(config, prefix, state_id,
"", tags, category))
548func get_missing_assignments(required_ids:Array = []) -> Array:
549 var ids := required_ids.duplicate()
551 for id
in sprites.keys():
552 if bool(sprites[id].get(
"required", false)):
557 var sprite = get_sprite(str(id))
558 if sprite.is_empty():
559 missing.append({
"id": str(id),
"reason":
"missing_definition"})
560 elif bool(sprite.get(
"placeholder", false)):
561 missing.append({
"id": str(id),
"reason":
"placeholder"})
562 elif not _has_texture_source(sprite):
563 missing.append({
"id": str(id),
"reason":
"missing_source"})
568func find_by_tags(tags:Array) -> Array:
570 for sprite
in sprites.values():
571 var sprite_tags = sprite.get(
"tags", [])
574 if not sprite_tags.has(str(tag)):
578 matches.append(sprite.duplicate(true))
583func get_all_sprites() -> Array:
585 for sprite
in sprites.values():
586 list.append(sprite.duplicate(true))
591func get_all_sprite_sets() -> Array:
593 for set_definition
in sprite_sets.values():
594 list.append(set_definition.duplicate(true))
603 warm_profiles.clear()
604 requested_sprites.clear()
605 clear_texture_cache()
608func _has_texture_source(sprite:Dictionary) -> bool:
609 return str(sprite.get(
"path",
"")) !=
"" or sprite.has(
"sheet")
or sprite.has(
"cell")
or sprite.has(
"animation")
612func _profile_sprite_ids(profile:Dictionary, options:Dictionary = {}) -> Array:
614 var skipped_optional:int = 0
615 for key
in [
"sprites",
"sprite_ids",
"animations"]:
616 var values = profile.get(key, [])
619 if value
is Dictionary:
620 if _should_skip_optional_profile_entry(value, options):
621 skipped_optional += 1
623 var sprite_id:String = str(value.get(
"id", value.get(
"sprite_id",
"")))
624 if sprite_id !=
"" and not ids.has(sprite_id):
625 ids.append(sprite_id)
627 var sprite_id:String = str(value)
628 if sprite_id !=
"" and not ids.has(sprite_id):
629 ids.append(sprite_id)
630 if skipped_optional > 0:
631 profile[
"_skipped_optional"] = skipped_optional
635func _should_skip_optional_profile_entry(entry:Dictionary, options:Dictionary) -> bool:
636 return bool(options.get(
"skip_optional", false))
and bool(entry.get(
"optional", false))
639func _profile_scaled_entries(profile:Dictionary, options:Dictionary = {}) -> Array:
640 var entries:Array = []
641 var scaled_values = profile.get(
"scaled", profile.get(
"scaled_textures", []))
642 if scaled_values
is Array:
643 for value
in scaled_values:
644 if value
is Dictionary:
645 entries.append(value.duplicate(true))
647 entries.append({
"id": str(value),
"size":
int(options.get(
"size", 32))})
648 var scaled_sizes = profile.get(
"scaled_sizes", {})
649 if scaled_sizes
is Dictionary:
650 for sprite_id
in scaled_sizes.keys():
651 entries.append({
"id": str(sprite_id),
"size":
int(scaled_sizes[sprite_id])})
655func _apply_texture_node_options(node:TextureRect, sprite:Dictionary, options:Dictionary) -> void:
656 node.flip_h =
bool(options.get(
"mirror_h", sprite.get(
"mirror_h", sprite.get(
"flip_h", false))))
657 node.flip_v =
bool(options.get(
"mirror_v", sprite.get(
"mirror_v", sprite.get(
"flip_v", false))))
658 if bool(options.get(
"greyscale", options.get(
"grayscale", sprite.get(
"greyscale", sprite.get(
"grayscale", false))))):
659 node.material = _greyscale_material()
662func _greyscale_material() -> ShaderMaterial:
663 if greyscale_material_cache != null:
664 return greyscale_material_cache
665 var shader = Shader.new()
666 shader.code =
"shader_type canvas_item;\nvoid fragment() {\n\tvec4 color = texture(TEXTURE, UV) * COLOR;\n\tfloat grey = dot(color.rgb, vec3(0.299, 0.587, 0.114));\n\tCOLOR = vec4(vec3(grey), color.a);\n}\n"
667 var material = ShaderMaterial.new()
668 material.shader = shader
669 greyscale_material_cache = material
670 return greyscale_material_cache
673func _state_is_directional(state_id:String, directional_states) -> bool:
674 if directional_states
is Array:
675 return directional_states.has(state_id)
or directional_states.has(
"*")
676 return bool(directional_states)
679func _angle_for_direction(direction:String) -> float:
680 match direction.to_lower():
693func _required_sprite_entry(config:Dictionary, prefix:String, state_id:String, direction:String, tags, category:String) -> Dictionary:
694 var id =
"%s_%s" % [prefix, state_id]
696 id =
"%s_%s" % [id, direction]
697 var display = str(config.get(
"display_name_prefix", prefix.capitalize().replace(
"_",
" ")))
698 display +=
" " + state_id.capitalize().replace(
"_",
" ")
700 display +=
" " + direction.capitalize()
703 "display_name": display,
706 "tags": tags.duplicate(true)
if tags
is Array
else []
709 entry[
"category"] = category
711 entry[
"direction"] = direction
715func _texture_from_sheet(sprite:Dictionary):
716 var sheet = _sheet_config(sprite)
717 var path = str(sheet.get(
"path",
""))
720 var cell = _cell_config(sprite)
723 var cell_width =
int(sheet.get(
"cell_width", sheet.get(
"width", 64)))
724 var cell_height =
int(sheet.get(
"cell_height", sheet.get(
"height", 64)))
725 var row = max(0,
int(cell.get(
"row", cell.get(
"y", 0))))
726 var column = max(0,
int(cell.get(
"column", cell.get(
"x", 0))))
727 var cache_key =
"%s|%d|%d|%d|%d" % [path, cell_width, cell_height, row, column]
728 if sheet_cell_cache.has(cache_key):
729 return sheet_cell_cache[cache_key]
730 var source_image = _get_source_image(path)
731 if source_image == null
or source_image.is_empty():
732 var source_texture = get_texture_for_path(path)
733 if source_texture == null
or not source_texture
is Texture2D:
735 source_image = _image_from_texture_or_path(source_texture, path)
736 if source_image == null
or source_image.is_empty():
738 var region = Rect2i(column * cell_width, row * cell_height, cell_width, cell_height)
739 if region.position.x + region.size.x > source_image.get_width()
or region.position.y + region.size.y > source_image.get_height():
741 var image = Image.create(cell_width, cell_height, false, source_image.get_format())
742 image.blit_rect(source_image, region, Vector2i.ZERO)
743 var texture = ImageTexture.create_from_image(image)
744 sheet_cell_cache[cache_key] = texture
748func get_texture_for_path(path:String):
751 if path_texture_cache.has(path):
752 return path_texture_cache[path]
754 if _should_use_resource_loader(path):
757 var image = _get_source_image(path)
758 if image != null
and not image.is_empty():
759 texture = ImageTexture.create_from_image(image)
760 elif ResourceLoader.exists(path):
763 path_texture_cache[path] = texture
767func _get_source_image(path:String):
770 if source_image_cache.has(path):
771 return source_image_cache[path]
772 var image = _load_image(path)
773 if image != null
and not image.is_empty():
774 source_image_cache[path] = image
778func _image_from_texture_or_path(texture:Texture2D, path:String =
""):
779 if path !=
"" and source_image_cache.has(path):
780 return source_image_cache[path].duplicate()
783 var image = texture.get_image()
784 if image != null
and not image.is_empty()
and path !=
"":
785 source_image_cache[path] = image
786 return image.duplicate()
if image != null
else null
789func _sheet_config(sprite:Dictionary) -> Dictionary:
790 var sheet = sprite.get(
"sheet", {})
791 if sheet
is Dictionary
and not sheet.is_empty():
793 var set_definition = get_sprite_set(str(sheet.get(
"set",
"")))
794 for key
in sheet.keys():
796 set_definition[key] = sheet[key]
797 return set_definition
798 return sheet.duplicate(true)
799 if sprite.has(
"set"):
800 return get_sprite_set(str(sprite.get(
"set",
"")))
804func _cell_config(sprite:Dictionary) -> Dictionary:
805 var cell = sprite.get(
"cell", {})
806 if cell
is Dictionary:
807 return cell.duplicate(true)
808 if cell
is Array
and cell.size() >= 2:
809 return {
"row":
int(cell[0]),
"column":
int(cell[1])}
810 var sheet = sprite.get(
"sheet", {})
811 if sheet
is Dictionary
and (sheet.has(
"row")
or sheet.has(
"column")):
812 return {
"row":
int(sheet.get(
"row", 0)),
"column":
int(sheet.get(
"column", 0))}
816func _animation_cells(animation:Dictionary) -> Array:
818 if animation.has(
"frames")
and animation[
"frames"]
is Array:
819 for frame
in animation[
"frames"]:
820 if frame
is Dictionary:
821 cells.append(frame.duplicate(true))
822 elif frame
is Array
and frame.size() >= 2:
823 cells.append({
"row":
int(frame[0]),
"column":
int(frame[1])})
824 if cells.is_empty()
and animation.has(
"range"):
825 var range_definition = animation.get(
"range", {})
826 if range_definition
is Dictionary:
827 var row =
int(range_definition.get(
"row", 0))
828 var from_column =
int(range_definition.get(
"from_column", range_definition.get(
"start_column", 0)))
829 var to_column =
int(range_definition.get(
"to_column", range_definition.get(
"end_column", from_column)))
830 var step = 1
if to_column >= from_column
else -1
831 var column = from_column
833 cells.append({
"row": row,
"column": column})
834 if column == to_column:
840func _load_image(path:String):
843 if ResourceLoader.exists(path):
844 var resource = ResourceLoader.load(path)
845 if resource
is Texture2D:
846 var texture_image = resource.get_image()
847 if texture_image != null
and not texture_image.is_empty():
849 if not FileAccess.file_exists(path):
851 var image = Image.load_from_file(path)
852 if image == null
or image.is_empty():
857func _should_use_resource_loader(path:String) -> bool:
858 if path ==
"" or not ResourceLoader.exists(path):
860 if not OS.has_feature(
"editor"):
862 return _has_import_cache(path)
865func _has_import_cache(path:String) -> bool:
866 var import_file_path =
"%s.import" % path
867 if not FileAccess.file_exists(import_file_path):
869 var config = ConfigFile.new()
870 if config.load(import_file_path) != OK:
872 var dest_files = config.get_value(
"deps",
"dest_files", PackedStringArray())
873 for dest_file
in dest_files:
874 if FileAccess.file_exists(str(dest_file)):
int
Load and return a scaled Texture2D for UI controls that need smaller icons.