135 Commits

Author SHA1 Message Date
Brandon Thomas 6ea72da6e5 Merge remote-tracking branch 'origin/main' into upd-172
# Conflicts:
#	ROADMAP.md
2026-11-02 19:25:12 -05:00
bflatastic a21114be26 Merge remote-tracking branch 'origin/main' into masks/more-smart-masks 2026-11-02 22:00:43 +07:00
bflatastic 55e5fcabf7 Merge remote-tracking branch 'origin/main' into materials/more-materials
# Conflicts:
#	ROADMAP.md
2026-11-02 21:48:56 +07:00
BFlat 623c1d5508 Merge pull request #168 from storytold/texturesets/tile-scaled-filters
Filter radii and height slopes follow each UV tile's own resolution
2026-11-02 21:48:33 +07:00
bflatastic 5ea7a91a42 Six more smart masks: snow from top, moss from ground, rust in cavities, edge scratches, dirt streaks, occluded areas
18 -> 24 smart masks, built from the existing mesh-map generators and
triplanar patterns.
2026-11-02 21:48:11 +07:00
bflatastic aa1d9a5f79 Nine more procedural materials: maple, cherry, bamboo, cobblestone, gravel, plaster, linen, wool, moss
63 -> 72 materials. Cobblestone uses rounded cells with sunken joints, gravel
fine Voronoi stones, plaster a soft troweled tooth; linen a coarse weave, wool
and moss a soft sheen.
2026-11-02 21:36:14 +07:00
bflatastic 67a5cb3a09 A light pen tap paints a small dab
A pen lifts reporting no pressure, and a tap paints on that frame, so a tap
painted at full pressure. The release now keeps the pen's contact pressure (a
touch without pressure, such as a finger, starts fresh).

Browsers report pen pressure only for pens that send touch events; desktop
browsers deliver pens as a mouse, so the docs say so.
2026-11-02 21:20:04 +07:00
bflatastic 6dabe66324 Filter radii and height slopes follow each UV tile's own resolution
A UV tile with a lower resolution than its atlas block fills the block's
corner, so it has fewer texels per UV unit. Neighbourhood filters (blur,
sharpen, warps, bevel, glow, ...) and height-to-normal slopes used the block's
texel density for every tile, so such a tile blurred twice as wide and showed
twice as steep slopes in UV space.

