extends Node2D

@export var render_width: int = 1920
@export var render_height: int = 1080
@export var point_count: int = 1024 * 1024
@export var point_texture_width: int = 1024
var point_texture_height: int:
	get():
		@warning_ignore("integer_division")
		return point_count / point_texture_width

@export var point_speed: float = 2.0
@export var decay_factor: float = 0.95
@export var rng_seed: int = 10074

@onready var points: MultiMesh = %PointUpdateViewport/PointMesh.multimesh
@onready var points_draw: MultiMesh = %PointDrawViewport/PointMesh.multimesh
@onready var view := $View
@onready var point_update_vp := %PointUpdateViewport
@onready var trail_update_vp := %TrailUpdateViewport
@onready var point_draw_vp := %PointDrawViewport
@onready var point_shader: ShaderMaterial = %PointUpdateViewport/PointMesh.material
@onready var trail_shader: ShaderMaterial = %TrailUpdateViewport/Pass.material
@onready var point_draw_shader: ShaderMaterial = %PointDrawViewport/PointMesh.material

var _frame_count: int = 0
var point_texture: ImageTexture = null

func populate_points() -> void:
	var rng = RandomNumberGenerator.new()
	rng.seed = rng_seed
	points.instance_count = point_count
	var point_data_image: Image = Image.create_empty(point_texture_width, point_texture_height, false, Image.FORMAT_RGBAF)
	for i in point_count:
		var pos: Vector2 = Vector2(
			rng.randf_range(0, 1.0), rng.randf_range(0, 1.0)
		)
		var angle: float = rng.randf_range(0, 1.0)
		
		var x = i % point_texture_width
		@warning_ignore("integer_division")
		var y = i / point_texture_width
		point_data_image.set_pixel(x, y, Color(pos.x, pos.y, angle, 1.0))
		
		# Lets keep original positions at 0 instead of doing the below
		var t: Transform2D = Transform2D()
		points.set_instance_transform_2d(i, t)

	var render_size := Vector2i(render_width, render_height);
	var point_texture_size := Vector2i(point_texture_width, point_texture_height)
	point_texture = ImageTexture.create_from_image(point_data_image)
	point_shader.set_shader_parameter("point_texture", point_texture)
	point_shader.set_shader_parameter("point_texture_size", point_texture_size)
	point_shader.set_shader_parameter("canvas_size", render_size)
	point_shader.set_shader_parameter("point_speed", point_speed)
	point_draw_shader.set_shader_parameter("point_texture", point_texture)
	point_draw_shader.set_shader_parameter("point_texture_size", point_texture_size)
	point_draw_shader.set_shader_parameter("canvas_size", render_size)

	points_draw = points


func _ready():
	populate_points()
	RenderingServer.call_on_render_thread(_initialize_render.bind(render_width, render_height))


func _process(_delta: float) -> void:
	RenderingServer.call_on_render_thread(_render_process.bind(_frame_count, decay_factor))
	_frame_count = _frame_count + 1


# Below is for rendering

var rd: RenderingDevice = null
var sim_texture: Texture2D = null


func _create_initial_sim_texture(width: int, height: int) -> ImageTexture:
	var sim_image := Image.create_empty(width, height, false, Image.FORMAT_RGBF)
	sim_texture = ImageTexture.create_from_image(sim_image)

	return sim_texture


func _initialize_render(_width: int, _height: int) -> void:
	rd = RenderingServer.get_rendering_device()

	trail_shader.set_shader_parameter("trail_texture", point_update_vp.get_texture().get_rid())
	trail_shader.set_shader_parameter("decay_factor", decay_factor)


func _render_process(frame_count: int) -> void:
	if frame_count > 0:
		point_shader.set_shader_parameter("trail_texture", trail_update_vp.get_texture().get_rid())
		point_shader.set_shader_parameter("agent_texture", point_update_vp.get_texture().get_rid())

	view.texture = point_texture.get_rid()
	trail_shader.set_shader_parameter("decay_factor", decay_factor)
	#trail_shader.set_shader_parameter("trail_texture", point_update_vp.get_texture().get_rid())
	# point_shader.set_shader_parameter("sim_texture", trail_update_vp.get_texture().get_rid())
