extends Node2D ## Fog overlay controller — manages ColorRect + shader uniforms for D-059 fog. ## Reads textures from FogState autoload, positions rect to cover viewport. ## Architecture: docs/architecture/fog-shader-spec.md var _fog_rect: ColorRect var _shader_mat: ShaderMaterial const TILE_SIZE := float(Constants.TILE_SIZE) func _ready() -> void: # Create the fog overlay ColorRect _fog_rect = ColorRect.new() _fog_rect.name = "FogRect" add_child(_fog_rect) # Load shader and create material var shader := load("res://shaders/fog.gdshader") as Shader _shader_mat = ShaderMaterial.new() _shader_mat.shader = shader _fog_rect.material = _shader_mat # Create seamless noise texture for fog animation var noise := FastNoiseLite.new() noise.noise_type = FastNoiseLite.TYPE_PERLIN noise.frequency = 0.03 var noise_tex := NoiseTexture2D.new() noise_tex.noise = noise noise_tex.width = 256 noise_tex.height = 256 noise_tex.seamless = true _shader_mat.set_shader_parameter("noise_tex", noise_tex) _shader_mat.set_shader_parameter("tile_size", TILE_SIZE) print("FogShader: Initialized (D-059 5-layer)") func update_fog() -> void: # 1. Update FogState textures from GameState FogState.update_from_state() # 2. Position ColorRect to cover the current viewport var vp_size := get_viewport().get_visible_rect().size var zoom := Vector2(2.0, 2.0) # Must match Camera2D zoom var camera_pos := GameState.player_position * TILE_SIZE var half_view := vp_size / (2.0 * zoom) _fog_rect.position = camera_pos - half_view _fog_rect.size = vp_size / zoom # 3. Update shader uniforms _shader_mat.set_shader_parameter("visibility_tex", FogState.visibility_texture) _shader_mat.set_shader_parameter("exploration_tex", FogState.exploration_texture) _shader_mat.set_shader_parameter("zone_tint_tex", FogState.zone_tint_texture) _shader_mat.set_shader_parameter("rect_pos", _fog_rect.position) _shader_mat.set_shader_parameter("rect_sz", _fog_rect.size) _shader_mat.set_shader_parameter("map_offset", Vector2(FogState.map_bounds.position)) _shader_mat.set_shader_parameter("map_size", Vector2(FogState.map_bounds.size)) _shader_mat.set_shader_parameter("time", Time.get_ticks_msec() / 1000.0)