Skip to content

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 ComponentTypeHandle instances 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.GetOrCreateSystemManaged in 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.