Game.Rendering.RouteRenderSystem
Assembly: Assembly-CSharp (game code)
Namespace: Game.Rendering
Type: class
Base: GameSystemBase
Summary:
RouteRenderSystem is an ECS system responsible for rendering route segments (routes and live paths) in the game world. It queries route entities, builds indirect draw arguments, binds per-route compute buffers and material parameters, and issues DrawMeshInstancedIndirect calls for Game and SceneView cameras. It subscribes to the Scriptable Render Pipeline’s begin-context rendering callback to perform rendering outside the normal ECS update loop. The system also manages a small procedural mesh used to render route segments and a ComputeBuffer for indirect draw arguments.
Fields
-
private struct TypeHandle
Internal generated struct that caches EntityTypeHandle and ComponentTypeHandleinstances used when accessing archetype chunk data. It provides an __AssignHandles method to initialize the handles from a SystemState. -
private ToolSystem m_ToolSystem
Reference to the ToolSystem (fetched via World.GetOrCreateSystemManagedin OnCreate). Used to access the currently selected tool and selected entity. -
private RouteBufferSystem m_RouteBufferSystem
Reference to RouteBufferSystem used to obtain per-route data like the segment ComputeBuffer, material, original render queue, bounds and size. -
private EntityQuery m_RouteQuery
EntityQuery selecting route entities (Route, RouteWaypoint, RouteSegment; excludes HiddenRoute, Deleted, Hidden). Used when regular route rendering is required. -
private EntityQuery m_LivePathQuery
EntityQuery selecting LivePath entities (LivePath, RouteWaypoint, RouteSegment; excludes HiddenRoute, Deleted, Hidden). Used when only live path drawing is needed (e.g. tools that show only live paths). -
private EntityQuery m_InfomodeQuery
EntityQuery that detects when an infomode requiring route overlay is active (InfomodeActive + InfoviewRouteData). -
private Mesh m_Mesh
Procedural mesh used for rendering a single route segment instance. Built on demand in EnsureMesh(). -
private ComputeBuffer m_ArgsBuffer
GPU ComputeBuffer used for indirect draw arguments (DrawMeshInstancedIndirect). Resized/recreated to hold enough draw argument entries for all instances. -
private List<uint> m_ArgsArray
CPU-side list of uints used to populate m_ArgsBuffer (indirect draw arguments per instance). -
private int m_RouteSegmentBuffer
Shader property ID for the per-route segment ComputeBuffer (set via Shader.PropertyToID("colossal_RouteSegmentBuffer")). -
private int m_RouteColor
Shader property ID for route color (colossal_RouteColor). -
private int m_RouteSize
Shader property ID for route size (colossal_RouteSize). -
private TypeHandle __TypeHandle
Instance of the generated TypeHandle struct used to cache and access ComponentTypeHandle instances.
Properties
- (none)
Constructors
public RouteRenderSystem()
Default constructor. The system uses [Preserve] attributes on lifecycle methods and relies on OnCreate to initialize runtime state.
Methods
[Preserve] protected override void OnCreate()
Initializes the system:- Acquires references to ToolSystem and RouteBufferSystem from the World.
- Creates EntityQueries for routes, live paths and infomode detection.
- Initializes shader property IDs (m_RouteSegmentBuffer, m_RouteColor, m_RouteSize).
- Subscribes to RenderPipelineManager.beginContextRendering with the Render callback. Notes:
- Initialization is done on main thread. No GPU resources are created here beyond storing property IDs.
-
The subscription ensures the Render method is invoked as part of the SRP rendering loop.
-
[Preserve] protected override void OnDestroy()
Cleanup: - Unsubscribes from RenderPipelineManager.beginContextRendering.
- Destroys the procedural mesh if created (Object.Destroy).
- Releases the m_ArgsBuffer ComputeBuffer if allocated.
-
Calls base.OnDestroy(). Important to avoid leaking GPU resources and render callbacks.
-
[Preserve] protected override void OnUpdate()
Empty override. Rendering is performed in the SRP callback (Render), so OnUpdate does not perform per-frame rendering work. -
private void Render(ScriptableRenderContext context, List<Camera> cameras)
Main render routine invoked during beginContextRendering. High-level behavior: - Chooses between m_RouteQuery and m_LivePathQuery depending on ShouldRenderRoutes().
- Early-outs if selected query is empty.
- Converts the EntityQuery to an ArchetypeChunk array (Allocator.TempJob), iterates chunks and counts instances.
- Ensures the procedural mesh exists (EnsureMesh()).
- Computes total instance count and allocates/recreates m_ArgsBuffer as a ComputeBuffer of appropriate size.
- Calls CompleteDependency() and obtains EntityTypeHandle and ComponentTypeHandle
instances via InternalCompilerInterface. - For each archetype chunk: gets native arrays for Entity, RouteBufferIndex, Color, Temp, and checks Highlighted presence.
- For each entity in the chunk:
- Retrieves route buffer data from m_RouteBufferSystem.GetBuffer(index).
- Skips if material or segmentBuffer is null.
- Appends an indirect draw argument entry to m_ArgsArray (indexCount, instanceCount, indexStart, baseVertex, 0).
- Adjusts color alpha and size if entity is selected, highlighted, or has Temp flags (Create/Delete/Select/Modify), and bumps material.renderQueue if highlighted/selected.
- Binds segment ComputeBuffer and material parameters (color, size).
- Expands bounds by size.x and issues Graphics.DrawMeshInstancedIndirect for each camera of type Game or SceneView.
- After processing chunks, writes m_ArgsArray data into m_ArgsBuffer via SetData. Notes and caveats:
- The method relies on m_RouteBufferSystem to provide a ComputeBuffer of route segments and an appropriate material.
- Uses DrawMeshInstancedIndirect: the GPU expects valid argument buffers; m_ArgsBuffer entries hold one draw call per route material/segment buffer.
-
Accesses ECS data via ComponentTypeHandle and archetype chunk APIs; CompleteDependency() is used to ensure safety with scheduled jobs.
-
private bool ShouldRenderRoutes()
Returns true when routes should be rendered: - If an active tool requires route data (tool.requireRoutes != RouteType.None).
-
Or if m_InfomodeQuery is non-empty (an infomode requires route overlay). Otherwise returns false. This controls whether m_RouteQuery or m_LivePathQuery is used.
-
private void EnsureMesh()
Builds the procedural mesh used to render a route segment if m_Mesh is null. - Creates a vertex array and uv array; constructs two strips (one along X and one along Y) subdivided into 16 segments each, producing a total of 68 vertices and 192 indices.
-
The mesh is named "Route segment" and has vertices, uv and triangles assigned. This mesh is small and designed to be instanced for individual route segments with GPU-based segment data.
-
[MethodImpl(MethodImplOptions.AggressiveInlining)] private void __AssignQueries(ref SystemState state)
Generated helper used during compiler-generated initialization. In this implementation it constructs an EntityQueryBuilder and immediately disposes it. Not intended for external use. -
protected override void OnCreateForCompiler()
Compiler-time helper: calls base.OnCreateForCompiler(), sets up queries and assigns component type handles via the generated TypeHandle.__AssignHandles method. This is part of the ECS AOT/codegen support.
Usage Example
[Preserve]
protected override void OnCreate()
{
base.OnCreate();
// Acquire systems used by RouteRenderSystem
m_ToolSystem = base.World.GetOrCreateSystemManaged<ToolSystem>();
m_RouteBufferSystem = base.World.GetOrCreateSystemManaged<RouteBufferSystem>();
// Prepare EntityQueries, shader property IDs and subscribe to SRP rendering callback
m_RouteQuery = GetEntityQuery(ComponentType.ReadOnly<Route>(), ComponentType.ReadOnly<RouteWaypoint>(), ComponentType.ReadOnly<RouteSegment>(), ComponentType.Exclude<HiddenRoute>(), ComponentType.Exclude<Deleted>(), ComponentType.Exclude<Hidden>());
m_LivePathQuery = GetEntityQuery(ComponentType.ReadOnly<LivePath>(), ComponentType.ReadOnly<RouteWaypoint>(), ComponentType.ReadOnly<RouteSegment>(), ComponentType.Exclude<HiddenRoute>(), ComponentType.Exclude<Deleted>(), ComponentType.Exclude<Hidden>());
m_InfomodeQuery = GetEntityQuery(ComponentType.ReadOnly<InfomodeActive>(), ComponentType.ReadOnly<InfoviewRouteData>());
m_RouteSegmentBuffer = Shader.PropertyToID("colossal_RouteSegmentBuffer");
m_RouteColor = Shader.PropertyToID("colossal_RouteColor");
m_RouteSize = Shader.PropertyToID("colossal_RouteSize");
RenderPipelineManager.beginContextRendering += Render;
}
Notes and implementation tips: - This system ties ECS data to SRP rendering; be careful about threading and job dependencies. CompleteDependency() is used to synchronize with scheduled jobs before you access chunk data on the main thread. - The system assumes RouteBufferSystem provides a ComputeBuffer per-route that contains segment data expected by the route material shader. - OnDestroy must release GPU resources and unsubscribe from RenderPipelineManager to avoid leaks and crashes on domain reload. - If modifying or extending this system (e.g., to add new route visuals), ensure shader property names, mesh topology and argument buffer layout remain consistent with DrawMeshInstancedIndirect usage.