* feat(decal): add local-space triplanar projection to avoid side stretch
Classic planar box decals stretch or cull on faces nearly orthogonal to the
projection axis. Add a triplanar mode that samples YZ/XZ/XY in decal-local
space and blends by |nLocal|^sharpness (UE5-style 三维投射贴花), with API,
editor properties, Vulkan/WGSL shaders, tests, and a corner demo.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(decal): harden triplanar demo and windowed grazing-wall test
Use a procedural grid texture and larger corner volume in the example so
side faces stay inside the box. Replace the flaky headless layer check with
a windowed forward-path assertion (planar culls, triplanar tints red).
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* fix(decal): return DecalProjectionStatus from setProjection
Architecture api-shape rejects new operation bools. Use a named status
enum (Applied / UnknownId / InvalidMode / InvalidSharpness) so callers
can distinguish failure modes without a parallel lastError channel.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* ci(linux): raise cold-build timeouts for PR sccache misses
Linux debug timed out at 40m with a third-party cache miss and
read-only sccache (0 hits). Match the cold-path headroom used on
Windows/ASan so full rebuilds can finish and still run tests.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* ci(asan): raise cold sanitizer build timeout past 100m
PR ASan builds are sccache READ_ONLY and routinely hit the old
100-minute cap near the end of unit_test (94% on run 34820985249).
Allow 140 minutes so linking can finish before tests.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
* ci: re-trigger after ASan runner lost communication
Previous Linux (ASan+UBSan) job died mid-build with a hosted-runner
disconnect (no compile/test failure). Empty commit to retry.
Co-authored-by: 西风逍遥游 <sunxfancy@gmail.com>
---------
Co-authored-by: Cursor Agent <cursoragent@cursor.com>
Windowed gallery test projects blood / dirt / dent decals (procedural splat, noise and concave-normal art) onto a checker floor, reads the frame back and saves build/<plat>/test/out/decal/decal_gallery.png for visual review.
Adds the common-layer IDecalQuery capability (spawn/remove/clear/count/setLimit with an opaque texture handle) provided by the decal module at construction, so editor/devtools can drive decals without linking the module; adds a Squirrel script test (decal.nut + DecalScriptTest) covering eve.Decal() getName/clearAll/setLimit/update, and a C++ capability consumer test.
Completes the PBR surface-parameter layer: mesh3d.frag now blends normal / roughness / metallic / emissive (in addition to albedo) from the DecalLayer before lighting; decals are drawn as grouped instanced draws (112B per-instance SSBO, alpha-over non-premultiplied layer, per-decal uvRect/atlas + channel strengths + blend mode API); DecalManager gains frustum + distance culling and setUvRect/setTextures/setBlend; new headless readback readDecalLayerToImageData validates the pass without a swapchain. Fixes two Vulkan validation violations found by the layer (missing vertex/index binds on instanced draws, blend attachmentCount).