core/player/PlayerIsoCamera.cs
using Sandbox.Rendering;

public class PlayerIsoCamera : Component {
	[Property, ReadOnly] public BasePlayer Owner {get; set;}

	[Property, ReadOnly] public Vector2Int RenderSize {get; set;} = new(640,480);
	[Property, ReadOnly] public CameraComponent RenderCamera {get; set;}
	[Property, ReadOnly] public CameraComponent DrawCamera {get; set;}
	[Property, ReadOnly] public LightingRigs Lighting {get; set;}
	[Property, ReadOnly] public Vector2 DitherOffset {get; set;}
	[Property, ReadOnly] public Texture Background {get; set;}
	[Property, ReadOnly] public Texture BackgroundDepth {get; set;}
	[Property, ReadOnly] public Texture EntityShadow {get; set;}
	[Property, ReadOnly] public Texture EntityShadowDepth {get; set;}
	[Property, ReadOnly] public Texture EntityLighting {get; set;}
	[Property, ReadOnly] public Texture WorldText {get; set;}
	[Property, ReadOnly] public Texture Mask {get; set;}
	[Property, ReadOnly] public Texture Composite {get; set;}
	[Property, ReadOnly] public Texture Snow {get; set;}
	[Property, ReadOnly] public Texture Waypoint {get; set;}
	[Property, ReadOnly] public Texture WaypointMask {get; set;}
	[Property, ReadOnly] public Texture Final {get; set;}

	protected override void OnAwake() {
		LocalRotation = Rotation.FromYaw(60f) * Rotation.FromPitch(30f);
		LocalPosition = LocalRotation. Backward * 1024f;

		Lighting = Scene.CreateObject().Components.Create<LightingRigs>();

		Spawn.SetOwner(this);
		Spawn.Component(nameof(RenderCamera));
		RenderCamera.Orthographic = true;
		RenderCamera.BackgroundColor = Color.Black;
		RenderCamera.ZFar = 2048;
		Spawn.Component(nameof(DrawCamera));
		DrawCamera.RenderTags.Add("null");
		DrawCamera.BackgroundColor = Color.Black;
		DrawCamera.Priority = 1000;
		base.OnAwake();
	}

	public Vector2 PointToRenderPixels(Vector3 point) {
		var uv = RenderCamera.PointToScreenNormal(point);
		uv -= 0.5f;
		uv /= RenderSize / Screen.Size;
		uv += 0.5f;
		uv *= RenderSize;
		uv.x = uv.x.Floor();
		uv.y = uv.y.Floor();
		return uv;
	}

	public Vector3 MouseTarget() => ScreenPixelsToPoint(Mouse.Position);
	public Vector3 ScreenPixelsToPoint(Vector2 position) {
		var uv = position / Screen.Size;
		uv -= 0.5f;
		uv *= RenderSize / Screen.Size;
		uv.x *= Screen.Aspect;
		uv.x /= (float)RenderSize.x / RenderSize.y;
		uv += 0.5f;
		return new Plane(Vector3.Zero, Vector3.Up).Trace(RenderCamera.ScreenNormalToRay(uv)).Value;
	}

	private TimeUntil NextFullRender = 0;
	public void Update() {
		UpdateZoom();
		ResetTextures();
		Mouse.Visibility = MouseVisibility.Visible;
		if (Owner.Mouse.InteractMode == PlayerMouse.Mode.Move && Owner.Mouse.TargetLayer != PlayerMouse.Layer.Interface)
			Mouse.CursorType = "None";
		else if (Owner.Mouse.InteractMode == PlayerMouse.Mode.Shoot)
			Mouse.CursorType = "iso2_crosshair";
		else
			Mouse.CursorType = "iso2_pointer";
		UpdateMouseDrag();
		if (NextFullRender)
			FullRender();
		InterfaceRender();
	}

	[Property] public float ZoomScale {get; set;} = 0.25f;
	private void UpdateZoom() {
		if (Input.MouseWheel.y == 0)
			return;
		var startscale = ZoomScale;
		if (Input.MouseWheel.y > 0)
			ZoomScale /= 2f;
		else
			ZoomScale *= 2f;
		ZoomScale = ZoomScale.Clamp(0.25f, 0.5f);
		if (startscale != ZoomScale) {
			LastSize = Vector2.Zero;
			NextFullRender = 0f;
		}
	}

