tool
class_name MMMateial
extends Resource

#threads are implemented using my thread pool engine module.
#if you want to use this without that module in your engine set this to false,
#and comment out the lines that give errors
const USE_THREADS = true

export(Vector2) var image_size : Vector2 = Vector2(128, 128)
export(Array) var nodes : Array

var initialized : bool = false
var rendering : bool = false
var queued_render : bool = false
var job : ThreadPoolExecuteJob = ThreadPoolExecuteJob.new()

func initialize():
	if !initialized:
		initialized = true
		
		job.setup(self, "_thread_func")
		
		for n in nodes:
			n.init_properties()
			n.connect("changed", self, "on_node_changed")

func add_node(node : MMNode) -> void:
	nodes.append(node)
	
	node.connect("changed", self, "on_node_changed")
	
	emit_changed()
	
func remove_node(node : MMNode) -> void:
	if !node:
		return
	
	for op in node.output_properties:
		for n in nodes:
			if n:
				for ip in n.input_properties:
						if ip.input_property == op:
							ip.set_input_property(null)
	
	nodes.erase(node)
	
	node.disconnect("changed", self, "on_node_changed")
	
	emit_changed()

func render() -> void:
	initialize()
	
	if rendering:
		queued_render = true
		return
	
	if USE_THREADS:
		render_threaded()
	else:
		render_non_threaded()
	
func render_non_threaded() -> void:
	var did_render : bool = true
		
	while did_render:
		did_render = false
		
		for n in nodes:
			if n && n.render(self):
				did_render = true

func render_threaded() -> void:
	job.cancelled = false
	
	if !ThreadPool.has_job(job):
		ThreadPool.add_job(job)

func _thread_func() -> void:
	if job.cancelled:
		rendering = false
		return
	
	rendering = true
	job.cancelled = false
	
	var did_render : bool = true
		
	while did_render:
		did_render = false
		
		for n in nodes:
			if n && n.render(self):
				did_render = true
				
			if job.cancelled:
				rendering = false
				return
				
	rendering = false
	
	if queued_render:
		queued_render = false
		_thread_func()

func cancel_render_and_wait() -> void:
	if rendering:
		ThreadPool.cancel_job_wait(job)
		
		job.cancelled = false
		
		pass

func on_node_changed() -> void:
	emit_changed()
	call_deferred("render")
