Files
VoxelGame/src/voxelgame/Voxels/UVWrapVisualizer.cs

112 lines
3.2 KiB
C#
Raw Normal View History

2026-04-04 13:04:05 -04:00
using Godot;
using SJK.Voxels;
using System;
public partial class UVWrapVisualizer : Control
{
public enum WrapperType
{
Normal,
Twisted
}
[Export] public int WorldSize = 8;
[Export] public int ChunkSize = 16;
[Export] public int RenderChunks = 4;
[Export] public WrapperType WrapMode = WrapperType.Twisted;
private ImageTexture texture;
public override void _Ready()
{
GenerateTexture();
}
private IWorldWrapper wrapper = new EndlessSizeXZWorld(10);
private void GenerateTexture()
{
int texSize = WorldSize * ChunkSize * RenderChunks;
var image = Godot.Image.CreateEmpty(texSize, texSize, false, Image.Format.Rgb8);
wrapper = WrapMode switch
{
WrapperType.Normal => new ToroidalWrapping(Vector3I.One * WorldSize),
WrapperType.Twisted => new MirroredZWrappingXOffset(Vector3I.One * WorldSize),
_ => throw new Exception(),
};
GD.Print(wrapper.GetType());
for (int gz = 0; gz < texSize; gz++)
{
for (int gx = 0; gx < texSize; gx++)
{
Vector2I global = new Vector2I(gx - texSize / 2, gz - texSize / 2); // center origin
var v3 = wrapper.Wrap(new Vector3I(global.X, 1, global.Y));
Vector2I local = new(v3.X, v3.Z);
bool flip = false;
// switch (WrapMode)
// {
// case WrapperType.Twisted:
// (local, flip) = TwistedWrapInt(global, WorldSize, WorldSize);
// break;
// default:
// local = new Vector2I(Mod(global.X, WorldSize), Mod(global.Y, WorldSize));
// flip = false;
// break;
// }
// Encode local position into RGB (U and V channels)
float u = local.X / (float)WorldSize;
float v = local.Y / (float)WorldSize;
Color color = new Color(u, v, flip ? 1.0f : 0.0f);
image.SetPixel(gx, gz, color);
}
}
texture = ImageTexture.CreateFromImage(image);
QueueRedraw();
}
public override void _Draw()
{
if (texture != null)
{
DrawTexture(texture, Vector2.Zero);
}
}
// ========== Wrapping Logic ==========
private (Vector2I local, bool flipped) TwistedWrapInt(Vector2I global, int W, int H)
{
int gx = global.X;
int gy = global.Y;
int yWrap = FloorDiv(gy, H);
bool flip = (yWrap & 1) != 0;
int tileY = gy % H;
if (tileY < 0) tileY += H;
int ly = flip ? (H - 1 - tileY) : tileY;
int xOffset = flip ? W / 2 : 0;
int wrappedX = gx + xOffset;
int tileX = wrappedX % W;
if (tileX < 0) tileX += W;
int lx = flip ? (W - 1 - tileX) : tileX;
return (new Vector2I(lx, ly), flip);
}
private int FloorDiv(int a, int b)
{
return (a >= 0) ? a / b : ((a + 1) / b) - 1;
}
private int Mod(int a, int b)
{
int r = a % b;
return r < 0 ? r + b : r;
}
}