Skip to content

pythontk v0.8.98

Latest

Choose a tag to compare

@m3trik m3trik released this 29 Jul 18:57
  • 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/blendertk UvUtils.gather_to_udim, the Shell Xform snap, mayatk._uv_pack.