public static class TextureProjectImagesFills a compiled plan's external images out of a project's own assets.
Remarks
The half of the editor's resolver that is about a project on disk rather than about a live session — #1087. Upload fills the externals whose bytes the compilation carries and hands back the ones naming an asset, so that a host with no asset database can see before it starts that this graph is not one it can bake. Every host that does have one then wants the same six steps, and until now those six steps existed once, , inside the texturing plugin — so vixen texture bake --graph could bake every generator, pattern and noise graph and refused any graph with a Source/Bitmap pointing at an imported PNG.
⚠ The decode is the caller's and that is a measurement rather than a preference. ImageDecoders lives in Vixen.Editor.Assets, whose project closure is 54 assemblies against this one's 32 and adds 25 of them — Vixen.Engine, Vixen.Ecs, Vixen.Terrain, Vixen.Water, Vixen.Navigation, Vixen.Editor.VfxGraph among them (measured over every ProjectReference in the tree on 2026-09-08). Referencing it to save one switch on a file extension would put the whole runtime behind an evaluator whose README says it "knows nothing about a project, a document or a panel". Vixen.Editor.Core, which EditorProject comes from, adds nothing: it is already in this assembly's closure through Vixen.Editor.NodeGraph, so naming it directly widens what this compilation may spell and not what it loads.
⚠ So the cut is between what drifts silently and what drifts loudly. Which folder an asset reference resolves against, what a missing one is called, and the refusal of a format the plan's external slot cannot hold are all here, because two hosts disagreeing about any of them produces a picture rather than an error. Choosing a decoder for an extension is the caller's, because a host that gets it wrong fails to read a file and says so.
⚠ Rgba8 only, and it is a real limit rather than an oversight. The plan's external image for a Source/Bitmap is Rgba8 — BitmapNode says why — so a KTX2 or DDS asset that decodes to a block-compressed format has the wrong byte count for the image it would fill, and TextureUploads.Add would refuse it with a message about a byte count rather than about a file. Named here instead.
⚠ Every failure is a returned sentence and none is an exception, including the ones that are this build's fault. A preview runs on every edit and a throw out of one takes the editor's frame with it — so a file that has been deleted, a format nothing decodes, and a decoder that read the file and produced nothing are all the same kind of answer.
Methods (2)
public static List<string> Fill(EditorProject project, TextureUploads uploads, TexturePlan plan, ImmutableArray<TextureGraphExternal> owed, Func<string, (TextureData? Picture, string? Unreadable)> read)Fills every external naming a project asset, and says which ones it could not.
public static string? Resolve(EditorProject project, TextureUploads uploads, TexturePlan plan, TextureGraphExternal entry, Func<string, (TextureData? Picture, string? Unreadable)> read)Reads one external image out of the project's assets and uploads it.
Used by (3)
- TextureExternalImagesVixen.Editor.Texturing
- TextureGraphRunnerVixen.Cli
- TextureProjectImagesTestsVixen.Editor.TextureGraph.Tests