ZeroVR/ZeroPacientVR/Assets/CodeRespawn/DungeonArchitect/Scripts/Builders/GridFlow/Minimap/GridFlowMinimap.cs

363 lines
13 KiB
C#

//$ Copyright 2015-22, Code Respawn Technologies Pvt Ltd - All Rights Reserved $//
using DungeonArchitect.MiniMaps;
using DungeonArchitect.Utils;
using System.Linq;
using System.Collections.Generic;
using DungeonArchitect.Flow.Domains.Tilemap;
using UnityEngine;
namespace DungeonArchitect.Builders.GridFlow
{
[System.Serializable]
public enum GridFlowMinimapInitMode
{
OnDungeonRebuild,
OnPlay,
Manual
}
[System.Serializable]
public struct GridFlowMinimapIcons
{
public Texture2D iconOneWayDoor;
}
public class GridFlowMinimap : DungeonMiniMap
{
public Shader tileShader;
public GridFlowMinimapInitMode initMode = GridFlowMinimapInitMode.Manual;
public GridFlowMinimapIcons icons;
public bool seeThroughWalls = false;
FlowTilemapRenderResources resources;
GridFlowDungeonModel model;
GridFlowDungeonConfig config;
int tileSize = 1;
List<GridFlowMinimapTrackedObject> trackedObjects = new List<GridFlowMinimapTrackedObject>();
Color[] fogMask;
protected override bool SupportsFogOfWar { get { return true; } }
private void Reset()
{
compositeShader = Shader.Find("DungeonArchitect/MiniMap/Composite");
tileShader = Shader.Find("DungeonArchitect/MiniMap/Tile");
initMode = GridFlowMinimapInitMode.OnDungeonRebuild;
}
private void Awake()
{
}
private void Start()
{
if (initMode == GridFlowMinimapInitMode.OnPlay)
{
Initialize();
}
}
public void AddTrackedObject(GridFlowMinimapTrackedObject trackedObject)
{
trackedObjects.Add(trackedObject);
}
protected override void CreateTextures(IntVector2 desiredSize, out Texture staticImage, out Texture fogOfWar, out Texture overlayImage, out IntVector2 targetTextureSize)
{
resources = new FlowTilemapRenderResources();
resources.materials = new TexturedMaterialInstances(tileShader);
resources.iconOneWayDoor = icons.iconOneWayDoor;
if (model == null)
{
model = GetComponent<GridFlowDungeonModel>();
}
if (config == null)
{
config = GetComponent<GridFlowDungeonConfig>();
}
if (model == null || config == null)
{
Debug.LogError("Cannot find GridFlowDungeonModel component along side the minimap script");
staticImage = null;
fogOfWar = null;
overlayImage = null;
targetTextureSize = IntVector2.Zero;
return;
}
var tilemap = model.Tilemap;
if (tilemap == null)
{
staticImage = null;
fogOfWar = null;
overlayImage = null;
targetTextureSize = IntVector2.Zero;
return;
}
// Calculate the tile size
{
var desiredTileSize2D = new Vector2();
desiredTileSize2D.x = (float)desiredSize.x / model.Tilemap.Width;
desiredTileSize2D.y = (float)desiredSize.y / model.Tilemap.Height;
var desiredTileSizeF = Mathf.Min(desiredTileSize2D.x, desiredTileSize2D.y);
tileSize = Mathf.FloorToInt(desiredTileSizeF);
}
var texWidth = tilemap.Width * tileSize;
var texHeight = tilemap.Height * tileSize;
targetTextureSize = new IntVector2(texWidth, texHeight);
staticImage = new RenderTexture(texWidth, texHeight, 0);
overlayImage = new RenderTexture(texWidth, texHeight, 0);
fogOfWar = new Texture2D(tilemap.Width, tilemap.Height, TextureFormat.R8, false, true);
fogMask = new Color[tilemap.Width * tilemap.Height];
}
protected override void UpdateStaticTexture(Texture texture)
{
var rtt = texture as RenderTexture;
if (rtt == null || model == null) return;
var tilemap = model.Tilemap;
if (tilemap != null)
{
FlowTilemapRenderer.Render(rtt, tilemap, tileSize, resources, cell => false);
}
}
struct FogOfWarItem
{
public Vector2 position;
public float radius;
public float falloffStart;
}
IntVector2[] FogOfWarFilterVisibility(IntVector2[] tiles, IntVector2 player)
{
if (seeThroughWalls)
{
return tiles;
}
var tilemap = model.Tilemap;
if (tilemap == null)
{
return tiles;
}
var result = new List<IntVector2>();
var valid = new HashSet<IntVector2>(tiles);
var visited = new HashSet<IntVector2>();
var queue = new Queue<IntVector2>();
queue.Enqueue(player);
visited.Add(player);
while (queue.Count > 0)
{
var coord = queue.Dequeue();
result.Add(coord);
var cell = tilemap.Cells.GetCell(coord.x, coord.y);
if (cell == null) continue;
if (cell.CellType == FlowTilemapCellType.Wall) continue;
if (cell.CellType == FlowTilemapCellType.Door) continue;
for (int dy = -1; dy <= 1; dy++)
{
for (int dx = -1; dx <= 1; dx++)
{
if (dx == 0 && dy == 0)
{
continue;
}
var cx = coord.x + dx;
var cy = coord.y + dy;
if (cx < 0 || cy < 0 || cx >= tilemap.Width || cy >= tilemap.Height) continue;
var childCoord = new IntVector2(cx, cy);
if (visited.Contains(childCoord) || !valid.Contains(childCoord))
{
continue;
}
visited.Add(childCoord);
queue.Enqueue(childCoord);
}
}
}
return result.ToArray();
}
protected override void UpdateFogOfWarTexture(Texture texture)
{
var fogTex = texture as Texture2D;
var tilemap = model.Tilemap;
if (fogTex == null || model == null || fogMask == null || tilemap == null) return;
var items = new List<FogOfWarItem>();
foreach (var trackedObject in trackedObjects)
{
if (trackedObject == null) continue;
if (trackedObject.exploresFogOfWar)
{
var item = new FogOfWarItem();
var localPosition = transform.InverseTransformPoint(trackedObject.transform.position);
var gridCoord = new Vector2(
localPosition.x / config.gridSize.x,
localPosition.z / config.gridSize.z);
item.position = gridCoord;
item.radius = trackedObject.fogOfWarNumTileRadius;
item.falloffStart = trackedObject.fogOfWarLightFalloffStart;
items.Add(item);
}
}
foreach (var item in items)
{
int cx = Mathf.FloorToInt(item.position.x);
int cy = Mathf.FloorToInt(item.position.y);
int x0 = Mathf.FloorToInt(item.position.x - item.radius);
int x1 = Mathf.FloorToInt(item.position.x + item.radius);
int y0 = Mathf.FloorToInt(item.position.y - item.radius);
int y1 = Mathf.FloorToInt(item.position.y + item.radius);
cx = Mathf.Clamp(cx, 0, tilemap.Width - 1);
cy = Mathf.Clamp(cy, 0, tilemap.Height - 1);
x0 = Mathf.Clamp(x0, 0, tilemap.Width - 1);
x1 = Mathf.Clamp(x1, 0, tilemap.Width - 1);
y0 = Mathf.Clamp(y0, 0, tilemap.Height - 1);
y1 = Mathf.Clamp(y1, 0, tilemap.Height - 1);
var falloff = Mathf.Clamp01(1 - item.falloffStart);
var tilesToProcess = new List<IntVector2>();
for (int y = y0; y <= y1; y++)
{
for (int x = x0; x <= x1; x++)
{
tilesToProcess.Add(new IntVector2(x, y));
}
}
var visibleTiles = FogOfWarFilterVisibility(tilesToProcess.ToArray(), new IntVector2(cx, cy));
foreach (var tile in visibleTiles)
{
float distance = (new Vector2(tile.x, tile.y) - item.position).magnitude;
distance = Mathf.Clamp01(distance / item.radius);
var weight = 1 - distance;
weight = weight / falloff;
weight = Mathf.Clamp01(weight);
int index = tile.y * tilemap.Width + tile.x;
fogMask[index].r = Mathf.Max(weight, fogMask[index].r);
}
}
fogTex.SetPixels(fogMask);
fogTex.Apply(false);
}
protected override void UpdateOverlayTexture(Texture texture)
{
var rtt = texture as RenderTexture;
if (rtt == null || model == null || model.Tilemap == null) return;
trackedObjects = (from trackedObject in trackedObjects
where trackedObject != null
select trackedObject).ToList();
var oldRTT = RenderTexture.active;
RenderTexture.active = rtt;
GL.PushMatrix();
GL.LoadOrtho();
GL.Clear(true, true, new Color(0, 0, 0, 0), 0);
var tilemap = model.Tilemap;
var tileSizeUV = tileSize / (float)texture.width;
foreach (var trackedObject in trackedObjects)
{
if (trackedObject == null || trackedObject.icon == null) continue;
var color = trackedObject.tint;
var positionUV = WorldToUVCoord(trackedObject.transform.position, tilemap.Width, tilemap.Height, texture.width, texture.height);
var iconSize = tileSizeUV * trackedObject.iconScale;
var hs = iconSize * 0.5f;
float cx = positionUV.x;
float cy = positionUV.y;
var x0 = -hs;
var x1 = +hs;
var y0 = -hs;
var y1 = +hs;
Quaternion rotation;
if (trackedObject.rotateIcon)
{
var forward = trackedObject.transform.forward;
forward.y = 0;
forward = forward.normalized;
rotation = Quaternion.LookRotation(forward);
}
else
{
rotation = Quaternion.identity;
}
var material = resources.materials.GetMaterial(trackedObject.icon);
material.SetPass(0);
GL.Begin(GL.QUADS);
EmitVertex(cx, cy, x0, y0, 0, 0, color, rotation);
EmitVertex(cx, cy, x0, y1, 0, 1, color, rotation);
EmitVertex(cx, cy, x1, y1, 1, 1, color, rotation);
EmitVertex(cx, cy, x1, y0, 1, 0, color, rotation);
GL.End();
}
GL.PopMatrix();
RenderTexture.active = oldRTT;
}
Vector2 WorldToUVCoord(Vector3 position, int tilemapWidth, int tilemapHeight, int textureWidth, int textureHeight)
{
var minimapWorldPosition = transform.InverseTransformPoint(position);
var minimapGridCoord = new Vector2(
minimapWorldPosition.x / config.gridSize.x,
minimapWorldPosition.z / config.gridSize.z);
var minimapPixelCoord = minimapGridCoord * tileSize;
var minimapUVCoord = new Vector2(
minimapPixelCoord.x / textureWidth,
minimapPixelCoord.y / textureHeight);
return minimapUVCoord;
}
void EmitVertex(float cx, float cy, float x, float y, float u, float v, Color color, Quaternion rotation)
{
var vertex = new Vector3(x, 0, y);
vertex = rotation * vertex;
x = vertex.x;
y = vertex.z;
GL.Color(color);
GL.TexCoord2(u, v);
GL.Vertex3(cx + x, cy + y, 0);
}
}
}