poppygl 0.0.17 → 0.0.18

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 CHANGED
@@ -50,6 +50,7 @@ const png = await renderGLTFToPNGBufferFromGLBBuffer(glb, {
50
50
  `renderGLTFToPNGBufferFromURL` accepts the same render options as the lower-level APIs:
51
51
 
52
52
  - `width`/`height` (default `512`): output resolution in pixels.
53
+ - `supersampling`: render at `width * supersampling` / `height * supersampling`, then downsample (default `1`).
53
54
  - `fov`: vertical field of view in degrees (defaults to `35`).
54
55
  - `camPos` and `lookAt`: override the auto-framed camera position and target.
55
56
  - `lightDir`: normalized directional light vector (defaults to a top-right key light).
package/dist/index.d.ts CHANGED
@@ -62,6 +62,7 @@ declare function hexToRgb(hex: string): [number, number, number] | null;
62
62
  interface RenderOptions {
63
63
  width: number;
64
64
  height: number;
65
+ supersampling: number;
65
66
  fov: number;
66
67
  cull: boolean;
67
68
  gamma: boolean;
package/dist/index.js CHANGED
@@ -132,6 +132,204 @@ var createUint8Bitmap = (width, height) => ({
132
132
  data: new Uint8ClampedArray(width * height * 4)
133
133
  });
134
134
 
135
+ // lib/render/downsampleBitmap.ts
136
+ function downsampleBitmap(source, targetWidth, targetHeight, imageFactory) {
137
+ const target = imageFactory(targetWidth, targetHeight);
138
+ const scaleX = source.width / targetWidth;
139
+ const scaleY = source.height / targetHeight;
140
+ for (let y = 0; y < targetHeight; y++) {
141
+ const srcY0 = Math.floor(y * scaleY);
142
+ const srcY1 = Math.max(
143
+ srcY0 + 1,
144
+ Math.min(source.height, Math.floor((y + 1) * scaleY))
145
+ );
146
+ for (let x = 0; x < targetWidth; x++) {
147
+ const srcX0 = Math.floor(x * scaleX);
148
+ const srcX1 = Math.max(
149
+ srcX0 + 1,
150
+ Math.min(source.width, Math.floor((x + 1) * scaleX))
151
+ );
152
+ let r = 0;
153
+ let g = 0;
154
+ let b = 0;
155
+ let a = 0;
156
+ let count = 0;
157
+ for (let sy = srcY0; sy < srcY1; sy++) {
158
+ for (let sx = srcX0; sx < srcX1; sx++) {
159
+ const srcIdx = (sy * source.width + sx) * 4;
160
+ r += source.data[srcIdx + 0];
161
+ g += source.data[srcIdx + 1];
162
+ b += source.data[srcIdx + 2];
163
+ a += source.data[srcIdx + 3];
164
+ count++;
165
+ }
166
+ }
167
+ const dstIdx = (y * targetWidth + x) * 4;
168
+ target.data[dstIdx + 0] = Math.round(r / count);
169
+ target.data[dstIdx + 1] = Math.round(g / count);
170
+ target.data[dstIdx + 2] = Math.round(b / count);
171
+ target.data[dstIdx + 3] = Math.round(a / count);
172
+ }
173
+ }
174
+ return target;
175
+ }
176
+
177
+ // lib/render/drawInfiniteGrid.ts
178
+ import { mat4 as mat43, vec4 as vec42 } from "gl-matrix";
179
+
180
+ // lib/utils/srgbEncodeLinear01.ts
181
+ function srgbEncodeLinear01(linear) {
182
+ if (linear <= 31308e-7) return 12.92 * linear;
183
+ return 1.055 * Math.pow(linear, 1 / 2.4) - 0.055;
184
+ }
185
+
186
+ // lib/utils/clamp.ts
187
+ var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
188
+
189
+ // lib/render/drawInfiniteGrid.ts
190
+ function computeGridLineIntensity(params) {
191
+ const rx = params.world_x / params.cell_size;
192
+ const rz = params.world_z / params.cell_size;
193
+ const fract_x = rx - Math.floor(rx + 0.5);
194
+ const fract_z = rz - Math.floor(rz + 0.5);
195
+ const grid_x = Math.abs(fract_x);
196
+ const grid_z = Math.abs(fract_z);
197
+ const pixel_size_in_world = params.dist / Math.min(params.screen_width, params.screen_height);
198
+ const fwidth_x = pixel_size_in_world / params.cell_size;
199
+ const fwidth_z = pixel_size_in_world / params.cell_size;
200
+ const line_x = grid_x / (fwidth_x + 1e-4);
201
+ const line_z = grid_z / (fwidth_z + 1e-4);
202
+ const line = Math.min(line_x, line_z);
203
+ return 1 - Math.min(line * params.line_thickness_multiplier, 1);
204
+ }
205
+ function computeGridFadeAlpha(params) {
206
+ const fade_start = params.fade_distance;
207
+ const fade_end = params.fade_distance * params.fade_strength;
208
+ return 1 - Math.min(
209
+ 1,
210
+ Math.max(0, (params.dist - fade_start) / (fade_end - fade_start))
211
+ );
212
+ }
213
+ function drawInfiniteGrid(software_renderer, params) {
214
+ const grid_y = params.grid_y ?? 0;
215
+ const cell_size = params.cell_size ?? 1;
216
+ const section_size = params.section_size ?? 10;
217
+ const fade_distance = params.fade_distance ?? 100;
218
+ const fade_strength = params.fade_strength ?? 1.5;
219
+ const grid_color = params.grid_color ?? [0.93, 0.93, 0.93];
220
+ const section_color = params.section_color ?? [0.8, 0.8, 1];
221
+ const gamma_out = params.gamma_out ?? true;
222
+ const camera = params.camera;
223
+ const view = camera.view;
224
+ const proj = camera.proj;
225
+ const inv_view = mat43.create();
226
+ mat43.invert(inv_view, view);
227
+ const cam_pos_x = inv_view[12];
228
+ const cam_pos_y = inv_view[13];
229
+ const cam_pos_z = inv_view[14];
230
+ const vp = mat43.create();
231
+ mat43.multiply(vp, proj, view);
232
+ const inv_vp = mat43.create();
233
+ mat43.invert(inv_vp, vp);
234
+ for (let y = 0; y < software_renderer.height; y++) {
235
+ for (let x = 0; x < software_renderer.width; x++) {
236
+ const ndc_x = x / (software_renderer.width - 1) * 2 - 1;
237
+ const ndc_y = 1 - y / (software_renderer.height - 1) * 2;
238
+ const near_point = vec42.fromValues(ndc_x, ndc_y, -1, 1);
239
+ const far_point = vec42.fromValues(ndc_x, ndc_y, 1, 1);
240
+ vec42.transformMat4(near_point, near_point, inv_vp);
241
+ vec42.transformMat4(far_point, far_point, inv_vp);
242
+ near_point[0] /= near_point[3];
243
+ near_point[1] /= near_point[3];
244
+ near_point[2] /= near_point[3];
245
+ far_point[0] /= far_point[3];
246
+ far_point[1] /= far_point[3];
247
+ far_point[2] /= far_point[3];
248
+ const ray_dir_x = far_point[0] - near_point[0];
249
+ const ray_dir_y = far_point[1] - near_point[1];
250
+ const ray_dir_z = far_point[2] - near_point[2];
251
+ if (Math.abs(ray_dir_y) < 1e-6) continue;
252
+ const t = (grid_y - near_point[1]) / ray_dir_y;
253
+ if (t < 0 || t > 1) continue;
254
+ const world_x = near_point[0] + t * ray_dir_x;
255
+ const world_z = near_point[2] + t * ray_dir_z;
256
+ const world_pt = vec42.fromValues(world_x, grid_y, world_z, 1);
257
+ const clip_pt = vec42.create();
258
+ vec42.transformMat4(clip_pt, world_pt, vp);
259
+ const ndc_z = clip_pt[2] / clip_pt[3];
260
+ const depth_01 = ndc_z * 0.5 + 0.5;
261
+ const di = y * software_renderer.width + x;
262
+ if (depth_01 >= software_renderer.depth[di]) continue;
263
+ const dx = world_x - cam_pos_x;
264
+ const dy = grid_y - cam_pos_y;
265
+ const dz = world_z - cam_pos_z;
266
+ const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
267
+ const alpha = computeGridFadeAlpha({
268
+ dist,
269
+ fade_distance,
270
+ fade_strength
271
+ });
272
+ if (alpha <= 0) continue;
273
+ const g1 = computeGridLineIntensity({
274
+ world_x,
275
+ world_z,
276
+ cell_size,
277
+ dist,
278
+ screen_width: software_renderer.width,
279
+ screen_height: software_renderer.height,
280
+ line_thickness_multiplier: 0.8
281
+ });
282
+ const g2 = computeGridLineIntensity({
283
+ world_x,
284
+ world_z,
285
+ cell_size: section_size,
286
+ dist,
287
+ screen_width: software_renderer.width,
288
+ screen_height: software_renderer.height,
289
+ line_thickness_multiplier: 0.5
290
+ // Thicker section lines
291
+ });
292
+ const grid_strength = Math.max(g1, g2);
293
+ if (grid_strength <= 0) continue;
294
+ const final_r = grid_color[0] * (1 - g2) + section_color[0] * g2;
295
+ const final_g = grid_color[1] * (1 - g2) + section_color[1] * g2;
296
+ const final_b = grid_color[2] * (1 - g2) + section_color[2] * g2;
297
+ const final_alpha = grid_strength * alpha;
298
+ if (final_alpha <= 0.01) continue;
299
+ let out_r = final_r;
300
+ let out_g = final_g;
301
+ let out_b = final_b;
302
+ if (gamma_out) {
303
+ out_r = srgbEncodeLinear01(clamp(out_r, 0, 1));
304
+ out_g = srgbEncodeLinear01(clamp(out_g, 0, 1));
305
+ out_b = srgbEncodeLinear01(clamp(out_b, 0, 1));
306
+ } else {
307
+ out_r = clamp(out_r, 0, 1);
308
+ out_g = clamp(out_g, 0, 1);
309
+ out_b = clamp(out_b, 0, 1);
310
+ }
311
+ const dst_idx = (y * software_renderer.width + x) * 4;
312
+ const dst_r = (software_renderer.buffer[dst_idx + 0] ?? 0) / 255;
313
+ const dst_g = (software_renderer.buffer[dst_idx + 1] ?? 0) / 255;
314
+ const dst_b = (software_renderer.buffer[dst_idx + 2] ?? 0) / 255;
315
+ const dst_a = (software_renderer.buffer[dst_idx + 3] ?? 0) / 255;
316
+ const one_minus_a = 1 - final_alpha;
317
+ const blend_r = out_r * final_alpha + dst_r * one_minus_a;
318
+ const blend_g = out_g * final_alpha + dst_g * one_minus_a;
319
+ const blend_b = out_b * final_alpha + dst_b * one_minus_a;
320
+ const blend_a = final_alpha + dst_a * one_minus_a;
321
+ software_renderer.setPixel(
322
+ x,
323
+ y,
324
+ clamp(blend_r, 0, 1) * 255 | 0,
325
+ clamp(blend_g, 0, 1) * 255 | 0,
326
+ clamp(blend_b, 0, 1) * 255 | 0,
327
+ clamp(blend_a, 0, 1) * 255 | 0
328
+ );
329
+ }
330
+ }
331
+ }
332
+
135
333
  // lib/render/getDefaultRenderOptions.ts
136
334
  var DEFAULT_LIGHT_DIR = [-0.4, -0.9, -0.2];
137
335
  function hexToRgb(hex) {
@@ -147,6 +345,7 @@ function hexToRgb(hex) {
147
345
  var DEFAULT_RENDER_OPTIONS = {
148
346
  width: 800,
149
347
  height: 600,
348
+ supersampling: 1,
150
349
  fov: 60,
151
350
  cull: true,
152
351
  gamma: true,
@@ -161,8 +360,21 @@ function getDefaultRenderOptions() {
161
360
  return { ...DEFAULT_RENDER_OPTIONS };
162
361
  }
163
362
 
363
+ // lib/render/resolveRenderOptions.ts
364
+ function resolveRenderOptions(options = {}) {
365
+ const supersampling = typeof options.supersampling === "number" && Number.isFinite(options.supersampling) ? Math.max(1, Math.floor(options.supersampling)) : DEFAULT_RENDER_OPTIONS.supersampling;
366
+ return {
367
+ ...DEFAULT_RENDER_OPTIONS,
368
+ ...options,
369
+ supersampling,
370
+ lightDir: options.lightDir != null ? options.lightDir : DEFAULT_RENDER_OPTIONS.lightDir,
371
+ camPos: options.camPos !== void 0 ? options.camPos : DEFAULT_RENDER_OPTIONS.camPos,
372
+ lookAt: options.lookAt !== void 0 ? options.lookAt : DEFAULT_RENDER_OPTIONS.lookAt
373
+ };
374
+ }
375
+
164
376
  // lib/render/SoftwareRenderer.ts
165
- import { mat3, mat4 as mat43, vec3 as vec32, vec4 as vec42 } from "gl-matrix";
377
+ import { mat3, mat4 as mat44, vec3 as vec32, vec4 as vec43 } from "gl-matrix";
166
378
 
167
379
  // lib/gltf/computeSmoothNormals.ts
168
380
  function computeSmoothNormals(positions, indices) {
@@ -235,15 +447,6 @@ function mulColor(a, b) {
235
447
  return [a[0] * b[0], a[1] * b[1], a[2] * b[2], a[3] * b[3]];
236
448
  }
237
449
 
238
- // lib/utils/srgbEncodeLinear01.ts
239
- function srgbEncodeLinear01(linear) {
240
- if (linear <= 31308e-7) return 12.92 * linear;
241
- return 1.055 * Math.pow(linear, 1 / 2.4) - 0.055;
242
- }
243
-
244
- // lib/utils/clamp.ts
245
- var clamp = (value, min, max) => Math.max(min, Math.min(max, value));
246
-
247
450
  // lib/render/SoftwareRenderer.ts
248
451
  var SoftwareRenderer = class {
249
452
  width;
@@ -283,21 +486,21 @@ var SoftwareRenderer = class {
283
486
  if (!indices) return;
284
487
  const view = camera.view;
285
488
  const proj = camera.proj;
286
- const mvp = mat43.create();
287
- mat43.multiply(mvp, proj, mat43.multiply(mat43.create(), view, model));
489
+ const mvp = mat44.create();
490
+ mat44.multiply(mvp, proj, mat44.multiply(mat44.create(), view, model));
288
491
  const vertexCount = positions.length / 3 | 0;
289
492
  const vScreen = new Array(vertexCount);
290
493
  const vInvW = new Float32Array(vertexCount);
291
494
  const vNDCz = new Float32Array(vertexCount);
292
495
  for (let i = 0; i < vertexCount; i++) {
293
- const p = vec42.fromValues(
496
+ const p = vec43.fromValues(
294
497
  positions[i * 3 + 0],
295
498
  positions[i * 3 + 1],
296
499
  positions[i * 3 + 2],
297
500
  1
298
501
  );
299
- const c = vec42.create();
300
- vec42.transformMat4(c, p, mvp);
502
+ const c = vec43.create();
503
+ vec43.transformMat4(c, p, mvp);
301
504
  const invW = 1 / c[3];
302
505
  vInvW[i] = invW;
303
506
  if (!isFinite(invW)) {
@@ -397,8 +600,8 @@ var SoftwareRenderer = class {
397
600
  const { positions, normals, uvs, indices, model, colors } = mesh;
398
601
  const view = camera.view;
399
602
  const proj = camera.proj;
400
- const mvp = mat43.create();
401
- mat43.multiply(mvp, proj, mat43.multiply(mat43.create(), view, model));
603
+ const mvp = mat44.create();
604
+ mat44.multiply(mvp, proj, mat44.multiply(mat44.create(), view, model));
402
605
  const normalMat = mat3.create();
403
606
  mat3.normalFromMat4(normalMat, model);
404
607
  const vertexCount = positions.length / 3 | 0;
@@ -417,14 +620,14 @@ var SoftwareRenderer = class {
417
620
  const vWorldN = new Array(vertexCount);
418
621
  const vColor = new Array(vertexCount);
419
622
  for (let i = 0; i < vertexCount; i++) {
420
- const p = vec42.fromValues(
623
+ const p = vec43.fromValues(
421
624
  positions[i * 3 + 0],
422
625
  positions[i * 3 + 1],
423
626
  positions[i * 3 + 2],
424
627
  1
425
628
  );
426
- const c = vec42.create();
427
- vec42.transformMat4(c, p, mvp);
629
+ const c = vec43.create();
630
+ vec43.transformMat4(c, p, mvp);
428
631
  const invW = 1 / c[3];
429
632
  const ndcX = c[0] * invW;
430
633
  const ndcY = c[1] * invW;
@@ -603,178 +806,20 @@ function edge(a, b, p) {
603
806
  return (p[0] - a[0]) * (b[1] - a[1]) - (p[1] - a[1]) * (b[0] - a[0]);
604
807
  }
605
808
 
606
- // lib/render/resolveRenderOptions.ts
607
- function resolveRenderOptions(options = {}) {
608
- return {
609
- ...DEFAULT_RENDER_OPTIONS,
610
- ...options,
611
- lightDir: options.lightDir != null ? options.lightDir : DEFAULT_RENDER_OPTIONS.lightDir,
612
- camPos: options.camPos !== void 0 ? options.camPos : DEFAULT_RENDER_OPTIONS.camPos,
613
- lookAt: options.lookAt !== void 0 ? options.lookAt : DEFAULT_RENDER_OPTIONS.lookAt
614
- };
615
- }
616
-
617
- // lib/render/drawInfiniteGrid.ts
618
- import { mat4 as mat44, vec4 as vec43 } from "gl-matrix";
619
- function computeGridLineIntensity(params) {
620
- const rx = params.world_x / params.cell_size;
621
- const rz = params.world_z / params.cell_size;
622
- const fract_x = rx - Math.floor(rx + 0.5);
623
- const fract_z = rz - Math.floor(rz + 0.5);
624
- const grid_x = Math.abs(fract_x);
625
- const grid_z = Math.abs(fract_z);
626
- const pixel_size_in_world = params.dist / Math.min(params.screen_width, params.screen_height);
627
- const fwidth_x = pixel_size_in_world / params.cell_size;
628
- const fwidth_z = pixel_size_in_world / params.cell_size;
629
- const line_x = grid_x / (fwidth_x + 1e-4);
630
- const line_z = grid_z / (fwidth_z + 1e-4);
631
- const line = Math.min(line_x, line_z);
632
- return 1 - Math.min(line * params.line_thickness_multiplier, 1);
633
- }
634
- function computeGridFadeAlpha(params) {
635
- const fade_start = params.fade_distance;
636
- const fade_end = params.fade_distance * params.fade_strength;
637
- return 1 - Math.min(
638
- 1,
639
- Math.max(0, (params.dist - fade_start) / (fade_end - fade_start))
640
- );
641
- }
642
- function drawInfiniteGrid(software_renderer, params) {
643
- const grid_y = params.grid_y ?? 0;
644
- const cell_size = params.cell_size ?? 1;
645
- const section_size = params.section_size ?? 10;
646
- const fade_distance = params.fade_distance ?? 100;
647
- const fade_strength = params.fade_strength ?? 1.5;
648
- const grid_color = params.grid_color ?? [0.93, 0.93, 0.93];
649
- const section_color = params.section_color ?? [0.8, 0.8, 1];
650
- const gamma_out = params.gamma_out ?? true;
651
- const camera = params.camera;
652
- const view = camera.view;
653
- const proj = camera.proj;
654
- const inv_view = mat44.create();
655
- mat44.invert(inv_view, view);
656
- const cam_pos_x = inv_view[12];
657
- const cam_pos_y = inv_view[13];
658
- const cam_pos_z = inv_view[14];
659
- const vp = mat44.create();
660
- mat44.multiply(vp, proj, view);
661
- const inv_vp = mat44.create();
662
- mat44.invert(inv_vp, vp);
663
- for (let y = 0; y < software_renderer.height; y++) {
664
- for (let x = 0; x < software_renderer.width; x++) {
665
- const ndc_x = x / (software_renderer.width - 1) * 2 - 1;
666
- const ndc_y = 1 - y / (software_renderer.height - 1) * 2;
667
- const near_point = vec43.fromValues(ndc_x, ndc_y, -1, 1);
668
- const far_point = vec43.fromValues(ndc_x, ndc_y, 1, 1);
669
- vec43.transformMat4(near_point, near_point, inv_vp);
670
- vec43.transformMat4(far_point, far_point, inv_vp);
671
- near_point[0] /= near_point[3];
672
- near_point[1] /= near_point[3];
673
- near_point[2] /= near_point[3];
674
- far_point[0] /= far_point[3];
675
- far_point[1] /= far_point[3];
676
- far_point[2] /= far_point[3];
677
- const ray_dir_x = far_point[0] - near_point[0];
678
- const ray_dir_y = far_point[1] - near_point[1];
679
- const ray_dir_z = far_point[2] - near_point[2];
680
- if (Math.abs(ray_dir_y) < 1e-6) continue;
681
- const t = (grid_y - near_point[1]) / ray_dir_y;
682
- if (t < 0 || t > 1) continue;
683
- const world_x = near_point[0] + t * ray_dir_x;
684
- const world_z = near_point[2] + t * ray_dir_z;
685
- const world_pt = vec43.fromValues(world_x, grid_y, world_z, 1);
686
- const clip_pt = vec43.create();
687
- vec43.transformMat4(clip_pt, world_pt, vp);
688
- const ndc_z = clip_pt[2] / clip_pt[3];
689
- const depth_01 = ndc_z * 0.5 + 0.5;
690
- const di = y * software_renderer.width + x;
691
- if (depth_01 >= software_renderer.depth[di]) continue;
692
- const dx = world_x - cam_pos_x;
693
- const dy = grid_y - cam_pos_y;
694
- const dz = world_z - cam_pos_z;
695
- const dist = Math.sqrt(dx * dx + dy * dy + dz * dz);
696
- const alpha = computeGridFadeAlpha({
697
- dist,
698
- fade_distance,
699
- fade_strength
700
- });
701
- if (alpha <= 0) continue;
702
- const g1 = computeGridLineIntensity({
703
- world_x,
704
- world_z,
705
- cell_size,
706
- dist,
707
- screen_width: software_renderer.width,
708
- screen_height: software_renderer.height,
709
- line_thickness_multiplier: 0.8
710
- });
711
- const g2 = computeGridLineIntensity({
712
- world_x,
713
- world_z,
714
- cell_size: section_size,
715
- dist,
716
- screen_width: software_renderer.width,
717
- screen_height: software_renderer.height,
718
- line_thickness_multiplier: 0.5
719
- // Thicker section lines
720
- });
721
- const grid_strength = Math.max(g1, g2);
722
- if (grid_strength <= 0) continue;
723
- const final_r = grid_color[0] * (1 - g2) + section_color[0] * g2;
724
- const final_g = grid_color[1] * (1 - g2) + section_color[1] * g2;
725
- const final_b = grid_color[2] * (1 - g2) + section_color[2] * g2;
726
- const final_alpha = grid_strength * alpha;
727
- if (final_alpha <= 0.01) continue;
728
- let out_r = final_r;
729
- let out_g = final_g;
730
- let out_b = final_b;
731
- if (gamma_out) {
732
- out_r = srgbEncodeLinear01(clamp(out_r, 0, 1));
733
- out_g = srgbEncodeLinear01(clamp(out_g, 0, 1));
734
- out_b = srgbEncodeLinear01(clamp(out_b, 0, 1));
735
- } else {
736
- out_r = clamp(out_r, 0, 1);
737
- out_g = clamp(out_g, 0, 1);
738
- out_b = clamp(out_b, 0, 1);
739
- }
740
- const dst_idx = (y * software_renderer.width + x) * 4;
741
- const dst_r = (software_renderer.buffer[dst_idx + 0] ?? 0) / 255;
742
- const dst_g = (software_renderer.buffer[dst_idx + 1] ?? 0) / 255;
743
- const dst_b = (software_renderer.buffer[dst_idx + 2] ?? 0) / 255;
744
- const dst_a = (software_renderer.buffer[dst_idx + 3] ?? 0) / 255;
745
- const one_minus_a = 1 - final_alpha;
746
- const blend_r = out_r * final_alpha + dst_r * one_minus_a;
747
- const blend_g = out_g * final_alpha + dst_g * one_minus_a;
748
- const blend_b = out_b * final_alpha + dst_b * one_minus_a;
749
- const blend_a = final_alpha + dst_a * one_minus_a;
750
- software_renderer.setPixel(
751
- x,
752
- y,
753
- clamp(blend_r, 0, 1) * 255 | 0,
754
- clamp(blend_g, 0, 1) * 255 | 0,
755
- clamp(blend_b, 0, 1) * 255 | 0,
756
- clamp(blend_a, 0, 1) * 255 | 0
757
- );
758
- }
759
- }
760
- }
761
-
762
809
  // lib/render/renderDrawCalls.ts
763
810
  function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint8Bitmap) {
764
811
  const options = resolveRenderOptions(optionsInput);
812
+ const renderWidth = options.width * options.supersampling;
813
+ const renderHeight = options.height * options.supersampling;
765
814
  const camera = buildCamera(
766
815
  drawCalls,
767
- options.width,
768
- options.height,
816
+ renderWidth,
817
+ renderHeight,
769
818
  options.fov,
770
819
  options.camPos ?? null,
771
820
  options.lookAt ?? null
772
821
  );
773
- const renderer = new SoftwareRenderer(
774
- options.width,
775
- options.height,
776
- imageFactory
777
- );
822
+ const renderer = new SoftwareRenderer(renderWidth, renderHeight, imageFactory);
778
823
  let rgb = null;
779
824
  if (options.backgroundColor) {
780
825
  if (typeof options.backgroundColor === "string") {
@@ -870,7 +915,13 @@ function renderDrawCalls(drawCalls, optionsInput = {}, imageFactory = createUint
870
915
  });
871
916
  }
872
917
  renderGroup(blendDraws);
873
- return { bitmap: renderer.bitmap, camera, options };
918
+ const bitmap = options.supersampling > 1 ? downsampleBitmap(
919
+ renderer.bitmap,
920
+ options.width,
921
+ options.height,
922
+ imageFactory
923
+ ) : renderer.bitmap;
924
+ return { bitmap, camera, options };
874
925
  }
875
926
 
876
927
  // lib/gltf/createInfiniteGrid.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "poppygl",
3
3
  "main": "dist/index.js",
4
- "version": "0.0.17",
4
+ "version": "0.0.18",
5
5
  "repository": {
6
6
  "type": "git",
7
7
  "url": "https://github.com/tscircuit/poppygl.git"