using Godot; using System; public enum DebugType { None, Slope, Height, Temperature, Moisture } [Tool] public partial class World : Node2D { [Export] public Texture2D HeightMapTexture; [Export] public int MapWidth { get => _mapWidth; set { _mapWidth = value; SetupShader(); } } private int _mapWidth = 3072; [Export] public float RockThreshold { get => _rockThreshold; set { _rockThreshold = value; UpdateShaderParameters(); } } private float _rockThreshold = 0.05f; [Export] public float SnowHeightThreshold { get => _snowHeightThreshold; set { _snowHeightThreshold = value; UpdateShaderParameters(); } } private float _snowHeightThreshold = 0.8f; [Export] public float WaterThreshold { get => _waterThreshold; set { _waterThreshold = value; UpdateShaderParameters(); } } private float _waterThreshold = 0.0f; [Export] public float DesertTemperatureThreshold { get => _desertTemperatureThreshold; set { _desertTemperatureThreshold = value; UpdateShaderParameters(); } } private float _desertTemperatureThreshold = 0.7f; [Export] public float DesertMoistureThreshold { get => _desertMoistureThreshold; set { _desertMoistureThreshold = value; UpdateShaderParameters(); } } private float _desertMoistureThreshold = 0.3f; [Export] public float TemperatureNoiseFrequency { get => _temperatureNoiseFrequency; set { _temperatureNoiseFrequency = value; UpdateShaderParameters(); } } private float _temperatureNoiseFrequency = 0.01f; [Export] public float MoistureNoiseFrequency { get => _moistureNoiseFrequency; set { _moistureNoiseFrequency = value; UpdateShaderParameters(); } } private float _moistureNoiseFrequency = 0.01f; [Export] public float TemperatureNoiseAmplitude { get => _temperatureNoiseAmplitude; set { _temperatureNoiseAmplitude = value; UpdateShaderParameters(); } } private float _temperatureNoiseAmplitude = 0.1f; [Export] public float MoistureNoiseAmplitude { get => _moistureNoiseAmplitude; set { _moistureNoiseAmplitude = value; UpdateShaderParameters(); } } private float _moistureNoiseAmplitude = 0.1f; [Export] public DebugType DebugType { get => _debugType; set { _debugType = value; UpdateShaderParameters(); } } private DebugType _debugType = DebugType.None; private Sprite2D _terrainSprite; private ShaderMaterial _shaderMaterial; public override void _Ready() { // If the height map image is not assigned, log an error and return if (HeightMapTexture == null) { GD.PrintErr("Height map texture is not assigned."); return; } SetupShader(); } private void SetupShader() { // Don't run during initialization if not ready if (HeightMapTexture == null) return; // Clear any existing terrain sprite if (_terrainSprite != null) { _terrainSprite.QueueFree(); _terrainSprite = null; } // Load the shader Shader terrainShader = GD.Load("res://Shaders/terrain.gdshader"); if (terrainShader == null) { GD.PrintErr("Failed to load terrain shader."); return; } // Create shader material _shaderMaterial = new ShaderMaterial(); _shaderMaterial.Shader = terrainShader; // Get heightmap dimensions Image heightImage = HeightMapTexture.GetImage(); if (heightImage == null) { GD.PrintErr("Failed to get image from HeightMapTexture."); return; } Vector2I heightMapSize = new Vector2I(heightImage.GetWidth(), heightImage.GetHeight()); // Calculate output resolution // Height is always calculated based on heightmap aspect ratio int outputWidth = MapWidth; float aspectRatio = (float)heightMapSize.Y / heightMapSize.X; int outputHeight = (int)(outputWidth * aspectRatio); // Create a sprite to display the shader _terrainSprite = new Sprite2D(); _terrainSprite.Material = _shaderMaterial; _terrainSprite.TextureFilter = TextureFilterEnum.Nearest; // Create a white texture with the desired output size // The shader will render over this Image whiteImage = Image.CreateEmpty(outputWidth, outputHeight, false, Image.Format.Rgba8); whiteImage.Fill(Colors.White); _terrainSprite.Texture = ImageTexture.CreateFromImage(whiteImage); // Center the sprite _terrainSprite.Centered = false; AddChild(_terrainSprite); // Update all shader parameters UpdateShaderParameters(); } private void UpdateShaderParameters() { if (_shaderMaterial == null) { GD.PrintErr("ShaderMaterial is null, cannot update parameters"); return; } if (HeightMapTexture == null) { GD.PrintErr("HeightMapTexture is null, cannot update parameters"); return; } GD.Print($"Setting height_map texture: {HeightMapTexture.ResourcePath}"); // Set the heightmap texture _shaderMaterial.SetShaderParameter("height_map", HeightMapTexture); // Set all threshold parameters _shaderMaterial.SetShaderParameter("water_threshold", WaterThreshold); _shaderMaterial.SetShaderParameter("rock_threshold", RockThreshold); _shaderMaterial.SetShaderParameter("snow_height_threshold", SnowHeightThreshold); _shaderMaterial.SetShaderParameter("desert_temperature_threshold", DesertTemperatureThreshold); _shaderMaterial.SetShaderParameter("desert_moisture_threshold", DesertMoistureThreshold); // Set noise parameters _shaderMaterial.SetShaderParameter("temperature_noise_frequency", TemperatureNoiseFrequency); _shaderMaterial.SetShaderParameter("temperature_noise_amplitude", TemperatureNoiseAmplitude); _shaderMaterial.SetShaderParameter("moisture_noise_frequency", MoistureNoiseFrequency); _shaderMaterial.SetShaderParameter("moisture_noise_amplitude", MoistureNoiseAmplitude); // Set debug mode _shaderMaterial.SetShaderParameter("debug_type", (int)DebugType); GD.Print("Shader parameters updated successfully"); } }