	private bool IsDragging = false;
	private Vector3 StartPosition;
	private Vector2 MouseStart;
	private Vector2 DitherStart;
	private void UpdateMouseDrag() {
		if (!IsDragging && Input.Pressed("drag_camera")) {
			IsDragging = true;
			StartPosition = Owner.WorldPosition;
			DitherStart = DitherOffset;
			MouseStart = Mouse.Position;
		}
		if (IsDragging && Input.Released("drag_camera"))
			IsDragging = false;
		if (IsDragging) {
			var mouse = ((Mouse.Position - MouseStart) * (RenderSize / Screen.Size)).SnapToGrid(1);
			var delta = ScreenPixelsToPoint(mouse) - ScreenPixelsToPoint(0);
			delta *= new Vector3(Screen.Size / RenderSize, 0f);
			Owner.WorldPosition = StartPosition - delta;
			DitherOffset = DitherStart - mouse;
			if (!mouse.IsNearZeroLength)
				FullRender();
		}
	}

	private Vector2 LastSize = Vector2.Zero;
	private void ResetTextures() {
		if (LastSize == Screen.Size)
			return;
		LastSize = Screen.Size;
		RenderSize = (Vector2Int)(Screen.Size * ZoomScale);

		Background?.Dispose();
		Background = Texture.CreateRenderTarget().WithSize(RenderSize).Create();
		BackgroundDepth?.Dispose();
		BackgroundDepth = Texture.CreateRenderTarget().WithSize(RenderSize).WithFormat(ImageFormat.RGBA32323232F).Create();
		EntityShadow?.Dispose();
		EntityShadow = Texture.CreateRenderTarget().WithSize(RenderSize).Create();
		EntityShadowDepth?.Dispose();
		EntityShadowDepth = Texture.CreateRenderTarget().WithSize(RenderSize).WithFormat(ImageFormat.RGBA32323232F).Create();
		EntityLighting?.Dispose();
		EntityLighting = Texture.CreateRenderTarget().WithSize(RenderSize).Create();
		Composite?.Dispose();
		Composite = Texture.CreateRenderTarget().WithUAVBinding().WithSize(RenderSize).Create();
		Snow?.Dispose();
		Snow = Texture.CreateRenderTarget().WithUAVBinding().WithSize(RenderSize).Create();
		Waypoint?.Dispose();
		Waypoint = Texture.CreateRenderTarget().WithSize(RenderSize).Create();
		WaypointMask?.Dispose();
		WaypointMask = Texture.CreateRenderTarget().WithSize(RenderSize).Create();
		Final?.Dispose();
		Final = Texture.CreateRenderTarget().WithUAVBinding().WithSize(RenderSize).Create();

		DrawCamera.ClearCommandLists();
		var cmds = new CommandList();
		cmds.Attributes.Set("Frame", Final);
		cmds.Attributes.Set("Interface", Owner.Inventory.Interface);
		cmds.Attributes.SetCombo("D_DRAW_INTERFACE", true);
		cmds.Blit(Material.FromShader(Shader.Load("shaders/post_draw.shader")));
		DrawCamera.AddCommandList(cmds, Stage.AfterPostProcess);
		FullRender();
	}

	private Vector2 LastEntityRenderOffset {get; set;}
	public void FullRender() {
		RenderCamera.OrthographicHeight = 1024 * (Screen.Height / 1024);
		RenderBackground();
		if (NextFullRender) {
			RenderShadows();
			RenderEntities();
			LastEntityRenderOffset = DitherOffset;
		}
		RenderWorldText();
		//RenderMask();
		DoComposite();
		if (NextFullRender)
			NextFullRender = 1f/8f;
	}

	private void RenderBackground() { //areas of static land behind the characters
		RenderCamera.RenderExcludeTags.Add("entity");
		RenderCamera.RenderExcludeTags.Add("flame");
		RenderCamera.RenderExcludeTags.Add("alpha_zero_depth_floor");
		RenderCamera.RenderExcludeTags.Add("iso_waypoint");
		TerrainSuperBlendController.Set(Scene, Scene.RenderAttributes);
		RenderCamera.RenderToTexture(Background);
		Scene.RenderAttributes.Clear();
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", true);
		RenderCamera.RenderExcludeTags.Add("light");
		RenderCamera.RenderExcludeTags.Add("flame");
		//RenderCamera.RenderExcludeTags.Add("no_depth");
		RenderCamera.RenderToTexture(BackgroundDepth);
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", false);
		RenderCamera.RenderExcludeTags.RemoveAll();
	}

