@weft-js/plugin-surface-keel 0.1.0 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +312 -3
- package/package.json +12 -3
- package/src/index.d.ts +5 -1
- package/src/index.mjs +20 -5
- package/src/runtime.mjs +6 -2
- package/vendor/README.md +7 -4
- package/vendor/keel-render/core-primitives.mjs +478 -0
- package/vendor/keel-render/effects-world.mjs +439 -0
- package/vendor/keel-render/indexed-render.mjs +516 -0
- package/vendor/keel-render/pixel-raster.mjs +512 -0
- package/vendor/keel-render/render-passes.mjs +530 -0
- package/vendor/keel-render/renderer-api.mjs +121 -0
- package/vendor/keel-render.mjs +1 -2268
- package/vendor/keel-theme/codec-runtime.mjs +549 -0
- package/vendor/keel-theme/collection-codecs.mjs +360 -0
- package/vendor/keel-theme/color-font.mjs +471 -0
- package/vendor/keel-theme/glyph-theme.mjs +529 -0
- package/vendor/keel-theme/icon-schema.mjs +540 -0
- package/vendor/keel-theme/scalar-codecs.mjs +535 -0
- package/vendor/keel-theme/schema-codec.mjs +515 -0
- package/vendor/keel-theme/schema-theme.mjs +533 -0
- package/vendor/keel-theme.mjs +1 -3571
|
@@ -0,0 +1,530 @@
|
|
|
1
|
+
import './indexed-render.mjs';
|
|
2
|
+
import {
|
|
3
|
+
adaptTargetPalette,
|
|
4
|
+
cameraBasis,
|
|
5
|
+
targetProfile,
|
|
6
|
+
} from './core-primitives.mjs';
|
|
7
|
+
import {
|
|
8
|
+
FULLSCREEN_VS,
|
|
9
|
+
MAX_BOXES,
|
|
10
|
+
MAX_CAPS,
|
|
11
|
+
MAX_COLOURS,
|
|
12
|
+
MAX_MATERIALS,
|
|
13
|
+
MAX_RAMPS,
|
|
14
|
+
MAX_WEDGES,
|
|
15
|
+
PALETTE_WIDTH,
|
|
16
|
+
POINTS_FS,
|
|
17
|
+
POINTS_VS,
|
|
18
|
+
SCREEN_TILE,
|
|
19
|
+
SKY_MAT,
|
|
20
|
+
WORLD_FS,
|
|
21
|
+
resolveFx,
|
|
22
|
+
toggleFxList,
|
|
23
|
+
} from './effects-world.mjs';
|
|
24
|
+
import {
|
|
25
|
+
DEPTH_FS,
|
|
26
|
+
DIRECT_PIXEL_FS,
|
|
27
|
+
PIXEL_FS,
|
|
28
|
+
smoothPixelFs,
|
|
29
|
+
unpackDepth,
|
|
30
|
+
} from './pixel-raster.mjs';
|
|
31
|
+
import {
|
|
32
|
+
RESOLVE_FS,
|
|
33
|
+
createIndexedPass,
|
|
34
|
+
dot2,
|
|
35
|
+
norm3,
|
|
36
|
+
program,
|
|
37
|
+
supersampleFor,
|
|
38
|
+
uploadWorld,
|
|
39
|
+
} from './indexed-render.mjs';
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
function prepareRender(__state, __frame) {
|
|
43
|
+
{ const { world, pixel, points } = __state.colourPrograms(); __frame.world = world; __frame.pixel = pixel; __frame.points = points; }
|
|
44
|
+
__frame.fx = __state.fxDirty || !__state.fxU ? __state.refreshFx() : __state.fxU;
|
|
45
|
+
__frame.timing = false;
|
|
46
|
+
if (__state.timer) {
|
|
47
|
+
if (__state.query && __state.gl.getQueryParameter(__state.query, __state.gl.QUERY_RESULT_AVAILABLE)) {
|
|
48
|
+
if (!__state.gl.getParameter(__state.timer.GPU_DISJOINT_EXT)) __state.gpuMs = __state.gl.getQueryParameter(__state.query, __state.gl.QUERY_RESULT) / 1e6;
|
|
49
|
+
__state.gl.deleteQuery(__state.query);
|
|
50
|
+
__state.query = null;
|
|
51
|
+
}
|
|
52
|
+
if (!__state.query) {
|
|
53
|
+
__state.query = __state.gl.createQuery();
|
|
54
|
+
__state.gl.beginQuery(__state.timer.TIME_ELAPSED_EXT, __state.query);
|
|
55
|
+
__frame.timing = true;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
{ const { forward: fwd, right, up } = cameraBasis(__frame.eye, __frame.look); __frame.fwd = fwd; __frame.right = right; __frame.up = up; }
|
|
59
|
+
__frame.tanF = Math.tan(__frame.fov / 2);
|
|
60
|
+
__frame.sunN = norm3(__frame.sun);
|
|
61
|
+
__frame.k = __state.edges === "smooth" && __state.activeProfile.kind === "native" ? supersampleFor(__state.W2, __state.H, __state.supersample) : 1;
|
|
62
|
+
__frame.F = __frame.k > 1 ? __state.fineBuffers(__frame.k) : null;
|
|
63
|
+
__state.lastK = __frame.k;
|
|
64
|
+
__state.RW = __frame.F ? __frame.F.w : __state.W2;
|
|
65
|
+
__state.RH = __frame.F ? __frame.F.h : __state.H;
|
|
66
|
+
__state.rfbo = __frame.F ? __frame.F.fbo : __state.fbo;
|
|
67
|
+
__state.gl.bindFramebuffer(__state.gl.FRAMEBUFFER, __state.rfbo);
|
|
68
|
+
__state.gl.viewport(0, 0, __state.RW, __state.RH);
|
|
69
|
+
__state.gl.enable(__state.gl.DEPTH_TEST);
|
|
70
|
+
__state.gl.depthFunc(__state.gl.ALWAYS);
|
|
71
|
+
__state.gl.clear(__state.gl.COLOR_BUFFER_BIT | __state.gl.DEPTH_BUFFER_BIT);
|
|
72
|
+
__frame.U = __frame.world.loc;
|
|
73
|
+
__state.gl.useProgram(__frame.world.p);
|
|
74
|
+
__state.gl.uniform2f(__frame.U.uRes, __state.RW, __state.RH);
|
|
75
|
+
__state.gl.uniform3fv(__frame.U.uEye, __frame.eye);
|
|
76
|
+
__state.gl.uniform3fv(__frame.U.uFwd, __frame.fwd);
|
|
77
|
+
__state.gl.uniform3fv(__frame.U.uRight, __frame.right);
|
|
78
|
+
__state.gl.uniform3fv(__frame.U.uUp, __frame.up);
|
|
79
|
+
__state.gl.uniform1f(__frame.U.uTan, __frame.tanF);
|
|
80
|
+
__state.gl.uniform1f(__frame.U.uTime, __frame.time);
|
|
81
|
+
__state.gl.uniform1i(__frame.U.uBoxes, __state.nBoxes);
|
|
82
|
+
__state.gl.uniform1i(__frame.U.uWedges, __state.nWedges);
|
|
83
|
+
__state.gl.uniform1i(__frame.U.uCaps, __state.nCaps);
|
|
84
|
+
for (const blk of __state.blocks) __state.gl.bindBufferBase(__state.gl.UNIFORM_BUFFER, blk.i, blk.buf);
|
|
85
|
+
__state.gl.activeTexture(__state.gl.TEXTURE1);
|
|
86
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, __state.matTex);
|
|
87
|
+
__state.gl.uniform1i(__frame.U.uMats, 1);
|
|
88
|
+
__state.gl.uniform3fv(__frame.U.uSun, __frame.sunN);
|
|
89
|
+
__state.gl.uniform1f(__frame.U.uWaterY, __frame.waterY);
|
|
90
|
+
__state.gl.uniform1f(__frame.U.uFogNear, __frame.fogNear);
|
|
91
|
+
__state.gl.uniform1f(__frame.U.uFogFar, __frame.fogFar);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function drawRender(__state, __frame) {
|
|
95
|
+
if (__frame.raster?.world === false) {
|
|
96
|
+
__state.gl.clearBufferfv(__state.gl.COLOR, 0, [0.5, (__state.matRows[SKY_MAT * 4] ?? 0) / 255, SKY_MAT / 255, 1]);
|
|
97
|
+
__state.gl.clearBufferfv(__state.gl.COLOR, 1, [0, 1, 0, 0]);
|
|
98
|
+
} else {
|
|
99
|
+
__state.gl.bindBuffer(__state.gl.ARRAY_BUFFER, __state.quad);
|
|
100
|
+
const aw = __state.gl.getAttribLocation(__frame.world.p, "aPos");
|
|
101
|
+
__state.gl.enableVertexAttribArray(aw);
|
|
102
|
+
__state.gl.vertexAttribPointer(aw, 2, __state.gl.FLOAT, false, 0, 0);
|
|
103
|
+
__state.gl.drawArrays(__state.gl.TRIANGLES, 0, 3);
|
|
104
|
+
}
|
|
105
|
+
if (__frame.particles.length) {
|
|
106
|
+
__state.gl.depthFunc(__state.gl.LESS);
|
|
107
|
+
const data = new Float32Array(__frame.particles.length * 7);
|
|
108
|
+
__frame.particles.forEach((q, i) => data.set([q.p[0], q.p[1], q.p[2], q.size ?? 1, q.light ?? 0.8, (q.ramp === void 0 ? void 0 : __state.rampIndex.get(q.ramp)) ?? 0, q.glow ?? 0], i * 7));
|
|
109
|
+
__state.gl.useProgram(__frame.points.p);
|
|
110
|
+
const P = __frame.points.loc;
|
|
111
|
+
__state.gl.uniform3fv(P.uEye, __frame.eye);
|
|
112
|
+
__state.gl.uniform3fv(P.uFwd, __frame.fwd);
|
|
113
|
+
__state.gl.uniform3fv(P.uRight, __frame.right);
|
|
114
|
+
__state.gl.uniform3fv(P.uUp, __frame.up);
|
|
115
|
+
__state.gl.uniform1f(P.uTan, __frame.tanF);
|
|
116
|
+
__state.gl.uniform1f(P.uAspect, __state.RW / __state.RH);
|
|
117
|
+
__state.gl.uniform1f(P.uH, __state.RH);
|
|
118
|
+
__state.gl.bindBuffer(__state.gl.ARRAY_BUFFER, __state.pbuf);
|
|
119
|
+
__state.gl.bufferData(__state.gl.ARRAY_BUFFER, data, __state.gl.DYNAMIC_DRAW);
|
|
120
|
+
const a0 = __state.gl.getAttribLocation(__frame.points.p, "aPos");
|
|
121
|
+
const a1 = __state.gl.getAttribLocation(__frame.points.p, "aLook");
|
|
122
|
+
__state.gl.enableVertexAttribArray(a0);
|
|
123
|
+
__state.gl.vertexAttribPointer(a0, 4, __state.gl.FLOAT, false, 28, 0);
|
|
124
|
+
__state.gl.enableVertexAttribArray(a1);
|
|
125
|
+
__state.gl.vertexAttribPointer(a1, 3, __state.gl.FLOAT, false, 28, 16);
|
|
126
|
+
__state.gl.drawArrays(__state.gl.POINTS, 0, __frame.particles.length);
|
|
127
|
+
__state.gl.disableVertexAttribArray(a1);
|
|
128
|
+
}
|
|
129
|
+
if (__frame.raster) __state.drawRaster(__frame.raster, __frame.eye, __frame.fwd, __frame.right, __frame.up, __frame.tanF, __frame.sunN, __frame.waterY, __frame.fogNear, __frame.fogFar, __frame.time);
|
|
130
|
+
__state.gl.disable(__state.gl.DEPTH_TEST);
|
|
131
|
+
__state.gl.bindFramebuffer(__state.gl.FRAMEBUFFER, __frame.F ? __frame.F.colourFbo : null);
|
|
132
|
+
__state.gl.viewport(0, 0, __state.RW, __state.RH);
|
|
133
|
+
__frame.pass2 = __frame.F ? __frame.raster?.draw ? __state.smoothDirectP ??= program(__state.gl, FULLSCREEN_VS, smoothPixelFs(DIRECT_PIXEL_FS)) : __state.smoothPixelP ??= program(__state.gl, FULLSCREEN_VS, smoothPixelFs(PIXEL_FS)) : __frame.raster?.draw ? __state.directPixelP ??= program(__state.gl, FULLSCREEN_VS, DIRECT_PIXEL_FS) : __frame.pixel;
|
|
134
|
+
__state.gl.useProgram(__frame.pass2.p);
|
|
135
|
+
__frame.X = __frame.pass2.loc;
|
|
136
|
+
__frame.T = [[__frame.F ? __frame.F.data : __state.dataTex, "uData"], [__frame.F ? __frame.F.data2 : __state.data2Tex, "uData2"], [__frame.F ? __frame.F.depth : __state.depthTex, "uDepth"], [__state.palTex, "uPalette"], [__state.rampTex, "uRamps"], [__state.screenTex, "uScreenTex"]];
|
|
137
|
+
__frame.T.forEach(([t, name], i) => {
|
|
138
|
+
__state.gl.activeTexture(__state.gl.TEXTURE0 + i);
|
|
139
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, t);
|
|
140
|
+
__state.gl.uniform1i(__frame.X[name], i);
|
|
141
|
+
});
|
|
142
|
+
__frame.u = __frame.fx.u;
|
|
143
|
+
__state.gl.uniform1i(__frame.X.uScreen, __frame.u.uScreen);
|
|
144
|
+
__state.gl.uniform1f(__frame.X.uDither, __frame.u.uDither);
|
|
145
|
+
__state.gl.uniform1f(__frame.X.uTime, __frame.time);
|
|
146
|
+
__state.gl.uniform3fv(__frame.X.uOutline, __frame.u.uOutline);
|
|
147
|
+
__state.gl.uniform1i(__frame.X.uOutlineInk, __frame.u.uOutlineInk);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function composeRender(__state, __frame) {
|
|
151
|
+
__state.gl.uniform4fv(__frame.X.uFog, __frame.u.uFog);
|
|
152
|
+
__state.gl.uniform2fv(__frame.X.uFogLook, __frame.u.uFogLook);
|
|
153
|
+
__state.gl.uniform4fv(__frame.X.uGlow, __frame.u.uGlow);
|
|
154
|
+
__state.gl.uniform2fv(__frame.X.uGlowK, __frame.u.uGlowK);
|
|
155
|
+
__state.gl.uniform4fv(__frame.X.uVig, __frame.u.uVig);
|
|
156
|
+
__state.gl.uniform4fv(__frame.X.uScan, __frame.u.uScan);
|
|
157
|
+
__state.gl.uniform4fv(__frame.X.uCrt, __frame.u.uCrt);
|
|
158
|
+
__state.gl.uniform4fv(__frame.X.uRim, __frame.u.uRim);
|
|
159
|
+
__frame.rd = __frame.u.uRimDir;
|
|
160
|
+
if (!__frame.rd) {
|
|
161
|
+
const sx = dot2(__frame.sunN, __frame.right);
|
|
162
|
+
const sy = dot2(__frame.sunN, __frame.up);
|
|
163
|
+
const l = Math.hypot(sx, sy);
|
|
164
|
+
__frame.rd = l > 1e-3 ? [sx / l, sy / l] : [0, 1];
|
|
165
|
+
}
|
|
166
|
+
__state.gl.uniform2fv(__frame.X.uRimDir, __frame.rd);
|
|
167
|
+
__state.gl.uniform4fv(__frame.X.uFlash, __frame.u.uFlash);
|
|
168
|
+
__state.gl.uniform4iv(__frame.X.uFlashMats, __frame.u.uFlashMats);
|
|
169
|
+
__state.gl.uniform2fv(__frame.X.uGrade, __frame.u.uGrade);
|
|
170
|
+
__state.gl.uniform1i(__frame.X.uCycle, __frame.u.uCycle);
|
|
171
|
+
if (__frame.F) __state.gl.uniform1i(__frame.X.uSS, __frame.k);
|
|
172
|
+
__state.gl.bindBuffer(__state.gl.ARRAY_BUFFER, __state.quad);
|
|
173
|
+
__frame.ap = __state.gl.getAttribLocation(__frame.pass2.p, "aPos");
|
|
174
|
+
__state.gl.enableVertexAttribArray(__frame.ap);
|
|
175
|
+
__state.gl.vertexAttribPointer(__frame.ap, 2, __state.gl.FLOAT, false, 0, 0);
|
|
176
|
+
__state.gl.drawArrays(__state.gl.TRIANGLES, 0, 3);
|
|
177
|
+
if (__frame.F) {
|
|
178
|
+
const rp = __state.resolveP ??= program(__state.gl, FULLSCREEN_VS, RESOLVE_FS);
|
|
179
|
+
__state.gl.bindFramebuffer(__state.gl.FRAMEBUFFER, null);
|
|
180
|
+
__state.gl.viewport(0, 0, __state.W2, __state.H);
|
|
181
|
+
__state.gl.useProgram(rp.p);
|
|
182
|
+
__state.gl.activeTexture(__state.gl.TEXTURE0);
|
|
183
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, __frame.F.colour);
|
|
184
|
+
__state.gl.uniform1i(rp.loc.uColour, 0);
|
|
185
|
+
__state.gl.uniform1i(rp.loc.uSS, __frame.k);
|
|
186
|
+
const ar = __state.gl.getAttribLocation(rp.p, "aPos");
|
|
187
|
+
__state.gl.enableVertexAttribArray(ar);
|
|
188
|
+
__state.gl.vertexAttribPointer(ar, 2, __state.gl.FLOAT, false, 0, 0);
|
|
189
|
+
__state.gl.drawArrays(__state.gl.TRIANGLES, 0, 3);
|
|
190
|
+
}
|
|
191
|
+
if (__frame.depthOut) __state.writeDepthOut(__frame.depthOut);
|
|
192
|
+
if (__frame.timing && __state.timer) __state.gl.endQuery(__state.timer.TIME_ELAPSED_EXT);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function initializeGraphics(__state) {
|
|
196
|
+
__state.ctx = __state.canvas.getContext("webgl2", { antialias: false, preserveDrawingBuffer: true });
|
|
197
|
+
if (!__state.ctx) throw new Error("WebGL2 is not available");
|
|
198
|
+
__state.gl = __state.ctx;
|
|
199
|
+
__state.worldP = null;
|
|
200
|
+
__state.pixelP = null;
|
|
201
|
+
__state.pointsP = null;
|
|
202
|
+
__state.directPixelP = null;
|
|
203
|
+
__state.colourPrograms = () => {
|
|
204
|
+
if (!__state.worldP) {
|
|
205
|
+
const w = program(__state.gl, FULLSCREEN_VS, WORLD_FS);
|
|
206
|
+
if (__state.bakeOnly) ["Boxes", "Wedges", "Capsules"].forEach((name, i) => __state.gl.uniformBlockBinding(w.p, __state.gl.getUniformBlockIndex(w.p, name), i));
|
|
207
|
+
__state.worldP = w;
|
|
208
|
+
__state.pixelP = program(__state.gl, FULLSCREEN_VS, PIXEL_FS);
|
|
209
|
+
__state.pointsP = program(__state.gl, POINTS_VS, POINTS_FS);
|
|
210
|
+
}
|
|
211
|
+
return { world: __state.worldP, pixel: __state.pixelP, points: __state.pointsP };
|
|
212
|
+
};
|
|
213
|
+
if (!__state.bakeOnly) __state.colourPrograms();
|
|
214
|
+
__state.quad = __state.gl.createBuffer();
|
|
215
|
+
__state.gl.bindBuffer(__state.gl.ARRAY_BUFFER, __state.quad);
|
|
216
|
+
__state.gl.bufferData(__state.gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), __state.gl.STATIC_DRAW);
|
|
217
|
+
__state.pbuf = __state.gl.createBuffer();
|
|
218
|
+
__state.nearest = () => {
|
|
219
|
+
for (const [k, v] of [[__state.gl.TEXTURE_MIN_FILTER, __state.gl.NEAREST], [__state.gl.TEXTURE_MAG_FILTER, __state.gl.NEAREST], [__state.gl.TEXTURE_WRAP_S, __state.gl.CLAMP_TO_EDGE], [__state.gl.TEXTURE_WRAP_T, __state.gl.CLAMP_TO_EDGE]]) __state.gl.texParameteri(__state.gl.TEXTURE_2D, k, v);
|
|
220
|
+
};
|
|
221
|
+
__state.floatTex = (w, h, data = null) => {
|
|
222
|
+
const t = __state.gl.createTexture();
|
|
223
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, t);
|
|
224
|
+
__state.gl.texImage2D(__state.gl.TEXTURE_2D, 0, __state.gl.RGBA32F, w, h, 0, __state.gl.RGBA, __state.gl.FLOAT, data);
|
|
225
|
+
__state.nearest();
|
|
226
|
+
return t;
|
|
227
|
+
};
|
|
228
|
+
__state.W2 = __state.width;
|
|
229
|
+
__state.H = __state.height;
|
|
230
|
+
__state.fbo = null;
|
|
231
|
+
__state.dataTex = null;
|
|
232
|
+
__state.data2Tex = null;
|
|
233
|
+
__state.depthTex = null;
|
|
234
|
+
__state.blocks = [["Boxes", 2 * MAX_BOXES], ["Wedges", 3 * MAX_WEDGES], ["Capsules", 2 * MAX_CAPS]].map(([name, vecs], i) => {
|
|
235
|
+
const data = new Float32Array(vecs * 4);
|
|
236
|
+
const buf = __state.gl.createBuffer();
|
|
237
|
+
__state.gl.bindBuffer(__state.gl.UNIFORM_BUFFER, buf);
|
|
238
|
+
__state.gl.bufferData(__state.gl.UNIFORM_BUFFER, data.byteLength, __state.gl.DYNAMIC_DRAW);
|
|
239
|
+
if (__state.worldP) __state.gl.uniformBlockBinding(__state.worldP.p, __state.gl.getUniformBlockIndex(__state.worldP.p, name), i);
|
|
240
|
+
return { data, buf, i };
|
|
241
|
+
});
|
|
242
|
+
{ const [boxBlock, wedgeBlock, capBlock] = __state.blocks; __state.boxBlock = boxBlock; __state.wedgeBlock = wedgeBlock; __state.capBlock = capBlock; }
|
|
243
|
+
__state.rampRows = new Float32Array(MAX_RAMPS * 2 * 4);
|
|
244
|
+
__state.rampTex = __state.floatTex(MAX_RAMPS, 2, __state.rampRows);
|
|
245
|
+
__state.matRows = new Float32Array(256 * 4);
|
|
246
|
+
__state.matTex = __state.floatTex(256, 1, __state.matRows);
|
|
247
|
+
__state.screenTex = __state.gl.createTexture();
|
|
248
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, __state.screenTex);
|
|
249
|
+
__state.gl.texImage2D(__state.gl.TEXTURE_2D, 0, __state.gl.R8, SCREEN_TILE, SCREEN_TILE, 0, __state.gl.RED, __state.gl.UNSIGNED_BYTE, new Uint8Array(SCREEN_TILE * SCREEN_TILE));
|
|
250
|
+
__state.nearest();
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function initializePaletteAndEffects(__state) {
|
|
254
|
+
__state.screenLoaded = null;
|
|
255
|
+
__state.timer = __state.gl.getExtension("EXT_disjoint_timer_query_webgl2");
|
|
256
|
+
__state.query = null;
|
|
257
|
+
__state.gpuMs = null;
|
|
258
|
+
__state.palTex = null;
|
|
259
|
+
__state.palette = [];
|
|
260
|
+
__state.rampIndex = new Map();
|
|
261
|
+
__state.rampList = [];
|
|
262
|
+
__state.nBoxes = 0;
|
|
263
|
+
__state.nWedges = 0;
|
|
264
|
+
__state.nCaps = 0;
|
|
265
|
+
__state.style = { screen: 4, dither: 0.9, outline: 1 };
|
|
266
|
+
__state.activeProfile = targetProfile("native");
|
|
267
|
+
__state.authoredSize = [__state.width, __state.height];
|
|
268
|
+
__state.authoredStyle = { ...__state.style };
|
|
269
|
+
__state.authoredPalette = [];
|
|
270
|
+
__state.authoredRamps = {};
|
|
271
|
+
__state.fxList = [];
|
|
272
|
+
__state.fxResolved = [];
|
|
273
|
+
__state.fxU = null;
|
|
274
|
+
__state.fxDirty = true;
|
|
275
|
+
__state.target(__state.W2, __state.H);
|
|
276
|
+
__state.edges = "smooth";
|
|
277
|
+
__state.supersample = "auto";
|
|
278
|
+
__state.lastK = 1;
|
|
279
|
+
__state.fine = null;
|
|
280
|
+
__state.smoothPixelP = null;
|
|
281
|
+
__state.smoothDirectP = null;
|
|
282
|
+
__state.resolveP = null;
|
|
283
|
+
__state.smoothDepthOutP = null;
|
|
284
|
+
__state.RW = __state.W2;
|
|
285
|
+
__state.RH = __state.H;
|
|
286
|
+
__state.rfbo = null;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
function initializeIndexedBuffers(__state) {
|
|
290
|
+
__state.indexed = createIndexedPass({
|
|
291
|
+
gl: __state.gl,
|
|
292
|
+
quad: __state.quad,
|
|
293
|
+
matTex: __state.matTex,
|
|
294
|
+
blocks: __state.blocks,
|
|
295
|
+
get width() {
|
|
296
|
+
return __state.W2;
|
|
297
|
+
},
|
|
298
|
+
get height() {
|
|
299
|
+
return __state.H;
|
|
300
|
+
},
|
|
301
|
+
get fbo() {
|
|
302
|
+
return __state.fbo;
|
|
303
|
+
},
|
|
304
|
+
get dataTex() {
|
|
305
|
+
return __state.dataTex;
|
|
306
|
+
},
|
|
307
|
+
get data2Tex() {
|
|
308
|
+
return __state.data2Tex;
|
|
309
|
+
},
|
|
310
|
+
get depthTex() {
|
|
311
|
+
return __state.depthTex;
|
|
312
|
+
},
|
|
313
|
+
counts: { get boxes() {
|
|
314
|
+
return __state.nBoxes;
|
|
315
|
+
}, get wedges() {
|
|
316
|
+
return __state.nWedges;
|
|
317
|
+
}, get capsules() {
|
|
318
|
+
return __state.nCaps;
|
|
319
|
+
} }
|
|
320
|
+
}, () => program(__state.gl, FULLSCREEN_VS, DEPTH_FS));
|
|
321
|
+
{ const { mode: bakeMode, pass, readTarget } = __state.indexed; __state.bakeMode = bakeMode; __state.pass = pass; __state.readTarget = readTarget; }
|
|
322
|
+
__state.rasterState = null;
|
|
323
|
+
__state.rasterStats = { meshes: 0, triangles: 0, instances: 0, meshBytes: 0 };
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
function makeSetTarget(__state) {
|
|
327
|
+
return function setTarget(w, h) {
|
|
328
|
+
if (__state.activeProfile.kind === "hardware" && (w !== __state.activeProfile.width || h !== __state.activeProfile.height)) throw new RangeError(`${__state.activeProfile.label} preview requires ${__state.activeProfile.width} \xD7 ${__state.activeProfile.height}`);
|
|
329
|
+
__state.target(Math.max(8, w | 0), Math.max(8, h | 0));
|
|
330
|
+
if (__state.activeProfile.kind === "native") __state.authoredSize = [__state.W2, __state.H];
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
function makeSetProfile(__state) {
|
|
335
|
+
return function setProfile(input) {
|
|
336
|
+
const next = targetProfile(input);
|
|
337
|
+
__state.activeProfile = next;
|
|
338
|
+
if (next.kind === "native") {
|
|
339
|
+
__state.target(__state.authoredSize[0], __state.authoredSize[1]);
|
|
340
|
+
__state.style = { ...__state.authoredStyle };
|
|
341
|
+
} else {
|
|
342
|
+
__state.target(next.width, next.height);
|
|
343
|
+
__state.style = { ...__state.authoredStyle, screen: next.screen, dither: next.dither };
|
|
344
|
+
}
|
|
345
|
+
if (__state.authoredPalette.length) __state.api.setPalette(__state.authoredPalette, __state.authoredRamps);
|
|
346
|
+
__state.fxDirty = true;
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
function makeSetPalette(__state) {
|
|
351
|
+
return function setPalette(colours, ramps) {
|
|
352
|
+
if (colours.length > MAX_COLOURS) throw new RangeError(`${colours.length} colours: at most ${MAX_COLOURS}`);
|
|
353
|
+
const sourceColours = colours.map((c) => [c[0] ?? 0, c[1] ?? 0, c[2] ?? 0]);
|
|
354
|
+
if (__state.activeProfile.kind !== "native") colours = adaptTargetPalette(sourceColours, __state.activeProfile.id);
|
|
355
|
+
__state.palette = colours.map((c) => [c[0] ?? 0, c[1] ?? 0, c[2] ?? 0]);
|
|
356
|
+
const rows = Math.max(1, Math.ceil(colours.length / PALETTE_WIDTH));
|
|
357
|
+
const bytes = new Uint8Array(PALETTE_WIDTH * rows * 4);
|
|
358
|
+
colours.forEach((c, i) => {
|
|
359
|
+
bytes[i * 4] = c[0] ?? 0;
|
|
360
|
+
bytes[i * 4 + 1] = c[1] ?? 0;
|
|
361
|
+
bytes[i * 4 + 2] = c[2] ?? 0;
|
|
362
|
+
bytes[i * 4 + 3] = 255;
|
|
363
|
+
});
|
|
364
|
+
if (__state.palTex) __state.gl.deleteTexture(__state.palTex);
|
|
365
|
+
__state.palTex = __state.gl.createTexture();
|
|
366
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, __state.palTex);
|
|
367
|
+
__state.gl.pixelStorei(__state.gl.UNPACK_ALIGNMENT, 4);
|
|
368
|
+
__state.gl.texImage2D(__state.gl.TEXTURE_2D, 0, __state.gl.RGBA8, PALETTE_WIDTH, rows, 0, __state.gl.RGBA, __state.gl.UNSIGNED_BYTE, bytes);
|
|
369
|
+
__state.nearest();
|
|
370
|
+
const entries = Object.entries(ramps);
|
|
371
|
+
if (entries.length > MAX_RAMPS) throw new RangeError(`${entries.length} ramps: at most ${MAX_RAMPS}`);
|
|
372
|
+
__state.authoredPalette = sourceColours;
|
|
373
|
+
__state.authoredRamps = Object.fromEntries(entries.map(([name, slot]) => [name, [...slot]]));
|
|
374
|
+
__state.rampIndex = /* @__PURE__ */ new Map();
|
|
375
|
+
__state.rampList = entries.map(([name, [base, len2]], i) => {
|
|
376
|
+
__state.rampIndex.set(name, i);
|
|
377
|
+
return [base, len2];
|
|
378
|
+
});
|
|
379
|
+
__state.fxDirty = true;
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
function makeSetMaterials(__state) {
|
|
384
|
+
return function setMaterials(list) {
|
|
385
|
+
if (list.length > MAX_MATERIALS) throw new RangeError(`${list.length} materials: at most ${MAX_MATERIALS}`);
|
|
386
|
+
__state.matRows.fill(0);
|
|
387
|
+
list.forEach((m, i) => {
|
|
388
|
+
__state.matRows.set([__state.rampIndex.get(m.ramp) ?? 0, m.light ?? 1, m.pattern ?? 0, m.glow ?? 0], i * 4);
|
|
389
|
+
});
|
|
390
|
+
__state.gl.bindTexture(__state.gl.TEXTURE_2D, __state.matTex);
|
|
391
|
+
__state.gl.texSubImage2D(__state.gl.TEXTURE_2D, 0, 0, 0, 256, 1, __state.gl.RGBA, __state.gl.FLOAT, __state.matRows);
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
function makeSetStyle(__state) {
|
|
396
|
+
return function setStyle({ screen: s = __state.style.screen, dither: d = __state.style.dither, outline: o = __state.style.outline, edges: e = __state.edges, supersample: k = __state.supersample } = {}) {
|
|
397
|
+
__state.style = { screen: s, dither: d, outline: o ? 1 : 0 };
|
|
398
|
+
__state.edges = e;
|
|
399
|
+
__state.supersample = k;
|
|
400
|
+
__state.authoredStyle = { ...__state.style };
|
|
401
|
+
__state.fxDirty = true;
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
function makeSetWorld(__state) {
|
|
406
|
+
return function setWorld(world) {
|
|
407
|
+
const counts = uploadWorld(__state.gl, __state.blocks, world);
|
|
408
|
+
__state.nBoxes = counts.boxes;
|
|
409
|
+
__state.nWedges = counts.wedges;
|
|
410
|
+
__state.nCaps = counts.capsules;
|
|
411
|
+
return counts;
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function makeSetFx(__state) {
|
|
416
|
+
return function setFx(list = []) {
|
|
417
|
+
__state.fxList = list.map((e) => ({ ...e }));
|
|
418
|
+
resolveFx(__state.fxList, { width: __state.W2, height: __state.H });
|
|
419
|
+
__state.fxDirty = true;
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
function makeToggleFx(__state) {
|
|
424
|
+
return function toggleFx(name, on) {
|
|
425
|
+
__state.fxList = toggleFxList(__state.fxList, name, on);
|
|
426
|
+
__state.fxDirty = true;
|
|
427
|
+
};
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
function makeRender(__state) {
|
|
431
|
+
return function render({ eye, target: look, fov = 1.2, time = 0, sun = [0.4, 0.8, 0.3], waterY = 0, fogNear = 25, fogFar = 110, particles = [], raster, depthOut }) {
|
|
432
|
+
const __frame = { eye, look, fov, time, sun, waterY, fogNear, fogFar, particles, raster, depthOut };
|
|
433
|
+
prepareRender(__state, __frame);
|
|
434
|
+
drawRender(__state, __frame);
|
|
435
|
+
composeRender(__state, __frame);
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
function makeRead(__state) {
|
|
440
|
+
return function read() {
|
|
441
|
+
const out = new Uint8Array(__state.W2 * __state.H * 4);
|
|
442
|
+
__state.gl.readPixels(0, 0, __state.W2, __state.H, __state.gl.RGBA, __state.gl.UNSIGNED_BYTE, out);
|
|
443
|
+
return out;
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
function makeReadData(__state) {
|
|
448
|
+
return function readData() {
|
|
449
|
+
const x = __state.bakeMode();
|
|
450
|
+
const data = __state.readTarget(__state.fbo, __state.gl.COLOR_ATTACHMENT0);
|
|
451
|
+
const data2 = __state.readTarget(__state.fbo, __state.gl.COLOR_ATTACHMENT1);
|
|
452
|
+
__state.gl.disable(__state.gl.DEPTH_TEST);
|
|
453
|
+
__state.pass(x.depth.p, x.fb, [[__state.depthTex, x.depth.loc.uDepth]]);
|
|
454
|
+
const packed = __state.readTarget(x.fb, __state.gl.COLOR_ATTACHMENT0);
|
|
455
|
+
const depth = new Float32Array(__state.W2 * __state.H);
|
|
456
|
+
for (let i = 0; i < depth.length; i += 1) depth[i] = unpackDepth(packed[i * 4], packed[i * 4 + 1], packed[i * 4 + 2]);
|
|
457
|
+
return { width: __state.W2, height: __state.H, data, data2, depth };
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
function makeSetMesh(__state) {
|
|
462
|
+
return function setMesh(key2, mesh) {
|
|
463
|
+
const R = __state.rasterMode();
|
|
464
|
+
const old = R.meshes.get(key2);
|
|
465
|
+
if (old) {
|
|
466
|
+
for (const b of old.bufs) __state.gl.deleteBuffer(b);
|
|
467
|
+
__state.gl.deleteVertexArray(old.vao);
|
|
468
|
+
R.meshes.delete(key2);
|
|
469
|
+
__state.rasterStats.meshBytes -= old.bytes;
|
|
470
|
+
}
|
|
471
|
+
if (!mesh) return;
|
|
472
|
+
const vao = __state.gl.createVertexArray();
|
|
473
|
+
__state.gl.bindVertexArray(vao);
|
|
474
|
+
const bufs = [];
|
|
475
|
+
const attr = (loc, data, size) => {
|
|
476
|
+
const b = __state.gl.createBuffer();
|
|
477
|
+
bufs.push(b);
|
|
478
|
+
__state.gl.bindBuffer(__state.gl.ARRAY_BUFFER, b);
|
|
479
|
+
__state.gl.bufferData(__state.gl.ARRAY_BUFFER, data, __state.gl.STATIC_DRAW);
|
|
480
|
+
__state.gl.enableVertexAttribArray(loc);
|
|
481
|
+
__state.gl.vertexAttribPointer(loc, size, __state.gl.FLOAT, false, 0, 0);
|
|
482
|
+
};
|
|
483
|
+
attr(0, mesh.positions, 3);
|
|
484
|
+
attr(1, mesh.normals, 3);
|
|
485
|
+
attr(2, mesh.looks, 4);
|
|
486
|
+
for (let k = 3; k < 6; k += 1) {
|
|
487
|
+
__state.gl.disableVertexAttribArray(k);
|
|
488
|
+
__state.gl.vertexAttrib4f(k, 0, 0, 0, 0);
|
|
489
|
+
}
|
|
490
|
+
let bytes = mesh.positions.byteLength + mesh.normals.byteLength + mesh.looks.byteLength;
|
|
491
|
+
if (mesh.indices) {
|
|
492
|
+
const b = __state.gl.createBuffer();
|
|
493
|
+
bufs.push(b);
|
|
494
|
+
__state.gl.bindBuffer(__state.gl.ELEMENT_ARRAY_BUFFER, b);
|
|
495
|
+
__state.gl.bufferData(__state.gl.ELEMENT_ARRAY_BUFFER, mesh.indices, __state.gl.STATIC_DRAW);
|
|
496
|
+
bytes += mesh.indices.byteLength;
|
|
497
|
+
}
|
|
498
|
+
__state.gl.bindVertexArray(null);
|
|
499
|
+
R.meshes.set(key2, { vao, bufs, count: mesh.indices ? mesh.indices.length : mesh.positions.length / 3, indexed: !!mesh.indices, bytes });
|
|
500
|
+
__state.rasterStats.meshBytes += bytes;
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function makeOffPalette(__state) {
|
|
505
|
+
return function offPalette(pixels = __state.api.read()) {
|
|
506
|
+
const set = new Set(__state.palette.map((c) => c[0] << 16 | c[1] << 8 | c[2]));
|
|
507
|
+
let off = 0;
|
|
508
|
+
for (let i = 0; i < pixels.length; i += 4) if (!set.has((pixels[i] ?? 0) << 16 | (pixels[i + 1] ?? 0) << 8 | (pixels[i + 2] ?? 0))) off += 1;
|
|
509
|
+
return off;
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
export {
|
|
514
|
+
initializeGraphics,
|
|
515
|
+
initializeIndexedBuffers,
|
|
516
|
+
initializePaletteAndEffects,
|
|
517
|
+
makeOffPalette,
|
|
518
|
+
makeRead,
|
|
519
|
+
makeReadData,
|
|
520
|
+
makeRender,
|
|
521
|
+
makeSetFx,
|
|
522
|
+
makeSetMaterials,
|
|
523
|
+
makeSetMesh,
|
|
524
|
+
makeSetPalette,
|
|
525
|
+
makeSetProfile,
|
|
526
|
+
makeSetStyle,
|
|
527
|
+
makeSetTarget,
|
|
528
|
+
makeSetWorld,
|
|
529
|
+
makeToggleFx,
|
|
530
|
+
};
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import './render-passes.mjs';
|
|
2
|
+
import {
|
|
3
|
+
ALL_FX,
|
|
4
|
+
MAX_BOXES,
|
|
5
|
+
MAX_CAPS,
|
|
6
|
+
MAX_COLOURS,
|
|
7
|
+
MAX_MATERIALS,
|
|
8
|
+
MAX_RAMPS,
|
|
9
|
+
MAX_WEDGES,
|
|
10
|
+
} from './effects-world.mjs';
|
|
11
|
+
import {
|
|
12
|
+
drawRasterImpl,
|
|
13
|
+
fineBuffersImpl,
|
|
14
|
+
rasterModeImpl,
|
|
15
|
+
refreshFxImpl,
|
|
16
|
+
targetImpl,
|
|
17
|
+
uploadRampsImpl,
|
|
18
|
+
writeDepthOutImpl,
|
|
19
|
+
} from './indexed-render.mjs';
|
|
20
|
+
import {
|
|
21
|
+
initializeGraphics,
|
|
22
|
+
initializeIndexedBuffers,
|
|
23
|
+
initializePaletteAndEffects,
|
|
24
|
+
makeOffPalette,
|
|
25
|
+
makeRead,
|
|
26
|
+
makeReadData,
|
|
27
|
+
makeRender,
|
|
28
|
+
makeSetFx,
|
|
29
|
+
makeSetMaterials,
|
|
30
|
+
makeSetMesh,
|
|
31
|
+
makeSetPalette,
|
|
32
|
+
makeSetProfile,
|
|
33
|
+
makeSetStyle,
|
|
34
|
+
makeSetTarget,
|
|
35
|
+
makeSetWorld,
|
|
36
|
+
makeToggleFx,
|
|
37
|
+
} from './render-passes.mjs';
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
function createRendererApi(__state) {
|
|
41
|
+
return {
|
|
42
|
+
gl: __state.gl,
|
|
43
|
+
get width() {
|
|
44
|
+
return __state.W2;
|
|
45
|
+
},
|
|
46
|
+
get height() {
|
|
47
|
+
return __state.H;
|
|
48
|
+
},
|
|
49
|
+
limits: {
|
|
50
|
+
boxes: MAX_BOXES,
|
|
51
|
+
wedges: MAX_WEDGES,
|
|
52
|
+
capsules: MAX_CAPS,
|
|
53
|
+
ramps: MAX_RAMPS,
|
|
54
|
+
materials: MAX_MATERIALS,
|
|
55
|
+
colours: MAX_COLOURS,
|
|
56
|
+
fragmentUniformVectors: __state.gl.getParameter(__state.gl.MAX_FRAGMENT_UNIFORM_VECTORS),
|
|
57
|
+
maxTexture: __state.gl.getParameter(__state.gl.MAX_TEXTURE_SIZE)
|
|
58
|
+
},
|
|
59
|
+
setTarget: makeSetTarget(__state),
|
|
60
|
+
get profile() {
|
|
61
|
+
return __state.activeProfile;
|
|
62
|
+
},
|
|
63
|
+
setProfile: makeSetProfile(__state),
|
|
64
|
+
setPalette: makeSetPalette(__state),
|
|
65
|
+
get palette() {
|
|
66
|
+
return __state.palette;
|
|
67
|
+
},
|
|
68
|
+
ramp: (name) => __state.rampIndex.get(name) ?? 0,
|
|
69
|
+
setMaterials: makeSetMaterials(__state),
|
|
70
|
+
setStyle: makeSetStyle(__state),
|
|
71
|
+
setWorld: makeSetWorld(__state),
|
|
72
|
+
setFx: makeSetFx(__state),
|
|
73
|
+
toggleFx: makeToggleFx(__state),
|
|
74
|
+
get fx() {
|
|
75
|
+
return __state.fxList.map((e) => ({ ...e }));
|
|
76
|
+
},
|
|
77
|
+
get fxResolved() {
|
|
78
|
+
if (__state.fxDirty) __state.refreshFx();
|
|
79
|
+
return __state.fxResolved;
|
|
80
|
+
},
|
|
81
|
+
allFx: ALL_FX,
|
|
82
|
+
get gpuMs() {
|
|
83
|
+
return __state.gpuMs;
|
|
84
|
+
},
|
|
85
|
+
get supersample() {
|
|
86
|
+
return __state.lastK;
|
|
87
|
+
},
|
|
88
|
+
render: makeRender(__state),
|
|
89
|
+
read: makeRead(__state),
|
|
90
|
+
readData: makeReadData(__state),
|
|
91
|
+
renderIndexed: __state.indexed.renderIndexed,
|
|
92
|
+
readIndexed: __state.indexed.readIndexed,
|
|
93
|
+
renderIndexedHeights: __state.indexed.renderIndexedHeights,
|
|
94
|
+
setMesh: makeSetMesh(__state),
|
|
95
|
+
get rasterStats() {
|
|
96
|
+
return { ...__state.rasterStats };
|
|
97
|
+
},
|
|
98
|
+
offPalette: makeOffPalette(__state),
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
function createPixelRenderer(canvas, { width = 128, height = 128, bakeOnly = false, profile: profile2 } = {}) {
|
|
103
|
+
const __state = { canvas, width, height, bakeOnly, profile2 };
|
|
104
|
+
__state.target = (...args) => targetImpl(__state, ...args);
|
|
105
|
+
__state.uploadRamps = (...args) => uploadRampsImpl(__state, ...args);
|
|
106
|
+
__state.refreshFx = (...args) => refreshFxImpl(__state, ...args);
|
|
107
|
+
__state.fineBuffers = (...args) => fineBuffersImpl(__state, ...args);
|
|
108
|
+
__state.rasterMode = (...args) => rasterModeImpl(__state, ...args);
|
|
109
|
+
__state.drawRaster = (...args) => drawRasterImpl(__state, ...args);
|
|
110
|
+
__state.writeDepthOut = (...args) => writeDepthOutImpl(__state, ...args);
|
|
111
|
+
initializeGraphics(__state);
|
|
112
|
+
initializePaletteAndEffects(__state);
|
|
113
|
+
initializeIndexedBuffers(__state);
|
|
114
|
+
__state.api = createRendererApi(__state);
|
|
115
|
+
if (profile2 !== void 0) __state.api.setProfile(profile2);
|
|
116
|
+
return __state.api;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export {
|
|
120
|
+
createPixelRenderer,
|
|
121
|
+
};
|