TextureSet::block_scales gives each block's share; the compositor filters each
block at its tile's radius, texture export and the CPU path tracer scale the
slope by it, and the display packs it into the Extra texture's alpha for the
viewport and GPU path tracer shaders (parallax too).
2026-11-02 21:08:35 +07:00
bflatastic 099c3b1b5c Pen pressure thins strokes in the 2D view too
The 2D view painted at full pressure whatever the pen reported; it now reads
the same touch force as the 3D view. Docs say where pen pressure works today
(Windows Ink and the browser) and that Linux and macOS pens arrive as a mouse
until the windowing layer reports them.
2026-11-02 20:36:48 +07:00
bflatastic 04af749194 Merge remote-tracking branch 'origin/main' into HEAD
# Conflicts:
#	ROADMAP.md
2026-11-02 19:28:51 +07:00
bflatastic 8dc6e533b7 UV-tiled sets take mesh maps from one image per tile 2026-11-02 18:57:37 +07:00
bflatastic 281b343c22 Merge remote-tracking branch 'origin/main' into export/obj-mtl 2026-11-02 18:46:47 +07:00
bflatastic 92e92ff779 OBJ export writes an MTL material library with each material's maps 2026-11-02 18:20:21 +07:00
bflatastic fe02cd266d Fill normal images can be marked DirectX: their green flips where a normal channel samples them 2026-11-02 17:52:31 +07:00
bflatastic e828af5c35 Document sliders apply live while dragged, as one undo step 2026-11-02 16:28:51 +07:00
BFlat c2c5987bf2 Merge pull request #143 from storytold/fill/uv-transform
Fill projection: UV rotation and offset, sharpness, axis and offset
2026-11-02 16:12:24 +07:00
bflatastic 8657bfdc31 Image fills take a projection's fields without naming it; docs wording
layer.add.image read the projection params only when `projection` was
given, so an offset or rotation alone was dropped. The features list no
longer promises a cylindrical offset.
2026-11-02 15:59:26 +07:00
bflatastic 74383d7625 Merge remote-tracking branch 'origin/main' into fill/uv-transform 2026-11-02 15:01:45 +07:00
bflatastic 19c761f62c Merge remote-tracking branch 'origin/main' into sets/normal-map-format 2026-11-02 14:54:01 +07:00
bflatastic 9faf90c702 Normal map format: fill images keep reading as OpenGL
Flipping every fill image on a normal channel in a DirectX project
would also flip the OpenGL maps MaterialX import puts there, and change
how existing DirectX projects look. Fill images read as before; the
setting covers mesh map images (converted when set, so the tooltip
says to set them again) and the export default.
2026-11-02 14:54:01 +07:00
bflatastic 643a085d8e Fill projection: UV rotation and offset, sharpness, axis and offset
A fill's properties showed only its projection and scale, and
layer.fill.projection rebuilt the projection from its params, so
changing the scale reset a rotation set before and no offset could be
set at all. The command now changes only the fields it is given
(scale, also per axis; rotation; offset; sharpness; axis) and keeps the
rest while the kind stays the same. Properties show the UV rotation and
offset, the tri-planar blend sharpness, and the axis and world offset
of planar and cylindrical projections.
2026-11-02 14:49:14 +07:00
BFlat 19da5379d7 Merge pull request #131 from storytold/feat/cross-app-materials
MaterialCraft materials: .mcmat fills with live graph inputs
2026-11-02 14:36:20 +07:00
bflatastic 62229b41d4 Merge remote-tracking branch 'origin/main' into sets/normal-map-format 2026-11-02 14:30:54 +07:00
BFlat cad425c249 Merge pull request #139 from storytold/settings/data-folder
Settings: a data folder on any drive
2026-11-02 14:30:40 +07:00
bflatastic dd750cb3f6 Normal map format: in Texture Set Settings, and fill images follow it
The project's normal map format (OpenGL or DirectX) could only be set
by command or a template, and fill images on a normal channel were
always read as OpenGL, so a DirectX map's detail came out inverted.
Texture Set Settings now has a Normal map format row, and a fill's
image on a normal channel is read in that format, as mesh map images
already were. A change of format recomposites the sets.
2026-11-02 14:29:38 +07:00
bflatastic d619b53712 Merge origin/main into feat/cross-app-materials
Keeps both import menu items and formats modules (MaterialX import, MaterialCraft materials); menu parity regenerated (55 of 55).
2026-11-02 14:22:37 +07:00
bflatastic ec30388787 Settings: a data folder on any drive
Autosaves, smart materials, brush and export presets, project templates
and UI layouts always went to Documents/TextureCraft, which fills the
system drive. Settings > Folders > Data folder points them anywhere;
the choice applies on restart, and an export folder still at its
default follows it.

Refs #105.
2026-11-02 14:06:51 +07:00
bflatastic 2bf551f2a2 Merge origin/main into feat/cross-app-materials
Keeps both sides of the translation tables, AGENTS rules and the formats module list;
material files in the browser load before the ask-to-save step (they add a layer, not a
new project); Arabic for the eight MaterialCraft strings; menu parity regenerated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 13:45:27 +07:00
bflatastic 6d71d2fc38 Fill channels take an image from their source menu
A fill channel's source menu offered a uniform value, procedurals and
anchors, but no image, so a normal or roughness map could not be put on
its channel. The menu now lists the image resources and Import..., and
an image dropped from the Assets panel onto a channel becomes its
source. The mesh map slots share the same menu and drop target.

Fixes #127.
2026-11-02 13:43:40 +07:00
BFlat d0450eb1ca Merge pull request #75 from SteamSmith/feat/materialx-import
feat(import): MaterialX (.mtlx) material import as a fill layer
2026-11-02 12:44:50 +07:00
bflatastic 88c92dbf71 Merge remote-tracking branch 'origin/main' into HEAD 2026-11-02 12:23:33 +07:00
bflatastic 8c94d053b4 Merge remote-tracking branch 'origin/main' into effects/copy-paste 2026-11-02 12:20:06 +07:00
BFlat e9409b696b Merge pull request #126 from storytold/history/jump-to-step
History: click a step to return to it
2026-11-02 12:19:57 +07:00
bflatastic fbceb95242 Effects: Delete and Ctrl+D act on a selected effect
With an effect selected, Delete removed its whole layer and Ctrl+D
duplicated the layer. Both now act on the effect, like the clipboard
shortcuts; effect commands default to the selected effect.
2026-11-02 12:19:21 +07:00
BFlat 73043fd4b3 Merge pull request #125 from storytold/brush/ctrl-drag
Brush: Ctrl+drag sets size, hardness, flow and angle
2026-11-02 12:14:05 +07:00
bflatastic 4ca9f424f4 Effects: copy, cut and paste between layers
An effect's context menu copies, cuts and pastes it, and Ctrl+C,
Ctrl+X and Ctrl+V act on a selected effect (pasting a copied one above
the selected effect, or on top of the selected content or mask).
Painted strokes come along, resampled to the target set; generators
and other one-stack effects go to their stack, and a fill reading an
anchor point needs one below its new layer. effect.copy, effect.cut
and effect.paste share the layer clipboard.
2026-11-02 12:13:39 +07:00
bflatastic c092e7766b MaterialCraft materials: .mcmat fills with live graph inputs
- core: Fill::link (MaterialLink: package resource, graph, exposed inputs, presets,
  image inputs, size); BakedMap::interop_id / for_input shared mesh-map identifiers
