Skip to content

Commit 96c4d9a

Browse files
obiotclaude
andauthored
feat(shader): screen_texture / screen_uv / noise_uv builtins + {vertex, fragment} shader assets (+ Water Overworld example) (#1548)
* feat(shader): Godot-style builtins — screen_texture / screen_uv / noise_uv Inside a ShaderEffect fragment body (design contributed by the melonJS editor team, mirroring Godot's hint_screen_texture / SCREEN_UV): - `uniform sampler2D name : screen_texture;` — annotation parsed and stripped; the sampler is auto-wired to the renderer's shared toFrameTexture capture (live GPU-resident entry) and the engine refreshes the capture right before the effect draws: in drawImage's customShader block (scene behind the sprite) and in endPostEffect (camera FBO = the scene for camera chains, parent target for renderable chains). True BackBufferCopy semantics on every path. Optional `(repeat)` wrap honored under WebGL 2 (captures are NPOT). - `screen_uv` — free varying, clip→0..1 screen position, computed in a deterministically-templated vertex variant (user source never regex- rewritten). - `noise_uv` — free varying, frame-local 0..1 across the drawn object (undoes atlas packing, scaled to object pixels); fed per draw through the new @ignore ShaderEffect._setNoiseUVRect from the quad batchers' single-texture path and both blitTextures. Back-compat: annotation was never valid GLSL; varyings activate only when referenced and never when the body declares them itself; a body using no builtins compiles byte-identical to before. New renderer helper getSharedFrameTexture() gives the shared capture slot a stable identity from effect-construction time. 8 new tests (shadereffect-builtins.spec.js): parse/wiring/introspection, true screen sampling + orientation via two-tone backdrop + swizzle readback, frame-local noise_uv on an atlas sub-frame (both axes), no-capture-without-annotation (spy), clone, self-declared back-compat. Full suite 4810 passed | 15 skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * feat(examples): Water Overworld — the editor team's demo scene, ported 1:1 Side-scroller overworld (GandalfHardcore free 32x32 pack) with the water-refraction shader from the contributed build, verbatim: two cellular NoiseTexture2d flow maps + screenTex : screen_texture + screen_uv mirror + noise_uv flow — the canonical showcase of the new shader builtins. TMX level, atlas strip-sliced animated props (campfire, portal, cooking area), drifting clouds, playable character (A/D walk, W jump, Shift run — their controller plugin replaced by ~25 lines of plain melonJS input/body code with the same tuning). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * fix(examples): waterOverworld parity with the reference build - water sprite uses the two regions verbatim (their settings semantics) instead of getAnimationSettings, whose bottom-align trim mis-placed the frame and bled the adjacent cloud5 atlas pixels (the white artifact on the left edge); the 2dWater art carries its own transparent sky band, matching the original placement - clouds drift right and respawn off the left edge (ported from the demo's update user-code: speed 1+random, wrap at x 1040) - handle video.init() returning false (CodeRabbit finding), alongside the existing thrown-error path Verified side-by-side against the zip's build served statically — scene, water surface line, reflection and drift now match; CodeRabbit re-review clean (0 findings). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * feat(examples): waterOverworld — debug panel + arrow-key controls - register @melonjs/debug-plugin (press "S" to toggle), like the other examples and the original demo build - arrow keys as movement aliases: ←/→ walk, ↑ jump (alongside A/D/W) - controls hint updated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * test(shader): cover both endPostEffect screen-capture paths The camera chain (capture from the still-bound camera FBO = the scene, orientation preserved, exactly one toFrameTexture call) and the multi-effect renderable chain (capture = the parent target behind the object, not the object's own rendering) were the only untested branches of the builtins feature — the example and prior tests only exercised the sprite/customShader path. 10 tests total now. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * feat(loader): {vertex, fragment} shader-asset pairs compile into raw GLShaders A shader asset can now be a complete program pair — src: {vertex, fragment} URLs (fetched in parallel) or inline via data: — compiled at load time into a shared raw GLShader, returned by the same loader.getShader(). This is the honest type for full programs (Mesh custom shaders, renderer.customShader, custom batchers) and sidesteps ShaderEffect's apply() wrapping entirely: no source rewriting, no builtins injection — the user owns both stages. Same shared/clone/ unload lifecycle as fragment-body assets; WebGL-only (a pair loads as null under Canvas, with a warning — no canvas analog for a raw program; unload guards the null entry). 6 adversarial tests (shader-loader.spec.js), mutation-verified: drop shared flag / swap vertex-fragment stages / remove the already-loaded guard each kill exactly their matching test. Full suite 4818 | 15 skipped. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * docs(changelog): note the {vertex, fragment} shader-asset pair form Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A * docs: drop third-party engine references from comments, docs, changelog The builtins stand on their own names — comparisons to other engines' equivalents removed from JSDoc, module comments, spec headers, the example, and the 19.9.0 changelog entries (generic "back-buffer copy" terminology kept where technically descriptive). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019t8kP8vp58ZrvaD2FqJU6A --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
1 parent 69b578a commit 96c4d9a