	private void RenderShadows() {
		RenderCamera.RenderTags.Add("entity");
		RenderCamera.RenderTags.Add("entity_shadows");
		Lighting.EntityShadows.GameObject.Enabled = true;
		Scene.RenderAttributes.SetCombo("D_SHADOW_PASS", true);
		RenderCamera.RenderToTexture(EntityShadow);
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", true);
		RenderCamera.RenderExcludeTags.Add("light");
		RenderCamera.RenderExcludeTags.Add("iso_waypoint");
		RenderCamera.RenderTags.Add("flame");
		RenderCamera.RenderToTexture(EntityShadowDepth);
		RenderCamera.RenderTags.RemoveAll();
		RenderCamera.RenderExcludeTags.RemoveAll();
		Lighting.EntityShadows.GameObject.Enabled = false;
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", false);
		Scene.RenderAttributes.SetCombo("D_SHADOW_PASS", false);
	}

	private void RenderEntities() { //areas of static land behind the characters
		RenderCamera.RenderTags.Add("entity");
		RenderCamera.RenderTags.Add("flame");
		RenderCamera.RenderTags.Add("light_directional");
		RenderCamera.RenderToTexture(EntityLighting);
		RenderCamera.RenderTags.RemoveAll();
	}

	private void RenderWorldText() {
		WorldText?.Dispose();
		var tex = new Bitmap(RenderSize.x, RenderSize.y);
		foreach (var talker in Scene.GetAllComponents<NpcTalker>()) {
			if (!talker.Message.HasValue)
				continue;
			tex.SetPen(Color.Yellow, 1);
			var center = new Rect(PointToRenderPixels(talker.GetCaptionPosition()), 0);
			center = center.Grow(Graphics.MeasureText(center, talker.Message.Value).Width * 0.5f, 8);
			center.Top = center.Top.Floor();
			center.Left = center.Left.Floor();
			center.Width = MathF.Ceiling(center.Width);
			tex.DrawText(talker.Message.Value, center, TextFlag.Center);
		}
		WorldText = tex.ToTexture();
		tex.Dispose();
	}

	private void RenderMask() {
		Mask?.Dispose();
		var tex = new Bitmap(RenderSize.x, RenderSize.y);
		var any = false;
		foreach (var bounds in Scene.GetAllComponents<IsoCropBounds>()) {
			var bbox = bounds.BBox;
			if (!any)
				tex.Clear(Color.Black);
			any = true;
			tex.SetPen(Color.White,0);
			tex.SetFill(Color.White);
			var top = PointToRenderPixels(bounds.WorldPosition + WorldRotation.Left * bounds.Bounds.x * 0.5f + WorldRotation.Up * bounds.Bounds.y * 0.5f).Clamp(0f, RenderSize);
			var bot = PointToRenderPixels(bounds.WorldPosition + WorldRotation.Left *-bounds.Bounds.x * 0.5f + WorldRotation.Up *-bounds.Bounds.y * 0.5f).Clamp(0f, RenderSize) - top;
			if (bot.IsNearZeroLength)
				continue;
			tex.DrawRect(new(top,bot));
		}
		if (!any)
			tex.Clear(Color.White);
		Mask = tex.ToTexture();
		tex.Dispose();
	}

	private void DoComposite() { //combine world renders, not including ui
		var shader = new ComputeShader("shaders/cs_iso_composite_a.shader");
		shader.Attributes.Set("Background", Background);
		shader.Attributes.Set("BackgroundDepth", BackgroundDepth);
		shader.Attributes.Set("EntityShadow", EntityShadow);
		shader.Attributes.Set("EntityShadowDepth", EntityShadowDepth);
		shader.Attributes.Set("EntityLighting", EntityLighting);
		shader.Attributes.Set("WorldText", WorldText);
		shader.Attributes.Set("Mask", Mask);
		shader.Attributes.Set("Snow", Snow);
		shader.Attributes.Set("EntityOffset", DitherOffset - LastEntityRenderOffset);
		shader.Attributes.Set("DitherOffset", DitherOffset);
		shader.Attributes.Set("RenderSize", Composite.Size);
		shader.Attributes.Set("Result", Composite);
		shader.Dispatch(Composite.Width, Composite.Height, 1);
	}

	public void InterfaceRender() {
		RenderSnow();
		RenderWaypoint();
		DoFinalComposite();
	}