- formats: own .mcmat reader (no MaterialCraft dependency) and 16-bit mesh-map PNGs
- engine: material.load takes .mcmat and .mcraft; material.link.set / .preset / .cook /
  .saveSource; LinkJob re-cooks through materialcraft-cli at the texture set's
  resolution with baked mesh maps as graph inputs; fresh resource names per cook keep
  undo and the decoded-image cache consistent; packages count as used resources
- ui: linked-material section in fill properties (presets, sliders, colors, toggles,
  options) cooking on a worker thread, one process per layer, stale results redone;
  Open in MaterialCraft; File > Import material...; .mcmat drops; library shelf lists
  .mcmat and rescans on focus; 8 new strings in every language
- tests: materialcraft_link (import, params, undo, duplicates, mesh maps, save, and a
  real materialcraft-cli round trip when MATERIALCRAFT_CLI is set)
- docs: README, features, control protocol, architecture, AGENTS, ROADMAP, parity

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-02 12:12:00 +07:00
bflatastic f8f241e804 Merge remote-tracking branch 'origin/main' into history/jump-to-step 2026-11-02 12:00:46 +07:00
BFlat 18b1969712 Merge pull request #122 from storytold/effects/reorder-duplicate
Effects: drag to reorder, duplicate
2026-11-02 12:00:32 +07:00
bflatastic b133186641 History: click a step to return to it
The History panel lists every undone step too (dimmed, next first) and
a click on any step goes back or forward to it, the current one
highlighted. edit.undo and edit.redo take {steps?} for the same jump.
2026-11-02 12:00:09 +07:00
bflatastic 296f439f53 Merge main into feat/materialx-import
# Conflicts:
#	crates/engine/src/lib.rs
2026-11-02 11:58:56 +07:00
bflatastic 410cf3a14f Brush: Ctrl+drag sets size, hardness, flow and angle
Ctrl (Cmd on macOS) + right-drag in the 3D or 2D view changes the
brush size (left/right) and hardness (up/down), Ctrl + left-drag its
flow and angle, instead of orbiting or painting. The brush cursor stays
where the drag began, with the values beside it, and the Brush
properties name the gesture.
2026-11-02 11:48:32 +07:00
bflatastic f6bd07e4d6 Mesh maps: use an image instead of a bake
Each mesh map slot of the Texture Set Settings takes an image resource:
drop one from the Assets panel on the slot, or pick it from the slot's
menu, which also clears the slot. The image is resampled to the size of
the set's other mesh maps (or its bake size), its values read as data,
a normal map in the project's normal format.
textureSet.meshMap.set {ts?, map, image} and
textureSet.meshMap.clear {ts?, map} give agents the same.
2026-11-02 11:32:20 +07:00
bflatastic 74a036540e Merge remote-tracking branch 'origin/main' into pr75
# Conflicts:
#	ROADMAP.md
2026-11-02 11:26:21 +07:00
bflatastic 0d2f1873cd Effects: drag to reorder, duplicate
Effect rows in the layer stack can be dragged within their stack (a
drop lands above the row, or below it from its lower half), and their
context menu duplicates an effect just above itself, painted pixels
included. effect.move {effect, index} and effect.duplicate {effect}
give agents the same.
2026-11-02 11:13:00 +07:00
BFlat b906f41f2e Merge pull request #118 from storytold/filters/histogram-scan-range-shift
Filters: histogram scan, range and shift
2026-11-02 10:38:29 +07:00
BFlat 78e6d7b334 Merge pull request #119 from storytold/materials/ground-and-metals
Materials: platinum, zinc, cobalt, bark, sand, mud, ice, snow and bone
2026-11-02 10:34:38 +07:00
bflatastic 39a2dd9d27 Merge main into filters/histogram-scan-range-shift 2026-11-02 10:27:48 +07:00
BFlat cb1501318f Merge pull request #114 from storytold/levels/histogram
Levels: a histogram of what the effect reads
2026-11-02 10:19:27 +07:00
bflatastic a4cebb790d Merge main into filters/histogram-scan-range-shift 2026-11-02 10:10:15 +07:00