Map presenter: one owner places every map icon in 2D, belts become one instanced draw (not yet compiled)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
da6fe0334e
commit
281745394b
16 changed files with 360 additions and 408 deletions
31
Assets/Materials/UI/MapAsteroid.mat
Normal file
31
Assets/Materials/UI/MapAsteroid.mat
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!21 &2100000
|
||||
Material:
|
||||
serializedVersion: 8
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: MapAsteroid
|
||||
m_Shader: {fileID: 4800000, guid: 22e2fc798f044a3aa2f6cd71f1df09a7, type: 3}
|
||||
m_ValidKeywords: []
|
||||
m_InvalidKeywords: []
|
||||
m_LightmapFlags: 0
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: 3000
|
||||
stringTagMap: {}
|
||||
disabledShaderPasses: []
|
||||
m_SavedProperties:
|
||||
serializedVersion: 3
|
||||
m_TexEnvs:
|
||||
- _MainTex:
|
||||
m_Texture: {fileID: 2800000, guid: 060aefd5a3d5ced4dabd9190a140e76e, type: 3}
|
||||
m_Scale: {x: 1, y: 1}
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Ints: []
|
||||
m_Floats: []
|
||||
m_Colors:
|
||||
- _Color: {r: 1, g: 1, b: 1, a: 1}
|
||||
m_BuildTextureStacks: []
|
||||
|
|
@ -1,7 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1f1bfa2175a13b647888e2949e0cb138
|
||||
PrefabImporter:
|
||||
guid: c1012d5466454651b7279be93ef9af88
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &992254348637625916
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1779911639310264026}
|
||||
- component: {fileID: 349597964696402918}
|
||||
- component: {fileID: 2844878085845264008}
|
||||
- component: {fileID: 917803079556930035}
|
||||
- component: {fileID: 4397878771830533054}
|
||||
m_Layer: 14
|
||||
m_Name: Asteroid Belt
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1779911639310264026
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 992254348637625916}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!33 &349597964696402918
|
||||
MeshFilter:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 992254348637625916}
|
||||
m_Mesh: {fileID: 0}
|
||||
--- !u!23 &2844878085845264008
|
||||
MeshRenderer:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 992254348637625916}
|
||||
m_Enabled: 1
|
||||
m_CastShadows: 1
|
||||
m_ReceiveShadows: 1
|
||||
m_DynamicOccludee: 1
|
||||
m_MotionVectors: 1
|
||||
m_LightProbeUsage: 1
|
||||
m_ReflectionProbeUsage: 1
|
||||
m_RayTracingMode: 2
|
||||
m_RayTraceProcedural: 0
|
||||
m_RenderingLayerMask: 1
|
||||
m_RendererPriority: 0
|
||||
m_Materials:
|
||||
- {fileID: 2100000, guid: c018d99199afeca448c64b9022ac7270, type: 2}
|
||||
m_StaticBatchInfo:
|
||||
firstSubMesh: 0
|
||||
subMeshCount: 0
|
||||
m_StaticBatchRoot: {fileID: 0}
|
||||
m_ProbeAnchor: {fileID: 0}
|
||||
m_LightProbeVolumeOverride: {fileID: 0}
|
||||
m_ScaleInLightmap: 1
|
||||
m_ReceiveGI: 1
|
||||
m_PreserveUVs: 0
|
||||
m_IgnoreNormalsForChartDetection: 0
|
||||
m_ImportantGI: 0
|
||||
m_StitchLightmapSeams: 0
|
||||
m_SelectedEditorRenderState: 3
|
||||
m_MinimumChartSize: 4
|
||||
m_AutoUVMaxDistance: 0.5
|
||||
m_AutoUVMaxAngle: 89
|
||||
m_LightmapParameters: {fileID: 0}
|
||||
m_SortingLayerID: 0
|
||||
m_SortingLayer: 0
|
||||
m_SortingOrder: 0
|
||||
m_AdditionalVertexStreams: {fileID: 0}
|
||||
--- !u!64 &917803079556930035
|
||||
MeshCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 992254348637625916}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 4
|
||||
m_Convex: 0
|
||||
m_CookingOptions: 30
|
||||
m_Mesh: {fileID: 0}
|
||||
--- !u!114 &4397878771830533054
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 992254348637625916}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 52538a3309c36fc4583c964a1c0b705f, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
|
|
@ -16421,8 +16421,7 @@ MonoBehaviour:
|
|||
TourFollowDistance: 100
|
||||
TourHeightOffset: 50
|
||||
TourFollowOffsetDegrees: 55
|
||||
AsteroidBeltUI: {fileID: 349597964696402918, guid: 1f1bfa2175a13b647888e2949e0cb138,
|
||||
type: 3}
|
||||
MapAsteroidMaterial: {fileID: 2100000, guid: c1012d5466454651b7279be93ef9af88, type: 2}
|
||||
Planet: {fileID: 8287217960984982033, guid: 88ace6073e3db1a46bd3aaf4f971acb9, type: 3}
|
||||
GasGiant: {fileID: 3250623180916197132, guid: 85753b4a7c762274385af384abed7a04,
|
||||
type: 3}
|
||||
|
|
|
|||
|
|
@ -298,10 +298,6 @@ public class ActionGameManager : MonoBehaviour
|
|||
Settings.GameplaySettings, Debug.Log);
|
||||
ZoneRenderer.ItemManager = ItemManager;
|
||||
|
||||
// If hiding minimap asteroids, turn them off to start with
|
||||
if (!PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
|
||||
ZoneRenderer.ShowAsteroidUI = false;
|
||||
|
||||
// TODO: Process Stories
|
||||
|
||||
#region Input Handling
|
||||
|
|
|
|||
|
|
@ -80,6 +80,8 @@ public class EntityInstance : MonoBehaviour
|
|||
var materials = new List<(Material material, List<(MeshRenderer renderer, int index)> submeshes)>();
|
||||
foreach (var mesh in meshes)
|
||||
{
|
||||
// The map icon is drawn by MapPresenter, not as part of the hull (SetEntity hands it over).
|
||||
if (mesh == MapIcon) continue;
|
||||
_meshes.Add(mesh, mesh.sharedMaterials);
|
||||
for (var i = 0; i < mesh.sharedMaterials.Length; i++)
|
||||
{
|
||||
|
|
@ -165,6 +167,9 @@ public class EntityInstance : MonoBehaviour
|
|||
ZoneRenderer = zoneRenderer;
|
||||
var hullData = entity.ItemManager.GetData(entity.Hull) as HullData;
|
||||
|
||||
zoneRenderer.Map.RegisterEntity(entity, MapIcon, transform);
|
||||
MapIcon = null;
|
||||
|
||||
if(Shield)
|
||||
Shield.Entity = entity;
|
||||
|
||||
|
|
@ -187,7 +192,8 @@ public class EntityInstance : MonoBehaviour
|
|||
{
|
||||
var pingInstance = Instantiate(PingPrefab);
|
||||
var pingMesh = pingInstance.GetComponent<MeshRenderer>();
|
||||
pingInstance.position = DrawAhead.Position(entity, ActionGameManager.Clock.Lead).ToUnity();
|
||||
var drawn = DrawAhead.Position(entity, ActionGameManager.Clock.Lead);
|
||||
pingInstance.position = new Vector3(drawn.x, MapPresenter.PlaneY, drawn.z);
|
||||
_pingBrightness = pingMesh.material.GetFloat("_Depth");
|
||||
_currentPing = (pingInstance, pingMesh);
|
||||
};
|
||||
|
|
@ -366,7 +372,10 @@ public class EntityInstance : MonoBehaviour
|
|||
OnFadedIn = null;
|
||||
ShowUnfadedElements();
|
||||
}
|
||||
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
||||
{
|
||||
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
||||
ZoneRenderer.Map.SetFade(Entity, _fade);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -381,7 +390,10 @@ public class EntityInstance : MonoBehaviour
|
|||
OnFadedOut?.Invoke();
|
||||
OnFadedOut = null;
|
||||
}
|
||||
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
||||
{
|
||||
foreach(var material in _fadeMaterials) material.SetFloat("_Fade", _fade);
|
||||
ZoneRenderer.Map.SetFade(Entity, _fade);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -63,7 +63,7 @@ public class PlayerGameplaySettings
|
|||
public class PlayerGraphicsSettings
|
||||
{
|
||||
[Key(0)] public Quality NebulaQuality = Quality.Normal;
|
||||
[Key(1)] public bool ShowAsteroidsInMinimap;
|
||||
// Key 1 is retired; an older player.cc that still carries it loads, and it is dropped.
|
||||
// How hard the camera shakes when the player's ship takes an impact: 0 off, 1 full (Feedback.Cue).
|
||||
[Key(2)] public float ScreenShake = 1f;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -296,9 +296,6 @@ public class MainMenu : MonoBehaviour
|
|||
CloudRenderer.quality = ActionGameManager.PlayerSettings.GraphicsSettings.NebulaQuality;
|
||||
},
|
||||
Enum.GetNames(typeof(Quality)));
|
||||
_nextMenu.panel.AddField("Show Asteroids in Minimap",
|
||||
() => ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap,
|
||||
b => ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap = b);
|
||||
_nextMenu.panel.AddField("Screen Shake",
|
||||
() => ActionGameManager.PlayerSettings.GraphicsSettings.ScreenShake,
|
||||
f => ActionGameManager.PlayerSettings.GraphicsSettings.ScreenShake = f,
|
||||
|
|
|
|||
|
|
@ -51,10 +51,7 @@ public class MapRenderer : MonoBehaviour
|
|||
TintCamera.gameObject.SetActive(true);
|
||||
InfluenceCamera.gameObject.SetActive(true);
|
||||
Title.text = $"Zone: {GameManager.Zone.GalaxyZone.Name}";
|
||||
|
||||
// If hiding minimap asteroids, turn them back on for the map screen
|
||||
if (!ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
|
||||
ZoneRenderer.ShowAsteroidUI = true;
|
||||
GameManager.ZoneRenderer.Map.OpenMapScreen(true);
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
|
|
@ -67,10 +64,7 @@ public class MapRenderer : MonoBehaviour
|
|||
GravityCamera.gameObject.SetActive(false);
|
||||
TintCamera.gameObject.SetActive(false);
|
||||
InfluenceCamera.gameObject.SetActive(false);
|
||||
|
||||
// If hiding minimap asteroids, turn them back off when leaving the map screen
|
||||
if (!ActionGameManager.PlayerSettings.GraphicsSettings.ShowAsteroidsInMinimap)
|
||||
ZoneRenderer.ShowAsteroidUI = false;
|
||||
GameManager.ZoneRenderer.Map.OpenMapScreen(false);
|
||||
}
|
||||
|
||||
void ReleaseTextures()
|
||||
|
|
@ -129,6 +123,6 @@ public class MapRenderer : MonoBehaviour
|
|||
InfluenceCamera.transform.position = pos;
|
||||
InfluenceCamera.orthographicSize = _size.y * Scale * .5f;
|
||||
|
||||
GameManager.ZoneRenderer.SetIconSize(IconSize * Scale);
|
||||
GameManager.ZoneRenderer.Map.SetMapScreenScale(IconSize * Scale);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
215
Assets/Scripts/Zone Display/MapPresenter.cs
Normal file
215
Assets/Scripts/Zone Display/MapPresenter.cs
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
using System.Collections.Generic;
|
||||
using CultMath;
|
||||
using CultMath.UnityBridge;
|
||||
using GameCult.Caching;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
using static CultMath.math;
|
||||
using float2 = CultMath.float2;
|
||||
using float3 = CultMath.float3;
|
||||
using float4 = CultMath.float4;
|
||||
using quaternion = CultMath.quaternion;
|
||||
|
||||
// The one owner of map-space projection (ruling map-icons-placed-in-2d): where every map icon and belt asteroid is
|
||||
// drawn, its yaw, its size, its fade, and the contour's depth range. Icons are not world objects: each is a mesh,
|
||||
// a material instance and an authored rotation read once from the icon child at registration (the child is then
|
||||
// destroyed), drawn every frame on the Minimap layer at the map plane from sim state through DrawAhead. Roll and
|
||||
// pitch never reach an icon, and field depth never decides whether one is seen. Both map cameras (the minimap's
|
||||
// and the map screen's) see these same draws; only the size input differs.
|
||||
public class MapPresenter
|
||||
{
|
||||
// The map plane. Every map camera is orthographic and looks down from above it, so this height is inside every
|
||||
// clip range; the offsets only order overlapping icons (planets under stations under ships, belts under all).
|
||||
public const float PlaneY = 0f;
|
||||
public const float BeltOffset = -.1f, PlanetOffset = 0f, OrbitalOffset = .1f, ShipOffset = .2f;
|
||||
|
||||
// The one place the heading of an icon is decided (question contact-icon-heading, yaw-for-all): every icon turns
|
||||
// with its entity's yaw. Another answer changes only this function.
|
||||
public static float IconYaw(Entity entity, quaternion drawnRotation)
|
||||
{
|
||||
var forward = drawnRotation.ToUnity() * Vector3.forward;
|
||||
return Mathf.Atan2(forward.x, forward.z) * Mathf.Rad2Deg;
|
||||
}
|
||||
|
||||
private sealed class Icon
|
||||
{
|
||||
public Mesh Mesh;
|
||||
public Material Material;
|
||||
public Color Base;
|
||||
public Quaternion Authored;
|
||||
public float Offset;
|
||||
public Entity Entity;
|
||||
public CultRecordKey Planet;
|
||||
public float Fade;
|
||||
public Matrix4x4 Drawn;
|
||||
}
|
||||
|
||||
private readonly List<Icon> _icons = new List<Icon>();
|
||||
private readonly Dictionary<Entity, Icon> _entityIcons = new Dictionary<Entity, Icon>();
|
||||
private readonly Material[] _gravityMaterials;
|
||||
private readonly int _layer = LayerMask.NameToLayer("Minimap");
|
||||
private float _minimapScale = 1, _mapScreenScale;
|
||||
private bool _mapScreenOpen;
|
||||
private readonly Material _asteroidMaterial;
|
||||
private readonly Vector4 _spriteSheet;
|
||||
private readonly float _asteroidSize;
|
||||
|
||||
public MapPresenter(Material[] gravityMaterials, Material asteroidMaterial, int spriteColumns, int spriteRows,
|
||||
float asteroidSize)
|
||||
{
|
||||
_gravityMaterials = gravityMaterials;
|
||||
_asteroidMaterial = asteroidMaterial;
|
||||
_spriteSheet = new Vector4(spriteColumns, spriteRows, 0, 0);
|
||||
_asteroidSize = asteroidSize;
|
||||
}
|
||||
|
||||
// The icon size: the map screen's scale while it is open, else the minimap's zoom.
|
||||
public float IconSize => _mapScreenOpen ? _mapScreenScale : _minimapScale;
|
||||
public void SetMinimapScale(float scale) => _minimapScale = scale;
|
||||
public void OpenMapScreen(bool open) => _mapScreenOpen = open;
|
||||
public void SetMapScreenScale(float scale) => _mapScreenScale = scale;
|
||||
|
||||
public int IconCount => _icons.Count;
|
||||
// What the last Draw issued, for the smoke.
|
||||
public int IconDraws { get; private set; }
|
||||
public int BeltDraws { get; private set; }
|
||||
public int LastBeltInstances { get; private set; }
|
||||
public bool TryDrawn(Entity entity, out Matrix4x4 drawn)
|
||||
{
|
||||
drawn = default;
|
||||
if (!_entityIcons.TryGetValue(entity, out var icon)) return false;
|
||||
drawn = icon.Drawn;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Reads the icon child once (mesh, material, rotation relative to its root) and destroys it: from here on no
|
||||
// world transform carries the icon.
|
||||
private Icon Take(MeshRenderer renderer, Transform root, float offset)
|
||||
{
|
||||
var icon = new Icon
|
||||
{
|
||||
Mesh = renderer.GetComponent<MeshFilter>().sharedMesh,
|
||||
Material = Object.Instantiate(renderer.sharedMaterial),
|
||||
Authored = Quaternion.Inverse(root.rotation) * renderer.transform.rotation,
|
||||
Offset = offset,
|
||||
Fade = 1,
|
||||
};
|
||||
icon.Base = icon.Material.HasProperty("_Color") ? icon.Material.GetColor("_Color") : Color.white;
|
||||
Object.Destroy(renderer.gameObject);
|
||||
_icons.Add(icon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
public void RegisterEntity(Entity entity, MeshRenderer renderer, Transform root)
|
||||
{
|
||||
var icon = Take(renderer, root, entity is Ship ? ShipOffset : OrbitalOffset);
|
||||
icon.Entity = entity;
|
||||
icon.Fade = 0;
|
||||
_entityIcons[entity] = icon;
|
||||
}
|
||||
|
||||
public void RegisterPlanet(CultRecordKey key, MeshRenderer renderer, Transform root) =>
|
||||
Take(renderer, root, PlanetOffset).Planet = key;
|
||||
|
||||
// The entity's fade, applied to its icon the same frame the hull's materials take it.
|
||||
public void SetFade(Entity entity, float fade)
|
||||
{
|
||||
if (_entityIcons.TryGetValue(entity, out var icon)) icon.Fade = fade;
|
||||
}
|
||||
|
||||
public void Unregister(Entity entity)
|
||||
{
|
||||
if (!_entityIcons.Remove(entity, out var icon)) return;
|
||||
_icons.Remove(icon);
|
||||
Object.Destroy(icon.Material);
|
||||
}
|
||||
|
||||
private sealed class Belt
|
||||
{
|
||||
public float4[] Source;
|
||||
public ComputeBuffer Buffer;
|
||||
public MaterialPropertyBlock Block = new MaterialPropertyBlock();
|
||||
}
|
||||
|
||||
private readonly Dictionary<CultRecordKey, Belt> _belts = new Dictionary<CultRecordKey, Belt>();
|
||||
private static readonly int BeltProperty = Shader.PropertyToID("_Belt");
|
||||
private static readonly int SheetProperty = Shader.PropertyToID("_Sheet");
|
||||
private static readonly int PlaneProperty = Shader.PropertyToID("_PlaneY");
|
||||
private static readonly int SizeProperty = Shader.PropertyToID("_AsteroidSize");
|
||||
|
||||
// A belt's map sprites: the 3D belt's per-frame float4s (x, y planar, z spin, w size), uploaded as they are.
|
||||
public void RegisterBelt(CultRecordKey key, float4[] source) =>
|
||||
_belts[key] = new Belt { Source = source, Buffer = new ComputeBuffer(source.Length, 16) };
|
||||
|
||||
// One instanced draw per belt: six vertices per asteroid, expanded to a quad on the map plane by the shader.
|
||||
private void DrawBelt(Belt belt)
|
||||
{
|
||||
belt.Buffer.SetData(belt.Source);
|
||||
belt.Block.SetBuffer(BeltProperty, belt.Buffer);
|
||||
belt.Block.SetVector(SheetProperty, _spriteSheet);
|
||||
belt.Block.SetFloat(PlaneProperty, PlaneY + BeltOffset);
|
||||
belt.Block.SetFloat(SizeProperty, _asteroidSize);
|
||||
var parameters = new RenderParams(_asteroidMaterial)
|
||||
{
|
||||
layer = _layer, matProps = belt.Block, shadowCastingMode = ShadowCastingMode.Off,
|
||||
worldBounds = new Bounds(Vector3.zero, Vector3.one * 1e6f),
|
||||
};
|
||||
Graphics.RenderPrimitives(parameters, MeshTopology.Triangles, 6, belt.Source.Length);
|
||||
BeltDraws++;
|
||||
LastBeltInstances = belt.Source.Length;
|
||||
}
|
||||
|
||||
// Every registered icon and belt for this frame, from sim state at the drawn time; and the contour's depth range,
|
||||
// the deepest drawn planet's field depth (the map gravity materials' normalisation, not a camera bound).
|
||||
public void Draw(Zone zone, float lead)
|
||||
{
|
||||
var size = IconSize;
|
||||
IconDraws = BeltDraws = 0;
|
||||
var maxDepth = 0f;
|
||||
foreach (var icon in _icons)
|
||||
{
|
||||
float2 planar;
|
||||
Quaternion yaw = Quaternion.identity;
|
||||
if (icon.Entity != null)
|
||||
{
|
||||
var drawn = DrawAhead.Position(icon.Entity, lead);
|
||||
planar = drawn.xz;
|
||||
var rotation = icon.Entity is Ship ship ? DrawAhead.Rotation(ship, lead) : quaternion.identity;
|
||||
yaw = Quaternion.Euler(0, IconYaw(icon.Entity, rotation), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
var body = zone.PlanetInstances[icon.Planet];
|
||||
planar = DrawAhead.Orbit(zone, body.BodyData.Orbit.Key, lead);
|
||||
maxDepth = Mathf.Max(maxDepth, -DrawAhead.Height(zone, planar, lead));
|
||||
}
|
||||
|
||||
if (icon.Fade <= .01f) continue;
|
||||
if (icon.Material.HasProperty("_Color"))
|
||||
icon.Material.SetColor("_Color", new Color(icon.Base.r, icon.Base.g, icon.Base.b, icon.Base.a * icon.Fade));
|
||||
var parameters = new RenderParams(icon.Material) { layer = _layer, shadowCastingMode = ShadowCastingMode.Off };
|
||||
icon.Drawn = Matrix4x4.TRS(new Vector3(planar.x, PlaneY + icon.Offset, planar.y), yaw * icon.Authored,
|
||||
Vector3.one * size);
|
||||
Graphics.RenderMesh(parameters, icon.Mesh, 0, icon.Drawn);
|
||||
IconDraws++;
|
||||
}
|
||||
|
||||
var depthRange = Mathf.Max(maxDepth, 1f);
|
||||
foreach (var material in _gravityMaterials)
|
||||
{
|
||||
material.SetFloat("_StartDepth", 0f);
|
||||
material.SetFloat("_DepthRange", depthRange);
|
||||
}
|
||||
|
||||
foreach (var belt in _belts.Values) DrawBelt(belt);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
foreach (var icon in _icons) Object.Destroy(icon.Material);
|
||||
_icons.Clear();
|
||||
_entityIcons.Clear();
|
||||
foreach (var belt in _belts.Values) belt.Buffer.Release();
|
||||
_belts.Clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
using UnityEngine.Serialization;
|
||||
|
||||
public class MapView : MonoBehaviour
|
||||
{
|
||||
public Camera Main;
|
||||
public Camera MinimapGravity;
|
||||
public Camera Minimap;
|
||||
public MeshRenderer GravityRenderer;
|
||||
public float ZoomSpeed;
|
||||
[FormerlySerializedAs("SectorRenderer")] public ZoneRenderer ZoneRenderer;
|
||||
|
||||
private Transform _minimapTransform;
|
||||
private CopyTransform _minimapCopyTransform;
|
||||
private RenderTexture _minimapTexture;
|
||||
private Transform _minimapGravityTransform;
|
||||
private CopyTransform _minimapGravityCopyTransform;
|
||||
private RenderTexture _minimapGravityTexture;
|
||||
private Transform _gravityRendererTransform;
|
||||
private CopyTransform _gravityRendererCopyTransform;
|
||||
private RenderTexture _fullscreenGravityTexture;
|
||||
private AetheriaInput.UIActions _input;
|
||||
private float _viewDistance = 1024;
|
||||
private float _aspectRatio;
|
||||
private Vector3 _previousGravityRendererScale;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
_aspectRatio = (float) Screen.width / Screen.height;
|
||||
Main.gameObject.SetActive(false);
|
||||
_minimapTexture = Minimap.targetTexture;
|
||||
_minimapTransform = Minimap.transform;
|
||||
_minimapCopyTransform = Minimap.GetComponent<CopyTransform>();
|
||||
_minimapCopyTransform.enabled = false;
|
||||
_minimapGravityTexture = MinimapGravity.targetTexture;
|
||||
_minimapGravityTransform = MinimapGravity.transform;
|
||||
_minimapGravityCopyTransform = MinimapGravity.GetComponent<CopyTransform>();
|
||||
_minimapGravityCopyTransform.enabled = false;
|
||||
_gravityRendererTransform = GravityRenderer.transform;
|
||||
_gravityRendererCopyTransform = GravityRenderer.GetComponent<CopyTransform>();
|
||||
_gravityRendererCopyTransform.enabled = false;
|
||||
_previousGravityRendererScale = _gravityRendererTransform.localScale;
|
||||
|
||||
_fullscreenGravityTexture = new RenderTexture(Screen.width / 2, Screen.height / 2, 1, RenderTextureFormat.RFloat);
|
||||
GravityRenderer.material.mainTexture = _fullscreenGravityTexture;
|
||||
MinimapGravity.targetTexture = _fullscreenGravityTexture;
|
||||
Minimap.targetTexture = null;
|
||||
SetZoom();
|
||||
}
|
||||
|
||||
void SetZoom()
|
||||
{
|
||||
//ZoneRenderer.ViewDistance = _viewDistance * _aspectRatio;
|
||||
Minimap.orthographicSize = MinimapGravity.orthographicSize = _viewDistance;
|
||||
_gravityRendererTransform.localScale = new Vector3(_viewDistance*_aspectRatio*2, _viewDistance*2, 1);
|
||||
}
|
||||
|
||||
// public void BindInput(AetheriaInput.UIActions input)
|
||||
// {
|
||||
// _input = input;
|
||||
// _input.ScrollWheel.performed += OnScroll;
|
||||
// }
|
||||
|
||||
// private void OnScroll(InputAction.CallbackContext context)
|
||||
// {
|
||||
// _viewDistance *= (1 - context.ReadValue<Vector2>().y * ZoomSpeed);
|
||||
// SetZoom();
|
||||
// }
|
||||
|
||||
void Update()
|
||||
{
|
||||
if (_input.Click.ReadValue<float>() > .5f)
|
||||
{
|
||||
var delta = _input.Drag.ReadValue<Vector2>();
|
||||
|
||||
var pos = _minimapTransform.position;
|
||||
pos.x -= delta.x * _viewDistance / Screen.height;
|
||||
pos.z -= delta.y * _viewDistance / Screen.height;
|
||||
|
||||
var gravPos = _gravityRendererTransform.position;
|
||||
gravPos.x = pos.x;
|
||||
gravPos.z = pos.z;
|
||||
|
||||
_gravityRendererTransform.position = gravPos;
|
||||
Main.transform.position = _minimapTransform.position = _minimapGravityTransform.position = pos;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
// _input.ScrollWheel.performed -= OnScroll;
|
||||
|
||||
Main.gameObject.SetActive(true);
|
||||
_minimapGravityCopyTransform.enabled = true;
|
||||
_minimapCopyTransform.enabled = true;
|
||||
_gravityRendererCopyTransform.enabled = true;
|
||||
|
||||
Minimap.targetTexture = _minimapTexture;
|
||||
MinimapGravity.targetTexture = _minimapGravityTexture;
|
||||
GravityRenderer.material.mainTexture = _minimapGravityTexture;
|
||||
_fullscreenGravityTexture.Release();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 76d9e45f376fcfe409f3a4f26ccb4f3e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -59,7 +59,8 @@ public class ZoneRenderer : MonoBehaviour
|
|||
// public Material AsteroidMaterial;
|
||||
|
||||
[Header("Prefabs")]
|
||||
public MeshFilter AsteroidBeltUI;
|
||||
// The map's belt sprites (Aetheria/MapBelt): MapPresenter draws every belt with it.
|
||||
public Material MapAsteroidMaterial;
|
||||
public PlanetObject Planet;
|
||||
public GasGiantObject GasGiant;
|
||||
public SunObject Sun;
|
||||
|
|
@ -72,7 +73,6 @@ public class ZoneRenderer : MonoBehaviour
|
|||
[HideInInspector] public Dictionary<Entity, EntityInstance> EntityInstances = new Dictionary<Entity, EntityInstance>();
|
||||
[HideInInspector] public Dictionary<CultRecordKey, PlanetObject> Planets = new Dictionary<CultRecordKey, PlanetObject>();
|
||||
|
||||
private Dictionary<CultRecordKey, AsteroidBeltUI> _beltObjects = new Dictionary<CultRecordKey, AsteroidBeltUI>();
|
||||
private Dictionary<CultRecordKey, InstancedMesh[]> _beltMeshes = new Dictionary<CultRecordKey, InstancedMesh[]>();
|
||||
private Dictionary<CultRecordKey, Matrix4x4[][]> _beltMatrices = new Dictionary<CultRecordKey, Matrix4x4[][]>();
|
||||
// Cut 1 (docs/mining-cut.md): the renderer's own buffer, filled from Zone.EvaluateBelt each frame. No pose
|
||||
|
|
@ -93,13 +93,14 @@ public class ZoneRenderer : MonoBehaviour
|
|||
private IDisposable[] _perspectiveSubscriptions = new IDisposable[2];
|
||||
private List<IDisposable> _zoneSubscriptions = new List<IDisposable>();
|
||||
private PlanetObject[] _suns;
|
||||
private bool _showAsteroidUI;
|
||||
|
||||
public Dictionary<Wormhole, (GameObject gravity, CompassIcon icon)> WormholeInstances = new Dictionary<Wormhole, (GameObject, CompassIcon)>();
|
||||
private Dictionary<FloatingItem, ItemPickup> _floatingItems = new Dictionary<FloatingItem, ItemPickup>();
|
||||
private Dictionary<Mine, MineInstance> _mines = new Dictionary<Mine, MineInstance>();
|
||||
private Dictionary<VapourCloud, VapourCloudInstance> _clouds = new Dictionary<VapourCloud, VapourCloudInstance>();
|
||||
|
||||
// The one owner of map-space projection: every map icon and belt sprite is drawn by it.
|
||||
public MapPresenter Map { get; private set; }
|
||||
public Zone Zone { get; private set; }
|
||||
public ItemManager ItemManager { get; set; }
|
||||
|
||||
|
|
@ -151,31 +152,15 @@ public class ZoneRenderer : MonoBehaviour
|
|||
_minimapDistance = value;
|
||||
foreach (var camera in MinimapCameras)
|
||||
camera.orthographicSize = value;
|
||||
SetIconSize(value * Settings.MinimapIconSize);
|
||||
Map.SetMinimapScale(value * Settings.MinimapIconSize);
|
||||
// MinimapGravityQuad.transform.localScale = value * 2 * Vector3.one;
|
||||
}
|
||||
}
|
||||
|
||||
public bool ShowAsteroidUI
|
||||
void Awake()
|
||||
{
|
||||
get { return _showAsteroidUI; }
|
||||
set
|
||||
{
|
||||
if (value != _showAsteroidUI)
|
||||
{
|
||||
_showAsteroidUI = value;
|
||||
foreach (var beltUI in _beltObjects.Values)
|
||||
{
|
||||
beltUI.Filter.gameObject.SetActive(_showAsteroidUI);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetIconSize(float size)
|
||||
{
|
||||
foreach(var entityInstance in EntityInstances.Values) entityInstance.MapIcon.transform.localScale = Vector3.one * size;
|
||||
foreach(var planet in Planets.Values) planet.Icon.transform.localScale = Vector3.one * size;
|
||||
Map = new MapPresenter(MapGravityMaterials, MapAsteroidMaterial, AsteroidSpritesheetWidth,
|
||||
AsteroidSpritesheetHeight, Settings.MinimapAsteroidSize);
|
||||
}
|
||||
|
||||
void Start()
|
||||
|
|
@ -395,12 +380,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
}
|
||||
|
||||
Planets.Clear();
|
||||
foreach (var beltObject in _beltObjects.Values)
|
||||
{
|
||||
Destroy(beltObject.Filter);
|
||||
}
|
||||
|
||||
_beltObjects.Clear();
|
||||
Map.Clear();
|
||||
_beltMeshes.Clear();
|
||||
_beltMatrices.Clear();
|
||||
_beltTransforms.Clear();
|
||||
|
|
@ -455,6 +435,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
}
|
||||
}
|
||||
|
||||
Map.Unregister(entity);
|
||||
Destroy(EntityInstances[entity].gameObject);
|
||||
EntityInstances.Remove(entity);
|
||||
}
|
||||
|
|
@ -476,16 +457,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
_beltMatrices[key][i] = new Matrix4x4[i < meshes.Count - 1 ? count : count + remainder];
|
||||
}
|
||||
|
||||
var beltObject = Instantiate(AsteroidBeltUI, ZoneRoot);
|
||||
var collider = beltObject.GetComponent<MeshCollider>();
|
||||
var belt = new AsteroidBeltUI(Zone,
|
||||
Zone.AsteroidBelts[key],
|
||||
beltObject,
|
||||
collider,
|
||||
AsteroidSpritesheetWidth,
|
||||
AsteroidSpritesheetHeight,
|
||||
Settings.MinimapAsteroidSize);
|
||||
_beltObjects[key] = belt;
|
||||
Map.RegisterBelt(key, _beltTransforms[key]);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -525,7 +497,7 @@ public class ZoneRenderer : MonoBehaviour
|
|||
|
||||
var planetInstance = Zone.PlanetInstances[key];
|
||||
planet.Body.transform.localScale = planetInstance.BodyRadius * Vector3.one;
|
||||
planet.Icon.transform.localScale = Settings.IconSize.Evaluate(planetInstance.BodyData.Mass) * Vector3.one;
|
||||
Map.RegisterPlanet(key, planet.Icon, planet.transform);
|
||||
|
||||
|
||||
Planets[key] = planet;
|
||||
|
|
@ -539,9 +511,13 @@ public class ZoneRenderer : MonoBehaviour
|
|||
LODHandler.FindPlanets();
|
||||
}
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
Map.Draw(Zone, ActionGameManager.Clock.Lead);
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
var maxDepth = 0f;
|
||||
var lead = ActionGameManager.Clock.Lead;
|
||||
GravityLowering.Lower(Zone, lead, ref _gravityWells);
|
||||
foreach (var loot in _floatingItems.Values)
|
||||
|
|
@ -594,9 +570,6 @@ public class ZoneRenderer : MonoBehaviour
|
|||
Graphics.DrawMeshInstanced(meshes[i].Mesh, 0, meshes[i].Material, matrices[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if(_showAsteroidUI)
|
||||
_beltObjects[key].Update(transforms, height);
|
||||
}
|
||||
|
||||
foreach (var planet in Planets)
|
||||
|
|
@ -604,10 +577,8 @@ public class ZoneRenderer : MonoBehaviour
|
|||
var planetInstance = Zone.PlanetInstances[planet.Key];
|
||||
var p = DrawAhead.Orbit(Zone, planetInstance.BodyData.Orbit.Key, lead);
|
||||
var height = DrawAhead.Height(Zone, p, lead);
|
||||
if (-height > maxDepth) maxDepth = -height;
|
||||
planet.Value.transform.position = new Vector3(p.x, 0, p.y);
|
||||
planet.Value.Body.transform.localPosition = new Vector3(0, height + planetInstance.BodyRadius * 2, 0);
|
||||
planet.Value.Icon.transform.localPosition = new Vector3(0, height, 0);
|
||||
if (planet.Value is GasGiantObject gasGiantObject)
|
||||
{
|
||||
if (!(planet.Value is SunObject))
|
||||
|
|
@ -641,13 +612,6 @@ public class ZoneRenderer : MonoBehaviour
|
|||
wormhole.icon.transform.rotation = Quaternion.Euler(0, 0, Mathf.Atan2(difference.y, difference.x) * Mathf.Rad2Deg - 90);
|
||||
}
|
||||
|
||||
//var fogPos = FogCameraParent.position;
|
||||
var depthRange = Mathf.Max(maxDepth, 1f);
|
||||
foreach (var mat in MapGravityMaterials)
|
||||
{
|
||||
mat.SetFloat("_StartDepth", 0f);
|
||||
mat.SetFloat("_DepthRange", depthRange);
|
||||
}
|
||||
// var gravPos = MinimapGravityQuad.transform.position;
|
||||
// MinimapGravityQuad.transform.position = gravPos;
|
||||
// MinimapTintQuad.transform.position = gravPos - Vector3.up*10;
|
||||
|
|
@ -661,98 +625,3 @@ public class InstancedMesh
|
|||
public Mesh Mesh;
|
||||
public Material Material;
|
||||
}
|
||||
|
||||
public class AsteroidBeltUI
|
||||
{
|
||||
public MeshFilter Filter;
|
||||
private MeshCollider _collider;
|
||||
private Vector3[] _vertices;
|
||||
private Vector3[] _normals;
|
||||
private Vector2[] _uvs;
|
||||
private int[] _indices;
|
||||
private CultRecordKey _orbitParent;
|
||||
private Mesh _mesh;
|
||||
private float _size;
|
||||
private Zone _zone;
|
||||
private AsteroidBelt _belt;
|
||||
private float _scale;
|
||||
|
||||
public AsteroidBeltUI(Zone zone,
|
||||
AsteroidBelt belt,
|
||||
MeshFilter meshFilter,
|
||||
MeshCollider collider,
|
||||
int spritesheetWidth,
|
||||
int spritesheetHeight,
|
||||
float scale)
|
||||
{
|
||||
_belt = belt;
|
||||
_zone = zone;
|
||||
Filter = meshFilter;
|
||||
_collider = collider;
|
||||
var orbit = zone.Orbits[belt.Data.Orbit.Key];
|
||||
_orbitParent = orbit.Data.Parent.Key;
|
||||
_vertices = new Vector3[_belt.Data.Asteroids.Length * 4];
|
||||
_normals = new Vector3[_belt.Data.Asteroids.Length * 4];
|
||||
_uvs = new Vector2[_belt.Data.Asteroids.Length * 4];
|
||||
_indices = new int[_belt.Data.Asteroids.Length * 6];
|
||||
_scale = scale;
|
||||
|
||||
var maxDist = 0f;
|
||||
var spriteSize = float2(1f / spritesheetWidth, 1f / spritesheetHeight);
|
||||
// vertex order: bottom left, top left, top right, bottom right
|
||||
for (var i = 0; i < belt.Data.Asteroids.Length; i++)
|
||||
{
|
||||
if (belt.Data.Asteroids[i].Distance > maxDist)
|
||||
maxDist = belt.Data.Asteroids[i].Distance;
|
||||
var spriteX = Random.Range(0, spritesheetWidth);
|
||||
var spriteY = Random.Range(0, spritesheetHeight);
|
||||
|
||||
_uvs[i * 4] = new Vector2(spriteX * spriteSize.x, spriteY * spriteSize.y);
|
||||
_uvs[i * 4 + 1] = new Vector2(spriteX * spriteSize.x, spriteY * spriteSize.y + spriteSize.y);
|
||||
_uvs[i * 4 + 2] = new Vector2(spriteX * spriteSize.x + spriteSize.x, spriteY * spriteSize.y + spriteSize.y);
|
||||
_uvs[i * 4 + 3] = new Vector2(spriteX * spriteSize.x + spriteSize.x, spriteY * spriteSize.y);
|
||||
|
||||
_indices[i * 6] = i * 4;
|
||||
_indices[i * 6 + 1] = i * 4 + 1;
|
||||
_indices[i * 6 + 2] = i * 4 + 3;
|
||||
_indices[i * 6 + 3] = i * 4 + 3;
|
||||
_indices[i * 6 + 4] = i * 4 + 1;
|
||||
_indices[i * 6 + 5] = i * 4 + 2;
|
||||
}
|
||||
|
||||
for (var i = 0; i < _normals.Length; i++)
|
||||
{
|
||||
_normals[i] = -Vector3.forward;
|
||||
}
|
||||
|
||||
_mesh = new Mesh();
|
||||
_mesh.vertices = _vertices;
|
||||
_mesh.uv = _uvs;
|
||||
_mesh.triangles = _indices;
|
||||
_mesh.normals = _normals;
|
||||
_mesh.bounds = new Bounds(Vector3.zero, Vector3.one * maxDist);
|
||||
_size = maxDist;
|
||||
|
||||
Filter.mesh = _mesh;
|
||||
//_collider.sharedMesh = _mesh;
|
||||
}
|
||||
|
||||
public void Update(float4[] transforms, float height)
|
||||
{
|
||||
var parentPosition = DrawAhead.Orbit(_zone, _orbitParent, ActionGameManager.Clock.Lead);
|
||||
for (var i = 0; i < transforms.Length; i++)
|
||||
{
|
||||
var transform = transforms[i];
|
||||
var rotation = Quaternion.Euler(90, transform.z, 0);
|
||||
var position = new Vector3(transform.x, height, transform.y);
|
||||
_vertices[i * 4] = rotation * new Vector3(-transform.w * _scale, -transform.w * _scale, 0) + position;
|
||||
_vertices[i * 4 + 1] = rotation * new Vector3(-transform.w * _scale, transform.w * _scale, 0) + position;
|
||||
_vertices[i * 4 + 2] = rotation * new Vector3(transform.w * _scale, transform.w * _scale, 0) + position;
|
||||
_vertices[i * 4 + 3] = rotation * new Vector3(transform.w * _scale, -transform.w * _scale, 0) + position;
|
||||
}
|
||||
|
||||
_mesh.bounds = new Bounds(new Vector3(parentPosition.x, 0, parentPosition.y), Vector3.one * (_size * 2));
|
||||
_mesh.vertices = _vertices;
|
||||
//_collider.sharedMesh = _mesh;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
59
Assets/Shaders/MapBelt.shader
Normal file
59
Assets/Shaders/MapBelt.shader
Normal file
|
|
@ -0,0 +1,59 @@
|
|||
// The minimap and map screen's belt asteroids: one instanced draw per belt, six vertices per asteroid expanded to a
|
||||
// quad on the map plane. _Belt holds the belt's per-frame float4s (x, y planar, z spin in degrees, w size); the sprite
|
||||
// cell is a hash of the instance id, so a belt keeps its sprites without any per-asteroid CPU state.
|
||||
Shader "Aetheria/MapBelt"
|
||||
{
|
||||
Properties { _MainTex ("Sprite Sheet", 2D) = "white" {} _Color ("Color", Color) = (1,1,1,1) }
|
||||
SubShader
|
||||
{
|
||||
Tags { "Queue"="Transparent" "RenderType"="Transparent" "IgnoreProjector"="True" }
|
||||
Cull Off ZWrite Off Blend SrcAlpha OneMinusSrcAlpha
|
||||
Pass
|
||||
{
|
||||
CGPROGRAM
|
||||
#pragma vertex vert
|
||||
#pragma fragment frag
|
||||
#pragma target 4.5
|
||||
#include "UnityCG.cginc"
|
||||
|
||||
sampler2D _MainTex;
|
||||
fixed4 _Color;
|
||||
StructuredBuffer<float4> _Belt;
|
||||
float4 _Sheet;
|
||||
float _PlaneY;
|
||||
float _AsteroidSize;
|
||||
|
||||
struct v2f { float4 pos : SV_POSITION; float2 uv : TEXCOORD0; };
|
||||
|
||||
uint Hash(uint x)
|
||||
{
|
||||
x = x * 747796405u + 2891336453u;
|
||||
x = ((x >> ((x >> 28u) + 4u)) ^ x) * 277803737u;
|
||||
return (x >> 22u) ^ x;
|
||||
}
|
||||
|
||||
v2f vert(uint vid : SV_VertexID, uint iid : SV_InstanceID)
|
||||
{
|
||||
// Triangles (0,1,3) and (3,1,2) over the corners bottom left, top left, top right, bottom right.
|
||||
static const uint corner[6] = { 0, 1, 3, 3, 1, 2 };
|
||||
static const float2 offsets[4] = { float2(-1, -1), float2(-1, 1), float2(1, 1), float2(1, -1) };
|
||||
float4 a = _Belt[iid];
|
||||
float2 o = offsets[corner[vid]];
|
||||
float theta = radians(a.z);
|
||||
float s = sin(theta), c = cos(theta);
|
||||
float2 q = o * a.w * _AsteroidSize;
|
||||
float3 world = float3(a.x + q.x * c + q.y * s, _PlaneY, a.y - q.x * s + q.y * c);
|
||||
uint cell = Hash(iid) % (uint)(_Sheet.x * _Sheet.y);
|
||||
float2 size = float2(1.0 / _Sheet.x, 1.0 / _Sheet.y);
|
||||
float2 origin = float2(cell % (uint)_Sheet.x, cell / (uint)_Sheet.x) * size;
|
||||
v2f v;
|
||||
v.pos = mul(UNITY_MATRIX_VP, float4(world, 1));
|
||||
v.uv = origin + (o * .5 + .5) * size;
|
||||
return v;
|
||||
}
|
||||
|
||||
fixed4 frag(v2f v) : SV_Target { return tex2D(_MainTex, v.uv) * _Color; }
|
||||
ENDCG
|
||||
}
|
||||
}
|
||||
}
|
||||
9
Assets/Shaders/MapBelt.shader.meta
Normal file
9
Assets/Shaders/MapBelt.shader.meta
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 22e2fc798f044a3aa2f6cd71f1df09a7
|
||||
ShaderImporter:
|
||||
externalObjects: {}
|
||||
defaultTextures: []
|
||||
nonModifiableTextures: []
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -555,7 +555,7 @@ public sealed partial class RunStartTests
|
|||
Assert.False(main.IsTutorial);
|
||||
}
|
||||
|
||||
// PlayerSettings Key 2, the never-written tutorial flag, is retired: a player.cc written with it still loads, every other field intact.
|
||||
// PlayerSettings Key 2, the never-written tutorial flag, and PlayerGraphicsSettings Key 1, ShowAsteroidsInMinimap, are retired: a player.cc written with it still loads, every other field intact.
|
||||
[Fact]
|
||||
public void OldPlayerSettingsLoad()
|
||||
{
|
||||
|
|
@ -569,7 +569,10 @@ public sealed partial class RunStartTests
|
|||
MessagePackSerializer.Serialize(ref writer, new Dictionary<string, string> { ["story"] = "hash" }, options);
|
||||
MessagePackSerializer.Serialize(ref writer, new PlayerGameplaySettings { TemperatureUnit = TemperatureUnit.Kelvin, SignificantDigits = 5 }, options);
|
||||
MessagePackSerializer.Serialize(ref writer, new PlayerInputSettings { ActionBarInputs = { "<Keyboard>/1" } }, options);
|
||||
MessagePackSerializer.Serialize(ref writer, new PlayerGraphicsSettings { NebulaQuality = Quality.High, ShowAsteroidsInMinimap = true }, options);
|
||||
writer.WriteArrayHeader(3); // PlayerGraphicsSettings with its retired Key 1 (ShowAsteroidsInMinimap)
|
||||
MessagePackSerializer.Serialize(ref writer, Quality.High, options);
|
||||
writer.Write(true);
|
||||
writer.Write(.4f);
|
||||
writer.Flush();
|
||||
|
||||
var settings = MessagePackSerializer.Deserialize<PlayerSettings>(buffer.WrittenMemory, options);
|
||||
|
|
@ -578,7 +581,7 @@ public sealed partial class RunStartTests
|
|||
Assert.Equal("hash", settings.HashedStoryFiles["story"]);
|
||||
Assert.Equal((TemperatureUnit.Kelvin, 5), (settings.GameplaySettings.TemperatureUnit, settings.GameplaySettings.SignificantDigits));
|
||||
Assert.Equal("<Keyboard>/1", Assert.Single(settings.InputSettings.ActionBarInputs));
|
||||
Assert.Equal((Quality.High, true), (settings.GraphicsSettings.NebulaQuality, settings.GraphicsSettings.ShowAsteroidsInMinimap));
|
||||
Assert.Equal((Quality.High, .4f), (settings.GraphicsSettings.NebulaQuality, settings.GraphicsSettings.ScreenShake));
|
||||
}
|
||||
|
||||
// A scenario's Brief is player text (the menu shows it): it names gear by what the catalog sells today. A name a rename retired,
|
||||
|
|
|
|||
Loading…
Reference in a new issue