namespace AcDream.App.Rendering.Scene;
///
/// Projects the retained PView route stream into particle-owner identities.
/// This keeps attached-effect routing on the same visibility decision as mesh
/// submission without walking spatial/gameplay entities a second time.
///
internal static class RenderFrameRouteOwnerSelector
{
public static void Replace(
HashSet destination,
in RenderFrameView view,
RenderFrameCandidateRoute route,
int routeIndex,
uint cellId)
{
ArgumentNullException.ThrowIfNull(destination);
destination.Clear();
Union(
destination,
in view,
route,
routeIndex,
cellId);
}
public static void Union(
HashSet destination,
in RenderFrameView view,
RenderFrameCandidateRoute route,
int routeIndex,
uint cellId)
{
ArgumentNullException.ThrowIfNull(destination);
VisitExact(
destination,
in view,
route,
routeIndex,
cellId,
remove: false);
}
public static void ExceptRoute(
HashSet destination,
in RenderFrameView view,
RenderFrameCandidateRoute route)
{
ArgumentNullException.ThrowIfNull(destination);
ReadOnlySpan ranges =
view.RouteRanges;
ReadOnlySpan candidates =
view.RouteCandidates;
for (int index = 0; index < ranges.Length; index++)
{
RenderFrameCandidateRange range = ranges[index];
if (range.Route != route)
continue;
ApplyRange(
destination,
candidates,
in range,
remove: true);
}
}
private static void VisitExact(
HashSet destination,
in RenderFrameView view,
RenderFrameCandidateRoute route,
int routeIndex,
uint cellId,
bool remove)
{
ReadOnlySpan ranges =
view.RouteRanges;
ReadOnlySpan candidates =
view.RouteCandidates;
for (int index = 0; index < ranges.Length; index++)
{
RenderFrameCandidateRange range = ranges[index];
if (range.Route != route
|| range.RouteIndex != routeIndex
|| range.CellId != cellId)
{
continue;
}
ApplyRange(
destination,
candidates,
in range,
remove);
return;
}
}
private static void ApplyRange(
HashSet destination,
ReadOnlySpan candidates,
in RenderFrameCandidateRange range,
bool remove)
{
ReadOnlySpan owners =
candidates.Slice(range.Offset, range.Count);
for (int index = 0; index < owners.Length; index++)
{
uint localEntityId = owners[index].Source.LocalEntityId;
if (localEntityId == 0)
continue;
if (remove)
destination.Remove(localEntityId);
else
destination.Add(localEntityId);
}
}
}