19 files changed

Lines changed: 3058 additions & 31 deletions

File tree

33.7 KB
Loading
315 KB
Loading
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
{"frames": [
2+
3+
{
4+
"filename": "2dWater",
5+
"frame": {"x":743,"y":387,"w":480,"h":480},
6+
"rotated": false,
7+
"trimmed": false,
8+
"spriteSourceSize": {"x":0,"y":0,"w":480,"h":480},
9+
"sourceSize": {"w":480,"h":480},
10+
"pivot": {"x":0.5,"y":0.5}
11+
},
12+
{
13+
"filename": "Angel Statue",
14+
"frame": {"x":1983,"y":1,"w":64,"h":64},
15+
"rotated": false,
16+
"trimmed": false,
17+
"spriteSourceSize": {"x":0,"y":0,"w":64,"h":64},
18+
"sourceSize": {"w":64,"h":64},
19+
"pivot": {"x":0.5,"y":0.5}
20+
},
21+
{
22+
"filename": "Birch1",
23+
"frame": {"x":1627,"y":663,"w":80,"h":112},
24+
"rotated": false,
25+
"trimmed": false,
26+
"spriteSourceSize": {"x":0,"y":0,"w":80,"h":112},
27+
"sourceSize": {"w":80,"h":112},
28+
"pivot": {"x":0.5,"y":0.5}
29+
},
30+
{
31+
"filename": "Campfire with food sheet",
32+
"frame": {"x":1627,"y":405,"w":160,"h":256},
33+
"rotated": false,
34+
"trimmed": false,
35+
"spriteSourceSize": {"x":0,"y":0,"w":160,"h":256},
36+
"sourceSize": {"w":160,"h":256},
37+
"pivot": {"x":0.5,"y":0.5}
38+
},
39+
{
40+
"filename": "cloud5",
41+
"frame": {"x":743,"y":349,"w":110,"h":35},
42+
"rotated": false,
43+
"trimmed": false,
44+
"spriteSourceSize": {"x":0,"y":0,"w":110,"h":35},
45+
"sourceSize": {"w":110,"h":35},
46+
"pivot": {"x":0.5,"y":0.5}
47+
},
48+
{
49+
"filename": "Cooking area",
50+
"frame": {"x":803,"y":935,"w":768,"h":64},
51+
"rotated": false,
52+
"trimmed": false,
53+
"spriteSourceSize": {"x":0,"y":0,"w":768,"h":64},
54+
"sourceSize": {"w":768,"h":64},
55+
"pivot": {"x":0.5,"y":0.5}
56+
},
57+
{
58+
"filename": "GandalfHardcore Background layers",
59+
"frame": {"x":1,"y":1,"w":1024,"h":346},
60+
"rotated": false,
61+
"trimmed": false,
62+
"spriteSourceSize": {"x":0,"y":0,"w":1024,"h":346},
63+
"sourceSize": {"w":1024,"h":346},
64+
"pivot": {"x":0.5,"y":0.5}
65+
},
66+
{
67+
"filename": "GandalfHardcore Portal sheet",
68+
"frame": {"x":1225,"y":789,"w":640,"h":64},
69+
"rotated": false,
70+
"trimmed": false,
71+
"spriteSourceSize": {"x":0,"y":0,"w":640,"h":64},
72+
"sourceSize": {"w":640,"h":64},
73+
"pivot": {"x":0.5,"y":0.5}
74+
},
75+
{
76+
"filename": "HP bar preview",
77+
"frame": {"x":1027,"y":1,"w":696,"h":384},
78+
"rotated": false,
79+
"trimmed": false,
80+
"spriteSourceSize": {"x":0,"y":0,"w":696,"h":384},
81+
"sourceSize": {"w":696,"h":384},
82+
"pivot": {"x":0.5,"y":0.5}
83+
},
84+
{
85+
"filename": "male_idle",
86+
"frame": {"x":1,"y":874,"w":800,"h":64},
87+
"rotated": false,
88+
"trimmed": false,
89+
"spriteSourceSize": {"x":0,"y":0,"w":800,"h":64},
90+
"sourceSize": {"w":800,"h":64},
91+
"pivot": {"x":0.5,"y":0.5}
92+
},
93+
{
94+
"filename": "male_run",
95+
"frame": {"x":1,"y":940,"w":800,"h":64},
96+
"rotated": false,
97+
"trimmed": false,
98+
"spriteSourceSize": {"x":0,"y":0,"w":800,"h":64},
99+
"sourceSize": {"w":800,"h":64},
100+
"pivot": {"x":0.5,"y":0.5}
101+
},
102+
{
103+
"filename": "male_walk",
104+
"frame": {"x":803,"y":869,"w":800,"h":64},
105+
"rotated": false,
106+
"trimmed": false,
107+
"spriteSourceSize": {"x":0,"y":0,"w":800,"h":64},
108+
"sourceSize": {"w":800,"h":64},
109+
"pivot": {"x":0.5,"y":0.5}
110+
},
111+
{
112+
"filename": "sun",
113+
"frame": {"x":1789,"y":405,"w":32,"h":32},
114+
"rotated": false,
115+
"trimmed": false,
116+
"spriteSourceSize": {"x":0,"y":0,"w":32,"h":32},
117+
"sourceSize": {"w":32,"h":32},
118+
"pivot": {"x":0.5,"y":0.5}
119+
},
120+
{
121+
"filename": "TilesAssets",
122+
"frame": {"x":1225,"y":387,"w":400,"h":400},
123+
"rotated": false,
124+
"trimmed": false,
125+
"spriteSourceSize": {"x":0,"y":0,"w":400,"h":400},
126+
"sourceSize": {"w":400,"h":400},
127+
"pivot": {"x":0.5,"y":0.5}
128+
},
129+
{
130+
"filename": "Tree2",
131+
"frame": {"x":1725,"y":1,"w":256,"h":208},
132+
"rotated": false,
133+
"trimmed": false,
134+
"spriteSourceSize": {"x":0,"y":0,"w":256,"h":208},
135+
"sourceSize": {"w":256,"h":208},
136+
"pivot": {"x":0.5,"y":0.5}
137+
},
138+
{
139+
"filename": "water2ds",
140+
"frame": {"x":1,"y":349,"w":740,"h":523},
141+
"rotated": false,
142+
"trimmed": false,
143+
"spriteSourceSize": {"x":0,"y":0,"w":740,"h":523},
144+
"sourceSize": {"w":740,"h":523},
145+
"pivot": {"x":0.5,"y":0.5}
146+
},
147+
{
148+
"filename": "Weeping Willow1",
149+
"frame": {"x":1725,"y":211,"w":224,"h":192},
150+
"rotated": false,
151+
"trimmed": false,
152+
"spriteSourceSize": {"x":0,"y":0,"w":224,"h":192},
153+
"sourceSize": {"w":224,"h":192},
154+
"pivot": {"x":0.5,"y":0.5}
155+
}],
156+
"meta": {
157+
"app": "https://www.codeandweb.com/texturepacker",
158+
"version": "1.0",
159+
"image": "texture_image_0.webp",
160+
"format": "RGBA8888",
161+
"size": {"w":2048,"h":1024},
162+
"scale": "1",
163+
"smartupdate": "$TexturePacker:SmartUpdate:100c99bc6065c58490c69f6f368c4ee3:6e253f253e708684eaeaa46c77137f6f:c6b1571f4a98eab5c8284aa57b587db1$"
164+
}
165+
}

0 commit comments

Comments
 (0)