nova64 0.2.6 → 0.2.7
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/dist/examples/strider-demo-3d/fix-game.sh +0 -0
- package/dist/runtime/api-2d.js +1158 -0
- package/dist/runtime/api-3d/camera.js +73 -0
- package/dist/runtime/api-3d/instancing.js +180 -0
- package/dist/runtime/api-3d/lights.js +51 -0
- package/dist/runtime/api-3d/materials.js +47 -0
- package/dist/runtime/api-3d/models.js +84 -0
- package/dist/runtime/api-3d/particles.js +296 -0
- package/dist/runtime/api-3d/pbr.js +113 -0
- package/dist/runtime/api-3d/primitives.js +304 -0
- package/dist/runtime/api-3d/scene.js +169 -0
- package/dist/runtime/api-3d/transforms.js +161 -0
- package/dist/runtime/api-3d.js +166 -0
- package/dist/runtime/api-effects.js +840 -0
- package/dist/runtime/api-gameutils.js +476 -0
- package/dist/runtime/api-generative.js +610 -0
- package/dist/runtime/api-presets.js +85 -0
- package/dist/runtime/api-skybox.js +232 -0
- package/dist/runtime/api-sprites.js +100 -0
- package/dist/runtime/api-voxel.js +712 -0
- package/dist/runtime/api.js +201 -0
- package/dist/runtime/assets.js +27 -0
- package/dist/runtime/audio.js +114 -0
- package/dist/runtime/collision.js +47 -0
- package/dist/runtime/console.js +101 -0
- package/dist/runtime/editor.js +233 -0
- package/dist/runtime/font.js +233 -0
- package/dist/runtime/framebuffer.js +28 -0
- package/dist/runtime/fullscreen-button.js +185 -0
- package/dist/runtime/gpu-canvas2d.js +47 -0
- package/dist/runtime/gpu-threejs.js +643 -0
- package/dist/runtime/gpu-webgl2.js +310 -0
- package/dist/runtime/index.d.ts +682 -0
- package/dist/runtime/index.js +22 -0
- package/dist/runtime/input.js +225 -0
- package/dist/runtime/logger.js +60 -0
- package/dist/runtime/physics.js +101 -0
- package/dist/runtime/screens.js +213 -0
- package/dist/runtime/storage.js +38 -0
- package/dist/runtime/store.js +151 -0
- package/dist/runtime/textinput.js +68 -0
- package/dist/runtime/ui/buttons.js +124 -0
- package/dist/runtime/ui/panels.js +105 -0
- package/dist/runtime/ui/text.js +86 -0
- package/dist/runtime/ui/widgets.js +141 -0
- package/dist/runtime/ui.js +111 -0
- package/package.json +34 -32
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
// runtime/gpu-webgl2.js
|
|
2
|
+
// WebGL2 backend with RGBA16F upload + tone mapping and a simple sprite renderer.
|
|
3
|
+
import { Framebuffer64 } from './framebuffer.js';
|
|
4
|
+
|
|
5
|
+
const VERT_FSQ = `#version 300 es
|
|
6
|
+
precision highp float;
|
|
7
|
+
layout(location=0) in vec2 a_pos;
|
|
8
|
+
out vec2 v_uv;
|
|
9
|
+
void main() {
|
|
10
|
+
v_uv = 0.5 * (a_pos + 1.0);
|
|
11
|
+
gl_Position = vec4(a_pos, 0.0, 1.0);
|
|
12
|
+
}`;
|
|
13
|
+
|
|
14
|
+
const FRAG_TONEMAP = `#version 300 es
|
|
15
|
+
precision highp float;
|
|
16
|
+
in vec2 v_uv;
|
|
17
|
+
out vec4 o_col;
|
|
18
|
+
uniform sampler2D u_tex;
|
|
19
|
+
// Simple ACES-like tonemapper (approx) then gamma to sRGB.
|
|
20
|
+
vec3 tonemapACES( vec3 x ) {
|
|
21
|
+
float a = 2.51, b = 0.03, c = 2.43, d = 0.59, e = 0.14;
|
|
22
|
+
return clamp((x*(a*x+b))/(x*(c*x+d)+e), 0.0, 1.0);
|
|
23
|
+
}
|
|
24
|
+
void main() {
|
|
25
|
+
vec4 c = texture(u_tex, v_uv);
|
|
26
|
+
c.rgb = tonemapACES(c.rgb);
|
|
27
|
+
c.rgb = pow(c.rgb, vec3(1.0/2.2));
|
|
28
|
+
o_col = c;
|
|
29
|
+
}`;
|
|
30
|
+
|
|
31
|
+
// Sprite shader (screen-space)
|
|
32
|
+
const VERT_SPR = `#version 300 es
|
|
33
|
+
precision highp float;
|
|
34
|
+
layout(location=0) in vec2 a_pos; // quad verts in pixels (0..1) scaled in VS
|
|
35
|
+
layout(location=1) in vec2 i_pos; // instance: screen position (pixels)
|
|
36
|
+
layout(location=2) in vec2 i_size; // instance: size in pixels
|
|
37
|
+
layout(location=3) in vec4 i_uv; // instance: uv rect (u0,v0,u1,v1)
|
|
38
|
+
out vec2 v_uv;
|
|
39
|
+
uniform vec2 u_resolution;
|
|
40
|
+
void main() {
|
|
41
|
+
vec2 px = i_pos + a_pos * i_size; // pixel space
|
|
42
|
+
v_uv = mix(i_uv.xy, i_uv.zw, a_pos);
|
|
43
|
+
vec2 ndc = (px / u_resolution)*2.0 - 1.0;
|
|
44
|
+
ndc.y = -ndc.y;
|
|
45
|
+
gl_Position = vec4(ndc, 0.0, 1.0);
|
|
46
|
+
}`;
|
|
47
|
+
|
|
48
|
+
const FRAG_SPR = `#version 300 es
|
|
49
|
+
precision highp float;
|
|
50
|
+
in vec2 v_uv;
|
|
51
|
+
out vec4 o_col;
|
|
52
|
+
uniform sampler2D u_tex;
|
|
53
|
+
void main(){
|
|
54
|
+
vec4 c = texture(u_tex, v_uv);
|
|
55
|
+
o_col = c;
|
|
56
|
+
}`;
|
|
57
|
+
|
|
58
|
+
export class GpuWebGL2 {
|
|
59
|
+
constructor(canvas, w, h) {
|
|
60
|
+
this.canvas = canvas;
|
|
61
|
+
/** @type {WebGL2RenderingContext} */
|
|
62
|
+
const gl = canvas.getContext('webgl2', {
|
|
63
|
+
antialias: false,
|
|
64
|
+
alpha: false,
|
|
65
|
+
premultipliedAlpha: false,
|
|
66
|
+
});
|
|
67
|
+
if (!gl) throw new Error('WebGL2 not supported');
|
|
68
|
+
this.gl = gl;
|
|
69
|
+
this.fb = new Framebuffer64(w, h);
|
|
70
|
+
this.w = w;
|
|
71
|
+
this.h = h;
|
|
72
|
+
|
|
73
|
+
// Programs
|
|
74
|
+
this.progFSQ = this._makeProgram(VERT_FSQ, FRAG_TONEMAP);
|
|
75
|
+
this.progSPR = this._makeProgram(VERT_SPR, FRAG_SPR);
|
|
76
|
+
|
|
77
|
+
// Fullscreen triangle VBO
|
|
78
|
+
this.vboFSQ = gl.createBuffer();
|
|
79
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboFSQ);
|
|
80
|
+
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([-1, -1, 3, -1, -1, 3]), gl.STATIC_DRAW);
|
|
81
|
+
|
|
82
|
+
// Quad for sprites (two-triangle unit quad encoded as [0,0]-[1,1])
|
|
83
|
+
this.vboQuad = gl.createBuffer();
|
|
84
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboQuad);
|
|
85
|
+
gl.bufferData(
|
|
86
|
+
gl.ARRAY_BUFFER,
|
|
87
|
+
new Float32Array([0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 1]),
|
|
88
|
+
gl.STATIC_DRAW
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
// Instance buffers
|
|
92
|
+
this.instPos = gl.createBuffer();
|
|
93
|
+
this.instSize = gl.createBuffer();
|
|
94
|
+
this.instUV = gl.createBuffer();
|
|
95
|
+
|
|
96
|
+
// Texture for framebuffer upload (RGBA16F, accepts FLOAT data)
|
|
97
|
+
this.texFB = gl.createTexture();
|
|
98
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texFB);
|
|
99
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
100
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
101
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
102
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
103
|
+
gl.pixelStorei(gl.UNPACK_ALIGNMENT, 1);
|
|
104
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA16F, w, h, 0, gl.RGBA, gl.FLOAT, null);
|
|
105
|
+
|
|
106
|
+
this.tmpF32 = new Float32Array(w * h * 4); // normalized 0..1
|
|
107
|
+
|
|
108
|
+
// Sprite batch state
|
|
109
|
+
this.spriteBatches = new Map(); // texture -> array of instances
|
|
110
|
+
this.texCache = new WeakMap(); // HTMLImageElement -> WebGLTexture
|
|
111
|
+
|
|
112
|
+
gl.enable(gl.BLEND);
|
|
113
|
+
gl.blendFuncSeparate(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
114
|
+
gl.viewport(0, 0, canvas.width, canvas.height);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
_makeProgram(vsSrc, fsSrc) {
|
|
118
|
+
const gl = this.gl;
|
|
119
|
+
const vs = gl.createShader(gl.VERTEX_SHADER);
|
|
120
|
+
gl.shaderSource(vs, vsSrc);
|
|
121
|
+
gl.compileShader(vs);
|
|
122
|
+
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(vs));
|
|
123
|
+
const fs = gl.createShader(gl.FRAGMENT_SHADER);
|
|
124
|
+
gl.shaderSource(fs, fsSrc);
|
|
125
|
+
gl.compileShader(fs);
|
|
126
|
+
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS)) throw new Error(gl.getShaderInfoLog(fs));
|
|
127
|
+
const p = gl.createProgram();
|
|
128
|
+
gl.attachShader(p, vs);
|
|
129
|
+
gl.attachShader(p, fs);
|
|
130
|
+
gl.linkProgram(p);
|
|
131
|
+
if (!gl.getProgramParameter(p, gl.LINK_STATUS)) throw new Error(gl.getProgramInfoLog(p));
|
|
132
|
+
return p;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
beginFrame() {
|
|
136
|
+
const gl = this.gl;
|
|
137
|
+
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
138
|
+
gl.clearColor(0, 0, 0, 1);
|
|
139
|
+
gl.clear(gl.COLOR_BUFFER_BIT);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Queue a sprite instance; img is HTMLImageElement, uv rect in pixels of the image
|
|
143
|
+
queueSprite(img, sx, sy, sw, sh, dx, dy, scale = 1) {
|
|
144
|
+
const gltex = this._getTexture(img);
|
|
145
|
+
let arr = this.spriteBatches.get(gltex);
|
|
146
|
+
if (!arr) {
|
|
147
|
+
arr = [];
|
|
148
|
+
this.spriteBatches.set(gltex, arr);
|
|
149
|
+
}
|
|
150
|
+
arr.push({
|
|
151
|
+
sx,
|
|
152
|
+
sy,
|
|
153
|
+
sw,
|
|
154
|
+
sh,
|
|
155
|
+
dx,
|
|
156
|
+
dy,
|
|
157
|
+
scale,
|
|
158
|
+
tex: gltex,
|
|
159
|
+
iw: img.naturalWidth,
|
|
160
|
+
ih: img.naturalHeight,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
_getTexture(img) {
|
|
165
|
+
let tex = this.texCache.get(img);
|
|
166
|
+
if (tex) return tex;
|
|
167
|
+
const gl = this.gl;
|
|
168
|
+
tex = gl.createTexture();
|
|
169
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
170
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
171
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
172
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
173
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
174
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
175
|
+
gl.texImage2D(
|
|
176
|
+
gl.TEXTURE_2D,
|
|
177
|
+
0,
|
|
178
|
+
gl.RGBA,
|
|
179
|
+
img.naturalWidth,
|
|
180
|
+
img.naturalHeight,
|
|
181
|
+
0,
|
|
182
|
+
gl.RGBA,
|
|
183
|
+
gl.UNSIGNED_BYTE,
|
|
184
|
+
img
|
|
185
|
+
);
|
|
186
|
+
this.texCache.set(img, tex);
|
|
187
|
+
return tex;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
endFrame() {
|
|
191
|
+
const gl = this.gl;
|
|
192
|
+
|
|
193
|
+
// Upload framebuffer as RGBA16F using Float32 normalized data
|
|
194
|
+
const p = this.fb.pixels;
|
|
195
|
+
const f = this.tmpF32;
|
|
196
|
+
let k = 0;
|
|
197
|
+
for (let i = 0; i < p.length; i += 4) {
|
|
198
|
+
f[k++] = p[i] / 65535.0;
|
|
199
|
+
f[k++] = p[i + 1] / 65535.0;
|
|
200
|
+
f[k++] = p[i + 2] / 65535.0;
|
|
201
|
+
f[k++] = p[i + 3] / 65535.0;
|
|
202
|
+
}
|
|
203
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texFB);
|
|
204
|
+
gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, this.w, this.h, gl.RGBA, gl.FLOAT, f);
|
|
205
|
+
|
|
206
|
+
// Draw FSQ with tone mapping
|
|
207
|
+
gl.useProgram(this.progFSQ);
|
|
208
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
209
|
+
gl.bindTexture(gl.TEXTURE_2D, this.texFB);
|
|
210
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboFSQ);
|
|
211
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
212
|
+
gl.enableVertexAttribArray(0);
|
|
213
|
+
gl.drawArrays(gl.TRIANGLES, 0, 3);
|
|
214
|
+
|
|
215
|
+
// Draw sprite batches on top
|
|
216
|
+
if (this.spriteBatches.size) {
|
|
217
|
+
gl.useProgram(this.progSPR);
|
|
218
|
+
const uRes = gl.getUniformLocation(this.progSPR, 'u_resolution');
|
|
219
|
+
gl.uniform2f(uRes, this.canvas.width, this.canvas.height);
|
|
220
|
+
// bind quad verts
|
|
221
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.vboQuad);
|
|
222
|
+
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
|
223
|
+
gl.enableVertexAttribArray(0);
|
|
224
|
+
|
|
225
|
+
// instance attribute locations
|
|
226
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instPos);
|
|
227
|
+
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
|
|
228
|
+
gl.enableVertexAttribArray(1);
|
|
229
|
+
gl.vertexAttribDivisor(1, 1);
|
|
230
|
+
|
|
231
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instSize);
|
|
232
|
+
gl.vertexAttribPointer(2, 2, gl.FLOAT, false, 0, 0);
|
|
233
|
+
gl.enableVertexAttribArray(2);
|
|
234
|
+
gl.vertexAttribDivisor(2, 1);
|
|
235
|
+
|
|
236
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instUV);
|
|
237
|
+
gl.vertexAttribPointer(3, 4, gl.FLOAT, false, 0, 0);
|
|
238
|
+
gl.enableVertexAttribArray(3);
|
|
239
|
+
gl.vertexAttribDivisor(3, 1);
|
|
240
|
+
|
|
241
|
+
for (const [tex, arr] of this.spriteBatches.entries()) {
|
|
242
|
+
const n = arr.length;
|
|
243
|
+
const pos = new Float32Array(n * 2);
|
|
244
|
+
const size = new Float32Array(n * 2);
|
|
245
|
+
const uvs = new Float32Array(n * 4);
|
|
246
|
+
for (let i = 0; i < n; i++) {
|
|
247
|
+
const s = arr[i];
|
|
248
|
+
pos[i * 2 + 0] = s.dx;
|
|
249
|
+
pos[i * 2 + 1] = s.dy;
|
|
250
|
+
size[i * 2 + 0] = s.sw * s.scale;
|
|
251
|
+
size[i * 2 + 1] = s.sh * s.scale;
|
|
252
|
+
const u0 = s.sx / s.iw,
|
|
253
|
+
v0 = s.sy / s.ih;
|
|
254
|
+
const u1 = (s.sx + s.sw) / s.iw,
|
|
255
|
+
v1 = (s.sy + s.sh) / s.ih;
|
|
256
|
+
uvs[i * 4 + 0] = u0;
|
|
257
|
+
uvs[i * 4 + 1] = v0;
|
|
258
|
+
uvs[i * 4 + 2] = u1;
|
|
259
|
+
uvs[i * 4 + 3] = v1;
|
|
260
|
+
}
|
|
261
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instPos);
|
|
262
|
+
gl.bufferData(gl.ARRAY_BUFFER, pos, gl.DYNAMIC_DRAW);
|
|
263
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instSize);
|
|
264
|
+
gl.bufferData(gl.ARRAY_BUFFER, size, gl.DYNAMIC_DRAW);
|
|
265
|
+
gl.bindBuffer(gl.ARRAY_BUFFER, this.instUV);
|
|
266
|
+
gl.bufferData(gl.ARRAY_BUFFER, uvs, gl.DYNAMIC_DRAW);
|
|
267
|
+
|
|
268
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
269
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
270
|
+
gl.drawArraysInstanced(gl.TRIANGLES, 0, 6, n);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
this.spriteBatches.clear();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
// API surface hooks needed by higher-level APIs
|
|
278
|
+
getFramebuffer() {
|
|
279
|
+
return this.fb;
|
|
280
|
+
}
|
|
281
|
+
supportsSpriteBatch() {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
updateTextureForImage(img) {
|
|
286
|
+
const gl = this.gl;
|
|
287
|
+
let tex = this.texCache.get(img);
|
|
288
|
+
if (!tex) {
|
|
289
|
+
tex = gl.createTexture();
|
|
290
|
+
this.texCache.set(img, tex);
|
|
291
|
+
}
|
|
292
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
293
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
294
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
295
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
296
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
297
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
298
|
+
gl.texImage2D(
|
|
299
|
+
gl.TEXTURE_2D,
|
|
300
|
+
0,
|
|
301
|
+
gl.RGBA,
|
|
302
|
+
img.naturalWidth,
|
|
303
|
+
img.naturalHeight,
|
|
304
|
+
0,
|
|
305
|
+
gl.RGBA,
|
|
306
|
+
gl.UNSIGNED_BYTE,
|
|
307
|
+
img
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
}
|