	private TimeUntil SnowUpdateTime {get; set;}
	private Vector2 LastDitherOffset {get; set;}
	private GpuBuffer<Vector4> SnowPositionBuffer {get; set;}
	private void RenderSnow() {
		if (SnowPositionBuffer == null)
			SnowPositionBuffer = new(2048);
		if (SnowUpdateTime || DitherOffset != LastDitherOffset) {
			var update = new ComputeShader("shaders/cs_snow_update.shader");
			update.Attributes.Set("PositionBuffer", SnowPositionBuffer);
			update.Attributes.Set("DeltaTime", SnowUpdateTime.Passed);
			update.Attributes.Set("TimeNow", Time.Now);
			update.Attributes.Set("DitherOffset", DitherOffset);
			update.Attributes.Set("MoveDelta", (DitherOffset - LastDitherOffset) / Snow.Size);
			update.Attributes.Set("Update", (bool)SnowUpdateTime);
			update.Dispatch(SnowPositionBuffer.ElementCount, 1, 1);
			LastDitherOffset = DitherOffset;
			if (SnowUpdateTime)
				SnowUpdateTime = 1f/20f;
		}
		var shader = new ComputeShader("shaders/cs_snow_draw.shader");
		shader.Attributes.Set("PositionBuffer", SnowPositionBuffer);
		shader.Attributes.Set("BufferSize", SnowPositionBuffer.ElementCount);
		shader.Attributes.Set("RenderSize", Snow.Size);
		shader.Attributes.Set("ZoomScale", ZoomScale);
		shader.Attributes.Set("Result", Snow);
		shader.Dispatch(Snow.Width, Snow.Height, 1);
	}

	private void RenderWaypoint() {
		RenderCamera.BackgroundColor = Color.Transparent;
		RenderCamera.RenderTags.Add("light_directional");
		if (Owner.Mouse.InteractMode == PlayerMouse.Mode.Move && Owner.Mouse.TargetLayer != PlayerMouse.Layer.Interface && !Input.Down("drag_camera"))
			RenderCamera.RenderTags.Add("iso_waypoint");
		RenderCamera.RenderToTexture(Waypoint);
		RenderCamera.RenderTags.RemoveAll();
		RenderCamera.RenderExcludeTags.Add("no_depth");
		RenderCamera.RenderExcludeTags.Add("iso_waypoint");
		RenderCamera.RenderExcludeTags.Add("ground");
		RenderCamera.RenderExcludeTags.Add("dynamic");
		RenderCamera.RenderExcludeTags.Add("flame");
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", true);
		RenderCamera.RenderToTexture(WaypointMask);
		Scene.RenderAttributes.SetCombo("D_MANUAL_DEPTH", false);
		RenderCamera.RenderExcludeTags.RemoveAll();
		RenderCamera.BackgroundColor = Color.Black;
	}

	[Property, Range(-1,1)] public float Fade {get; set;}
	private void DoFinalComposite() { //combine world renders, not including ui
		var shader = new ComputeShader("shaders/cs_iso_composite_b.shader");
		shader.Attributes.Set("Composite", Composite);
		shader.Attributes.Set("Snow", Snow);
		shader.Attributes.Set("Waypoint", Waypoint);
		shader.Attributes.Set("WaypointMask", WaypointMask);
		shader.Attributes.Set("EntityShadow", EntityShadow);
		shader.Attributes.Set("EntityOffset", DitherOffset - LastEntityRenderOffset);
		shader.Attributes.Set("BackgroundDepth", BackgroundDepth);
		shader.Attributes.Set("Freeze", Owner.Inventory.Temperature.Remap(-20,0,1,0).SnapToGrid(0.05f));
		shader.Attributes.Set("FreezeOverlay", Texture.Load("materials/interface/freeze.vtex"));
		shader.Attributes.Set("Fade", Fade);
		shader.Attributes.Set("RenderSize", Final.Size);
		shader.Attributes.Set("Result", Final);
		shader.Dispatch(Final.Width, Final.Height, 1);
	}
}

public class IsoCropBounds : Component {
	[Property] public Vector2 Bounds {get; set;}
	public BBox BBox => new(new Vector3(100, Bounds.x, Bounds.y) *-0.5f, new Vector3(100, Bounds.x, Bounds.y) * 0.5f);
	protected override void DrawGizmos() {
		Gizmo.Transform = Gizmo.Transform.WithRotation(Rotation.FromYaw(60f) * Rotation.FromPitch(30f));
		Vector3 vec = 0.5f;
		vec.x = 1000;
		vec.y *= Bounds.x;
		vec.z *= Bounds.y;
		Gizmo.Draw.Color = Color.Black;
		Gizmo.Draw.LineThickness = 5;
		Gizmo.Draw.LineBBox(new(-vec, vec));
		base.DrawGizmos();
	}
}