Skip to content

StackPreview

Namespace Nfty.Core.Imaging in assembly Nfty.Core.

public static class StackPreview

Composites several layers at their real depths, so art authored one layer at a time can be lined up against the layers it will actually sit between.

It introduces no third rendering path. Every layer goes through VariantPreview.Render — the one rule for what a Variant looks like — and the stack goes through Compositor.Composite() — the one rule for how layers combine. That is the property the project protects: the CLI's preview and the GUI's preview must produce the same image, not a similar one, and two copies of a colorizer is precisely how that stops being true.

Methods

PickVariant(LoadedIngredient)

public static string PickVariant(LoadedIngredient ingredient);

The variant to show when the caller has not named one: highest weight, ties broken by ordinal-first id.

Deliberately not a roll. A reference layer that changed appearance between repaints would make the alignment this feature exists to show unreadable, so there is no RNG here — and the tie-break is ordinal because a culture-sensitive one would pick differently on another machine.

A zero weight shelves a variant from generation but does not hide it here: the most probable variant is simply the one with the largest weight, and an ingredient whose variants are all shelved still previews as its ordinal-first one rather than failing.

Parameters

  • ingredient (LoadedIngredient) - The layer to pick a variant from.

Returns. The chosen variant's id.

Exceptions

  • ArgumentNullException - ingredient is null.
  • InvalidOperationException - The ingredient declares no variants, so there is nothing to draw.

Render(Dimensions, IReadOnlyList<PreviewLayer>)

public static Image<Rgba32> Render(Dimensions canvas, IReadOnlyList<PreviewLayer> bottomToTop);

Renders a stack of reference layers onto a transparent canvas.

Parameters

  • canvas (Dimensions) - The output size. Every layer must match it exactly.
  • bottomToTop (IReadOnlyList<PreviewLayer>) - The layers in paint order — index 0 paints first and everything after paints over it. An EMPTY list is legal and yields a fully transparent canvas: "no references on" is this feature's default state, not an error.

Returns. The composited preview. The caller owns it and must dispose it; every intermediate this method creates is disposed here, on the success path and on every failure path alike.

Exceptions

  • ArgumentNullException - canvas or bottomToTop is null.
  • ArgumentException - A layer carries no ingredient. Reachable only through default(PreviewLayer) — a struct cannot enforce its own non-null field — which is why it is checked rather than assumed.
  • InvalidOperationException - A layer's image does not match the canvas, or VariantPreview.Render refused it (unknown variant, colorized layer with no color).

Split(RecipeManifest, string, IEnumerable<string>)

public static StackSplit Split(RecipeManifest recipe, string editedIngredientId, IEnumerable<string> enabledIngredientIds);

Splits a recipe's enabled reference layers around the layer being edited.

Ordering comes from LayerDepth — the same 1-based, bottom-first projection of layerOrder that a layer table numbers its rows with — so the preview cannot disagree with the depths the author is looking at. It lives in Core precisely so the CLI and the GUI cannot compute the split two different ways.

Parameters

  • recipe (RecipeManifest) - The recipe whose stack is being previewed.
  • editedIngredientId (string) - The layer being authored. It is pinned at its own depth and never returned in either list, even if the caller also names it as enabled — it is the subject of the preview, not a reference in it.
  • enabledIngredientIds (IEnumerable<string>) - Which reference layers the author has switched on. An id the recipe does not stack is IGNORED rather than rejected — it has no depth here, so there is no position to put it at — which keeps a stale checkbox left over from a removed layer out of the panel instead of throwing in the middle of a repaint. This is not how a Kitchen layer gets placed. Only ids the recipe stacks are ever returned, so passing a loose .igt id in here yields nothing at all. A Kitchen layer has no canonical depth by design, and the caller places it in the gaps around what this returns — entirely outside this method. An earlier version of this comment claimed the tolerance above WAS the Kitchen case; it is not, and a caller who believed it would silently drop every loose layer.

Returns. The enabled layers below and above, each bottom-to-top.

Exceptions

  • ArgumentNullException - recipe or enabledIngredientIds is null.
  • KeyNotFoundException - The recipe does not stack editedIngredientId. Unlike an unknown reference, this one has no sane reading: there is no depth to split around.