using System.Diagnostics; using System.Linq; using Godot; public class WorldChunk : Spatial { private Sprite _heightmapSprite; private TextureRect _heightmapTextureRect; private Sprite _noiseMask; private Sprite _noiseSprite; private readonly SpatialMaterial _rectMaterial = new(); private bool _showTextureOverlay; [Export] public Vector2 ChunkIndex; public Color DebugColor = Colors.White; [Export] public Texture HeightMap; public int HeightMapFrameCount; public Viewport HeightmapOffscreenViewport; [Export] public Texture NavigationMap; public bool NoiseTextureCheckerboardOverlay = true; // signals // delegate void OnCoordClicked(Vector2 world_pos); // other members public Rect2 PlaneRect; // ui elements // scene nodes private MeshInstance PlaneRectMesh; [Export] public int Size = 32; // resources // exports [Export] public Texture TileTypeMap; public int TileTypeMapFrameCount; public Viewport TileTypeOffscreenViewport; public WorldChunk() { } public WorldChunk(int size) { SetSize(size); } [Export] public bool ShowTextureOverlay { get => _showTextureOverlay; set { if (PlaneRectMesh != null) PlaneRectMesh.Visible = value; } } // Called when the node enters the scene tree for the first time. public override void _Ready() { PlaneRectMesh = (MeshInstance)FindNode("PlaneRectMesh"); Debug.Assert(PlaneRectMesh != null); if (PlaneRectMesh.Visible) _showTextureOverlay = true; var planeRectTransform = Transform.Identity; planeRectTransform = planeRectTransform.Scaled(new Vector3(PlaneRect.Size.x, 0.125f, PlaneRect.Size.y)); planeRectTransform.origin.x = PlaneRect.GetCenter().x; planeRectTransform.origin.z = PlaneRect.GetCenter().y; PlaneRectMesh.Transform = planeRectTransform; // PlaneRectMesh.MaterialOverride = new SpatialMaterial(); // ((SpatialMaterial)PlaneRectMesh.MaterialOverride).AlbedoColor = DebugColor; // ((SpatialMaterial)PlaneRectMesh.MaterialOverride).FlagsTransparent = true; HeightmapOffscreenViewport = (Viewport)FindNode("HeightmapOffscreenViewport"); HeightmapOffscreenViewport.Size = Vector2.One * Size; Debug.Assert(HeightmapOffscreenViewport != null); _noiseSprite = (Sprite)FindNode("NoiseSprite"); _noiseMask = (Sprite)FindNode("NoiseMask"); _heightmapSprite = (Sprite)FindNode("HeightmapSprite"); TileTypeOffscreenViewport = (Viewport)FindNode("TileTypeOffscreenViewport"); TileTypeOffscreenViewport.Size = Vector2.One * Size; Debug.Assert(TileTypeOffscreenViewport != null); SetSize(World.ChunkSize); } public void SetSize(int size) { Size = size; if (TileTypeOffscreenViewport != null) { TileTypeOffscreenViewport.Size = Vector2.One * size; HeightmapOffscreenViewport.Size = Vector2.One * size; _noiseMask.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseMask.Texture.GetSize().x); _noiseSprite.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _noiseSprite.Texture.GetSize().x); _heightmapSprite.Transform = Transform2D.Identity.Scaled(Vector2.One * size / _heightmapSprite.Texture.GetSize().x); } } // other members public void SaveToFile(string chunkName) { var image = new Image(); image.CreateFromData(Size, Size, false, Image.Format.Rgba8, TileTypeMap.GetData().GetData()); image.SavePng(chunkName + "_tileType.png"); image.CreateFromData(Size, Size, false, Image.Format.Rgba8, NavigationMap.GetData().GetData()); image.SavePng(chunkName + "_navigationMap.png"); image.CreateFromData(Size, Size, false, Image.Format.Rgba8, HeightMap.GetData().GetData()); image.SavePng(chunkName + "_heightMap.png"); } public void LoadFromFile(string chunkName) { } public void SetNoisemap(Texture texture) { _noiseSprite.Texture = texture; _noiseSprite.Transform = Transform2D.Identity.Scaled(HeightmapOffscreenViewport.Size / _noiseSprite.Texture.GetSize().x); HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once; HeightMapFrameCount = 1; } public void SetHeightmap(Texture texture) { _heightmapSprite.Texture = texture; _heightmapSprite.Transform = Transform2D.Identity.Scaled(TileTypeOffscreenViewport.Size / _heightmapSprite.Texture.GetSize()); TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Once; TileTypeMapFrameCount = 1; } public override void _Process(float delta) { Texture tileTypeTexture = TileTypeOffscreenViewport.GetTexture(); if (NoiseTextureCheckerboardOverlay) { var tileTypeImage = tileTypeTexture.GetData(); tileTypeImage.Lock(); foreach (var i in Enumerable.Range(0, Size)) foreach (var j in Enumerable.Range(0, Size)) { var textureCoord = new Vector2(i, j); var baseColor = tileTypeImage.GetPixelv(textureCoord); if ((i + j) % 2 == 0) tileTypeImage.SetPixelv(textureCoord, baseColor); else tileTypeImage.SetPixelv(textureCoord, baseColor * 0.6f); } tileTypeImage.Unlock(); var imageTexture = new ImageTexture(); imageTexture.CreateFromImage(tileTypeImage, 0); tileTypeTexture = imageTexture; } _rectMaterial.AlbedoTexture = tileTypeTexture; _rectMaterial.FlagsTransparent = true; // _rectMaterial.AlbedoTexture = _heightmapRect.Texture; _rectMaterial.Uv1Scale = new Vector3(-3, -2, 1); _rectMaterial.Uv1Offset = Vector3.One * 2; //RectMaterial.Uv1Triplanar = true; PlaneRectMesh.SetSurfaceMaterial(0, _rectMaterial); if (HeightMapFrameCount == 0) HeightmapOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled; HeightMapFrameCount = HeightMapFrameCount > 0 ? HeightMapFrameCount - 1 : 0; if (TileTypeMapFrameCount == 0) TileTypeOffscreenViewport.RenderTargetUpdateMode = Viewport.UpdateMode.Disabled; TileTypeMapFrameCount = TileTypeMapFrameCount > 0 ? TileTypeMapFrameCount - 1 : 0; PlaneRectMesh.MaterialOverride = null; } }