generated from SGDA/GodotExampleProject
104 lines
2.9 KiB
GDScript
104 lines
2.9 KiB
GDScript
@tool
|
|
extends Node
|
|
|
|
const CACHE_DIR:String = "user://_guide_cache"
|
|
|
|
@onready var _sub_viewport:SubViewport = %SubViewport
|
|
@onready var _root:Node2D = %Root
|
|
@onready var _scene_holder = %SceneHolder
|
|
|
|
var _pending_requests:Array[Job] = []
|
|
var _current_request:Job = null
|
|
var _fetch_image:bool = false
|
|
|
|
func _ready():
|
|
# keep working when game is paused
|
|
process_mode = Node.PROCESS_MODE_ALWAYS
|
|
# don't needlessly eat performance
|
|
if _pending_requests.is_empty():
|
|
set_process(false)
|
|
|
|
|
|
func clear_cache():
|
|
var files = DirAccess.get_files_at(CACHE_DIR)
|
|
for file in files:
|
|
DirAccess.remove_absolute(CACHE_DIR + "/" + file)
|
|
|
|
## Makes an icon for the given input and returns a Texture2D with the icon. Icons
|
|
## are cached on disk so subsequent calls for the same input will be faster.
|
|
func make_icon(input:GUIDEInput, renderer:GUIDEIconRenderer, height_px:int) -> Texture2D:
|
|
DirAccess.make_dir_recursive_absolute(CACHE_DIR)
|
|
var cache_key = (str(height_px) + renderer.cache_key(input)).sha256_text()
|
|
var cache_path = "user://_guide_cache/" + cache_key + ".res"
|
|
if ResourceLoader.exists(cache_path):
|
|
return ResourceLoader.load(cache_path, "Texture2D")
|
|
|
|
var job = Job.new()
|
|
job.height = height_px
|
|
job.input = input
|
|
job.renderer = renderer
|
|
_pending_requests.append(job)
|
|
set_process(true)
|
|
|
|
await job.done
|
|
|
|
var image_texture = ImageTexture.create_from_image(job.result)
|
|
ResourceSaver.save(image_texture, cache_path)
|
|
image_texture.take_over_path(cache_path)
|
|
|
|
return image_texture
|
|
|
|
|
|
|
|
func _process(delta):
|
|
if _current_request == null and _pending_requests.is_empty():
|
|
# nothing more to do..
|
|
set_process(false)
|
|
return
|
|
|
|
# nothing in progress, so pick the next request
|
|
if _current_request == null:
|
|
_current_request = _pending_requests.pop_front()
|
|
var renderer = _current_request.renderer
|
|
_root.add_child(renderer)
|
|
|
|
renderer.render(_current_request.input)
|
|
await get_tree().process_frame
|
|
|
|
var actual_size = renderer.get_rect().size
|
|
var scale = float(_current_request.height) / float(actual_size.y)
|
|
_root.scale = Vector2.ONE * scale
|
|
_sub_viewport.size = actual_size * scale
|
|
|
|
_sub_viewport.render_target_update_mode = SubViewport.UPDATE_ALWAYS
|
|
|
|
# give the renderer some time to update itself. 3 frames seem
|
|
# to work nicely and keep things speedy.
|
|
await get_tree().process_frame
|
|
await get_tree().process_frame
|
|
await get_tree().process_frame
|
|
|
|
_fetch_image = true
|
|
return
|
|
|
|
# fetch the image after the renderer is done
|
|
if _fetch_image:
|
|
# we're done. make a copy of the viewport texture
|
|
var image:Image = _scene_holder.texture.get_image()
|
|
_current_request.result = image
|
|
_current_request.done.emit()
|
|
_current_request = null
|
|
# remove the renderer
|
|
_root.remove_child(_root.get_child(0))
|
|
_sub_viewport.render_target_update_mode = SubViewport.UPDATE_DISABLED
|
|
_fetch_image = false
|
|
|
|
class Job:
|
|
signal done()
|
|
var height:int
|
|
var input:GUIDEInput
|
|
var renderer:GUIDEIconRenderer
|
|
var result:Image
|
|
|
|
|