You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
2026-07-29 — NormalOutputMode.BOTH is actually both. The guard that stops the engine clobbering a user-supplied complement short-circuited the whole branch whenever the batch carried OpenGL, so a GL-only batch — the common case — never got its DirectX counterpart, and the DX-from-GL branch below it was unreachable in the normal flow. Verified empirically: a DirectX source produced both files, an OpenGL source produced only OpenGL, contradicting the mode's own docstring ("save the provided format + auto-generate the complement"). The guard is now per-direction — emit the counterpart of whichever format the map is, and only when that counterpart is absent from the batch inventory — restoring symmetry without weakening the anti-clobber rule: a batch carrying both formats still regenerates neither, and the DX/GL variant sets are disjoint so at most one branch applies. Note for GL-only projects: BOTH now writes the _Normal_DirectX.png sibling it used to skip; select OpenGL only in the compositor's normal-mode combo to opt out.
2026-07-29 — MapCompositor's output template no longer touches textures it didn't write.apply_output_template re-scanned output_dir with get_images and handed everything it found to MapFactory.prepare_maps. Compositing into a shared library folder — a project's sourceimages, the normal case — therefore swept every pre-existing texture set in there into the post-pass: group_textures_by_set split the folder into N unrelated sets and generated packed/format-converted siblings for materials the user never selected (observed: a 2-set composite produced template output for 9 sets). The composite pass now records every file it writes (written_paths, cleared per batch, including auto-generated normal complements and minus any variant a *_ONLY normal mode pruned), and the post-pass is scoped to that list. Tracking follows optimize_map's return value rather than the pre-optimization path — the optimizer resolves its own output name, so recording the input would leave a tracked path the optimizer had renamed away. apply_output_template(output_dir, files=None) takes an explicit override; it falls back to a directory scan only when the engine has written nothing, so a standalone call on a pre-existing folder still works — and that scan is now a path-only listing over the same extension set, where the old get_images call decoded every texture in the folder (whole 4K sets) just to discard the pixels. The Optimize output toggle was never implicated — _maybe_optimize only ever saw the path it just saved.
2026-07-29 — MathUtils.fit_into_tile + uv_tile_margin + majority_tile: the UDIM-gather and tile-border rules, one copy each.fit_into_tile returns the relative offset that brings a UV bounding box into a target tile — a whole-tile translation preserving the box's sub-tile position (the cheap stand-in for a repack), a minimal pull-in when the box merely straddles the target's border, and a margin-inset clamp for the remainder. A box too big for the inset tile is centered, not edge-anchored: anchoring pushed the common full-coverage shell (UVs spanning 0-1 exactly) off the far border by the whole margin, which the Blender engine test caught. uv_tile_margin names the tile-border rule — half the island gutter, since the border is shared across a seam — replacing the calculate_uv_padding(...)/2 that was open-coded in the packers. Both are map-size-invariant, so a layout built at one resolution stays correct at another. majority_tile completes the set — it decides which tile a gather targets when none is named (each box votes for its bbox-center tile, most votes wins), so the bulk of a layout defines where it lives and only strays travel; it was written twice, once per DCC engine, before being pulled here. Consumers: mayatk/blendertkUvUtils.gather_to_udim, the Shell Xform snap, mayatk._uv_pack.