@twick/core 0.15.20 → 0.15.21

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/index.cjs CHANGED
@@ -95,6 +95,7 @@ __export(index_exports, {
95
95
  ValueDispatcher: () => ValueDispatcher,
96
96
  Variables: () => Variables,
97
97
  Vector2: () => Vector2,
98
+ WasmEffectsExporter: () => WasmEffectsExporter,
98
99
  WasmExporter: () => WasmExporter,
99
100
  addEditorToProject: () => addEditorToProject,
100
101
  all: () => all,
@@ -1594,6 +1595,117 @@ _WasmExporter.id = "@twick/core/wasm";
1594
1595
  _WasmExporter.displayName = "Video (Wasm)";
1595
1596
  var WasmExporter = _WasmExporter;
1596
1597
 
1598
+ // src/exporter/WasmEffectsExporter.ts
1599
+ var import_gl_runtime = require("@twick/gl-runtime");
1600
+ var _WasmEffectsExporter = class _WasmEffectsExporter {
1601
+ constructor(project, settings, inner) {
1602
+ this.project = project;
1603
+ this.settings = settings;
1604
+ this.inner = inner;
1605
+ this.effectGlCanvas = null;
1606
+ this.effectContext = null;
1607
+ this.effectReadbackFbo = null;
1608
+ }
1609
+ static async create(project, settings) {
1610
+ const inner = await WasmExporter.create(project, settings);
1611
+ return new _WasmEffectsExporter(project, settings, inner);
1612
+ }
1613
+ async start() {
1614
+ return this.inner.start();
1615
+ }
1616
+ async handleFrame(canvas, frame, sceneFrame, sceneName, signal) {
1617
+ const variables = this.project.variables;
1618
+ const fps = this.settings.fps ?? this.project.settings.rendering.fps ?? 30;
1619
+ const activeEffects = this.project.getActiveEffectsForFrame?.(variables ?? {}, frame, fps) ?? [];
1620
+ if (activeEffects.length === 0) {
1621
+ return this.inner.handleFrame(canvas, frame, sceneFrame, sceneName, signal);
1622
+ }
1623
+ const w = canvas.width;
1624
+ const h = canvas.height;
1625
+ if (w <= 0 || h <= 0) {
1626
+ return this.inner.handleFrame(canvas, frame, sceneFrame, sceneName, signal);
1627
+ }
1628
+ if (!this.effectGlCanvas) {
1629
+ this.effectGlCanvas = typeof OffscreenCanvas !== "undefined" ? new OffscreenCanvas(w, h) : document.createElement("canvas");
1630
+ this.effectGlCanvas.width = w;
1631
+ this.effectGlCanvas.height = h;
1632
+ }
1633
+ const glCanvas = this.effectGlCanvas;
1634
+ if (glCanvas.width !== w || glCanvas.height !== h) {
1635
+ glCanvas.width = w;
1636
+ glCanvas.height = h;
1637
+ }
1638
+ if (!this.effectContext) {
1639
+ this.effectContext = (0, import_gl_runtime.createEffectContext)(glCanvas);
1640
+ }
1641
+ const gl = this.effectContext.gl;
1642
+ const sourceTexture = gl.createTexture();
1643
+ if (!sourceTexture) {
1644
+ return this.inner.handleFrame(canvas, frame, sceneFrame, sceneName, signal);
1645
+ }
1646
+ gl.bindTexture(gl.TEXTURE_2D, sourceTexture);
1647
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
1648
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
1649
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
1650
+ gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
1651
+ gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
1652
+ gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
1653
+ const resultTexture = (0, import_gl_runtime.applyEffects)({
1654
+ ctx: this.effectContext,
1655
+ sourceTexture,
1656
+ width: w,
1657
+ height: h,
1658
+ effects: activeEffects
1659
+ });
1660
+ gl.deleteTexture(sourceTexture);
1661
+ if (!this.effectReadbackFbo) {
1662
+ this.effectReadbackFbo = gl.createFramebuffer();
1663
+ }
1664
+ gl.bindFramebuffer(gl.FRAMEBUFFER, this.effectReadbackFbo);
1665
+ gl.framebufferTexture2D(
1666
+ gl.FRAMEBUFFER,
1667
+ gl.COLOR_ATTACHMENT0,
1668
+ gl.TEXTURE_2D,
1669
+ resultTexture,
1670
+ 0
1671
+ );
1672
+ const pixels = new Uint8Array(w * h * 4);
1673
+ gl.readPixels(0, 0, w, h, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
1674
+ gl.bindFramebuffer(gl.FRAMEBUFFER, null);
1675
+ const outCanvas = document.createElement("canvas");
1676
+ outCanvas.width = w;
1677
+ outCanvas.height = h;
1678
+ const ctx2d = outCanvas.getContext("2d");
1679
+ if (ctx2d) {
1680
+ const imageData = ctx2d.createImageData(w, h);
1681
+ const rowBytes = w * 4;
1682
+ for (let y = 0; y < h; y++) {
1683
+ imageData.data.set(
1684
+ pixels.subarray((h - 1 - y) * rowBytes, (h - y) * rowBytes),
1685
+ y * rowBytes
1686
+ );
1687
+ }
1688
+ ctx2d.putImageData(imageData, 0, 0);
1689
+ }
1690
+ return this.inner.handleFrame(outCanvas, frame, sceneFrame, sceneName, signal);
1691
+ }
1692
+ async stop(result) {
1693
+ return this.inner.stop?.();
1694
+ }
1695
+ async generateAudio(assets, startFrame, endFrame) {
1696
+ return this.inner.generateAudio?.(assets, startFrame, endFrame);
1697
+ }
1698
+ async mergeMedia() {
1699
+ return this.inner.mergeMedia?.();
1700
+ }
1701
+ async downloadVideos(assets) {
1702
+ return this.inner.downloadVideos?.(assets);
1703
+ }
1704
+ };
1705
+ _WasmEffectsExporter.id = "@twick/core/wasm-effects";
1706
+ _WasmEffectsExporter.displayName = "Video (Wasm + Effects)";
1707
+ var WasmEffectsExporter = _WasmEffectsExporter;
1708
+
1597
1709
  // src/plugin/makePlugin.ts
1598
1710
  function makePlugin(plugin) {
1599
1711
  return typeof plugin === "function" ? plugin : () => plugin;
@@ -5016,7 +5128,8 @@ var Renderer = class {
5016
5128
  const exporters = [
5017
5129
  FFmpegExporterClient,
5018
5130
  ImageExporter,
5019
- WasmExporter
5131
+ WasmExporter,
5132
+ WasmEffectsExporter
5020
5133
  ];
5021
5134
  const exporterClass = exporters.find(
5022
5135
  (exporter) => exporter.id === settings.exporter.name
@@ -6330,6 +6443,7 @@ function* zoomOutTransition(area, duration = 0.6) {
6330
6443
  ValueDispatcher,
6331
6444
  Variables,
6332
6445
  Vector2,
6446
+ WasmEffectsExporter,
6333
6447
  WasmExporter,
6334
6448
  addEditorToProject,
6335
6449
  all,