@elah/core 0.1.0
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/actions/index.d.ts +3 -0
- package/dist/actions/index.js +1 -0
- package/dist/actions/splitClipAtPlayhead.d.ts +8 -0
- package/dist/actions/splitClipAtPlayhead.js +34 -0
- package/dist/actions/types.d.ts +8 -0
- package/dist/actions/types.js +1 -0
- package/dist/assets/importFiles.d.ts +29 -0
- package/dist/assets/importFiles.js +351 -0
- package/dist/assets/index.d.ts +10 -0
- package/dist/assets/index.js +13 -0
- package/dist/assets/store.d.ts +13 -0
- package/dist/assets/store.js +20 -0
- package/dist/assets/types.d.ts +23 -0
- package/dist/assets/types.js +1 -0
- package/dist/debug/trace.d.ts +20 -0
- package/dist/debug/trace.js +98 -0
- package/dist/editor/TimelineEngine.d.ts +65 -0
- package/dist/editor/TimelineEngine.js +413 -0
- package/dist/editor-context.d.ts +10 -0
- package/dist/editor-context.js +10 -0
- package/dist/elements/audio.d.ts +13 -0
- package/dist/elements/audio.js +4 -0
- package/dist/elements/base.d.ts +40 -0
- package/dist/elements/base.js +39 -0
- package/dist/elements/image.d.ts +13 -0
- package/dist/elements/image.js +4 -0
- package/dist/elements/text.d.ts +12 -0
- package/dist/elements/text.js +8 -0
- package/dist/elements/video.d.ts +13 -0
- package/dist/elements/video.js +4 -0
- package/dist/export/ExportWorker.d.ts +1 -0
- package/dist/export/ExportWorker.js +371 -0
- package/dist/export/exportVideo.d.ts +3 -0
- package/dist/export/exportVideo.js +118 -0
- package/dist/export/index.d.ts +2 -0
- package/dist/export/index.js +1 -0
- package/dist/export/lazyExport.d.ts +4 -0
- package/dist/export/lazyExport.js +4 -0
- package/dist/export/types.d.ts +37 -0
- package/dist/export/types.js +1 -0
- package/dist/index.d.ts +48 -0
- package/dist/index.js +28 -0
- package/dist/media/audio/AudioPlaybackController.d.ts +26 -0
- package/dist/media/audio/AudioPlaybackController.js +125 -0
- package/dist/media/video/DecoderBackedVideoFrameProvider.d.ts +51 -0
- package/dist/media/video/DecoderBackedVideoFrameProvider.js +125 -0
- package/dist/media/video/FrameCache.d.ts +28 -0
- package/dist/media/video/FrameCache.js +88 -0
- package/dist/media/video/StreamingFrameProducer.d.ts +57 -0
- package/dist/media/video/StreamingFrameProducer.js +356 -0
- package/dist/media/video/VideoDecoderManager.d.ts +59 -0
- package/dist/media/video/VideoDecoderManager.js +342 -0
- package/dist/media/video/VideoFrameProvider.d.ts +101 -0
- package/dist/media/video/VideoFrameProvider.js +257 -0
- package/dist/media/video/demuxer/MediabunnyDemuxer.d.ts +23 -0
- package/dist/media/video/demuxer/MediabunnyDemuxer.js +88 -0
- package/dist/media/video/demuxer/createMediabunnyBackend.d.ts +32 -0
- package/dist/media/video/demuxer/createMediabunnyBackend.js +156 -0
- package/dist/media/video/index.d.ts +8 -0
- package/dist/media/video/index.js +5 -0
- package/dist/playback/PlaybackEngine.d.ts +50 -0
- package/dist/playback/PlaybackEngine.js +188 -0
- package/dist/renderer/gpu/GpuRenderer.d.ts +38 -0
- package/dist/renderer/gpu/GpuRenderer.js +208 -0
- package/dist/renderer/gpu/RenderGraph.d.ts +10 -0
- package/dist/renderer/gpu/RenderGraph.js +80 -0
- package/dist/renderer/gpu/ShaderProgram.d.ts +14 -0
- package/dist/renderer/gpu/ShaderProgram.js +76 -0
- package/dist/renderer/gpu/TexturePool.d.ts +25 -0
- package/dist/renderer/gpu/TexturePool.js +93 -0
- package/dist/renderer/gpu/VideoTexture.d.ts +13 -0
- package/dist/renderer/gpu/VideoTexture.js +54 -0
- package/dist/renderer/gpu/WebGLContext.d.ts +28 -0
- package/dist/renderer/gpu/WebGLContext.js +102 -0
- package/dist/renderer/gpu/debug/DebugGpuRenderer.d.ts +27 -0
- package/dist/renderer/gpu/debug/DebugGpuRenderer.js +108 -0
- package/dist/renderer/gpu/debug/DebugOverlay.d.ts +17 -0
- package/dist/renderer/gpu/debug/DebugOverlay.js +83 -0
- package/dist/renderer/gpu/debug/GpuDebugCounters.d.ts +38 -0
- package/dist/renderer/gpu/debug/GpuDebugCounters.js +72 -0
- package/dist/renderer/gpu/debug/GpuDebugGlobal.d.ts +16 -0
- package/dist/renderer/gpu/debug/GpuDebugGlobal.js +14 -0
- package/dist/renderer/gpu/debug/GpuRendererDebugPanel.d.ts +31 -0
- package/dist/renderer/gpu/debug/GpuRendererDebugPanel.js +128 -0
- package/dist/renderer/gpu/debug/RecordingGl.d.ts +88 -0
- package/dist/renderer/gpu/debug/RecordingGl.js +214 -0
- package/dist/renderer/gpu/debug/playground.d.ts +20 -0
- package/dist/renderer/gpu/debug/playground.js +64 -0
- package/dist/renderer/gpu/debug/scenarios.d.ts +7 -0
- package/dist/renderer/gpu/debug/scenarios.js +145 -0
- package/dist/renderer/gpu/debug/types.d.ts +16 -0
- package/dist/renderer/gpu/debug/types.js +1 -0
- package/dist/renderer/gpu/layers/FrameProbeLayer.d.ts +16 -0
- package/dist/renderer/gpu/layers/FrameProbeLayer.js +127 -0
- package/dist/renderer/gpu/layers/ImageLayer.d.ts +23 -0
- package/dist/renderer/gpu/layers/ImageLayer.js +124 -0
- package/dist/renderer/gpu/layers/TestLayer.d.ts +16 -0
- package/dist/renderer/gpu/layers/TestLayer.js +109 -0
- package/dist/renderer/gpu/layers/TextLayer.d.ts +19 -0
- package/dist/renderer/gpu/layers/TextLayer.js +166 -0
- package/dist/renderer/gpu/layers/VideoLayer.d.ts +38 -0
- package/dist/renderer/gpu/layers/VideoLayer.js +194 -0
- package/dist/renderer/gpu/layers/drawRect.d.ts +13 -0
- package/dist/renderer/gpu/layers/drawRect.js +55 -0
- package/dist/renderer/gpu/layers/objectFit.d.ts +7 -0
- package/dist/renderer/gpu/layers/objectFit.js +26 -0
- package/dist/renderer/gpu/layers/textLayout.d.ts +47 -0
- package/dist/renderer/gpu/layers/textLayout.js +82 -0
- package/dist/renderer/gpu/layers/types.d.ts +18 -0
- package/dist/renderer/gpu/layers/types.js +1 -0
- package/dist/renderer/gpu/shaders/quad.frag.d.ts +1 -0
- package/dist/renderer/gpu/shaders/quad.frag.js +14 -0
- package/dist/renderer/gpu/shaders/quad.vert.d.ts +1 -0
- package/dist/renderer/gpu/shaders/quad.vert.js +28 -0
- package/dist/renderer/gpu/types.d.ts +21 -0
- package/dist/renderer/gpu/types.js +1 -0
- package/dist/renderer/gpu/viewport.d.ts +7 -0
- package/dist/renderer/gpu/viewport.js +33 -0
- package/dist/renderer/types.d.ts +7 -0
- package/dist/renderer/types.js +1 -0
- package/dist/resolver/resolveTimeline.d.ts +3 -0
- package/dist/resolver/resolveTimeline.js +249 -0
- package/dist/resolver/scene.d.ts +54 -0
- package/dist/resolver/scene.js +1 -0
- package/dist/stores/playback.store.d.ts +50 -0
- package/dist/stores/playback.store.js +42 -0
- package/dist/stores/selection.store.d.ts +12 -0
- package/dist/stores/selection.store.js +19 -0
- package/dist/stores/tracks.store.d.ts +19 -0
- package/dist/stores/tracks.store.js +27 -0
- package/dist/stores/transitions.store.d.ts +9 -0
- package/dist/stores/transitions.store.js +7 -0
- package/dist/track/track.d.ts +8 -0
- package/dist/track/track.js +19 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.js +1 -0
- package/dist/utils/frames.d.ts +20 -0
- package/dist/utils/frames.js +40 -0
- package/dist/utils/id.d.ts +1 -0
- package/dist/utils/id.js +3 -0
- package/dist/utils/snap.d.ts +5 -0
- package/dist/utils/snap.js +79 -0
- package/dist/visitor/add.d.ts +3 -0
- package/dist/visitor/add.js +16 -0
- package/dist/visitor/clone.d.ts +3 -0
- package/dist/visitor/clone.js +25 -0
- package/dist/visitor/remove.d.ts +5 -0
- package/dist/visitor/remove.js +29 -0
- package/dist/visitor/split.d.ts +3 -0
- package/dist/visitor/split.js +31 -0
- package/dist/visitor/update.d.ts +4 -0
- package/dist/visitor/update.js +31 -0
- package/package.json +31 -0
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { ShaderProgram } from '../ShaderProgram';
|
|
2
|
+
import { QUAD_FRAG_SRC } from '../shaders/quad.frag';
|
|
3
|
+
import { QUAD_VERT_SRC } from '../shaders/quad.vert';
|
|
4
|
+
import { VideoTexture } from '../VideoTexture';
|
|
5
|
+
import { createVideoFrameProvider, } from '../../../media/video';
|
|
6
|
+
import { buildDrawTransformMatrix } from './drawRect';
|
|
7
|
+
export { buildTransformMatrixFromRect, resolveTransformRect, resolveDrawRect, buildDrawTransformMatrix, } from './drawRect';
|
|
8
|
+
export function buildVideoTransformMatrix(item, stageWidth, stageHeight, contentWidth, contentHeight) {
|
|
9
|
+
return buildDrawTransformMatrix(item.transform, stageWidth, stageHeight, contentWidth, contentHeight);
|
|
10
|
+
}
|
|
11
|
+
export class VideoLayer {
|
|
12
|
+
constructor(pool, providerFactoryOrDeps) {
|
|
13
|
+
this._program = null;
|
|
14
|
+
this._vao = null;
|
|
15
|
+
this._gl = null;
|
|
16
|
+
this._providers = new Map();
|
|
17
|
+
this._textures = new Map();
|
|
18
|
+
this._srcByItemId = new Map();
|
|
19
|
+
this._contentSizeByItemId = new Map();
|
|
20
|
+
this._lastLoggedSourceFrameByItemId = new Map();
|
|
21
|
+
this._holdoverTexture = null;
|
|
22
|
+
this._pool = pool;
|
|
23
|
+
if (typeof providerFactoryOrDeps === 'function') {
|
|
24
|
+
this._providerFactory = providerFactoryOrDeps;
|
|
25
|
+
this._deps = undefined;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
this._deps = providerFactoryOrDeps;
|
|
29
|
+
this._providerFactory = (src) => createVideoFrameProvider(src, this._deps);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
acquire(item, ctx) {
|
|
33
|
+
const { gl } = ctx;
|
|
34
|
+
this._gl = gl;
|
|
35
|
+
this._ensurePipeline(gl);
|
|
36
|
+
this._textures.set(item.id, new VideoTexture(this._pool));
|
|
37
|
+
this._srcByItemId.set(item.id, item.src);
|
|
38
|
+
let entry = this._providers.get(item.id);
|
|
39
|
+
if (!entry) {
|
|
40
|
+
const provider = this._deps
|
|
41
|
+
? createVideoFrameProvider(item.src, { ...this._deps, fps: ctx.fps })
|
|
42
|
+
: this._providerFactory(item.src);
|
|
43
|
+
entry = { provider, refCount: 0 };
|
|
44
|
+
this._providers.set(item.id, entry);
|
|
45
|
+
}
|
|
46
|
+
entry.refCount++;
|
|
47
|
+
entry.provider.markActive();
|
|
48
|
+
}
|
|
49
|
+
release(itemId) {
|
|
50
|
+
const src = this._srcByItemId.get(itemId);
|
|
51
|
+
if (!src)
|
|
52
|
+
return;
|
|
53
|
+
const texture = this._textures.get(itemId);
|
|
54
|
+
if (texture?.hasContent) {
|
|
55
|
+
this._holdoverTexture?.dispose();
|
|
56
|
+
this._holdoverTexture = texture;
|
|
57
|
+
}
|
|
58
|
+
else {
|
|
59
|
+
texture?.dispose();
|
|
60
|
+
}
|
|
61
|
+
this._textures.delete(itemId);
|
|
62
|
+
this._srcByItemId.delete(itemId);
|
|
63
|
+
this._contentSizeByItemId.delete(itemId);
|
|
64
|
+
this._lastLoggedSourceFrameByItemId.delete(itemId);
|
|
65
|
+
const entry = this._providers.get(itemId);
|
|
66
|
+
if (!entry)
|
|
67
|
+
return;
|
|
68
|
+
entry.refCount--;
|
|
69
|
+
if (entry.refCount <= 0) {
|
|
70
|
+
entry.refCount = 0;
|
|
71
|
+
entry.provider.markIdle();
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
draw(item, ctx) {
|
|
75
|
+
this._gl = ctx.gl;
|
|
76
|
+
const texture = this._textures.get(item.id);
|
|
77
|
+
const entry = this._providers.get(item.id);
|
|
78
|
+
if (!texture || !entry)
|
|
79
|
+
return;
|
|
80
|
+
const { provider } = entry;
|
|
81
|
+
provider.setPlayhead(item.sourceFrame);
|
|
82
|
+
const frame = provider.getCurrent(item.sourceFrame);
|
|
83
|
+
if (frame !== null) {
|
|
84
|
+
const uploaded = texture.upload(ctx.gl, frame);
|
|
85
|
+
if (uploaded) {
|
|
86
|
+
const width = 'displayWidth' in frame ? frame.displayWidth : frame.width;
|
|
87
|
+
const height = 'displayHeight' in frame ? frame.displayHeight : frame.height;
|
|
88
|
+
this._contentSizeByItemId.set(item.id, { width, height });
|
|
89
|
+
this._holdoverTexture?.dispose();
|
|
90
|
+
this._holdoverTexture = null;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
if (!this._program || !this._vao)
|
|
94
|
+
return;
|
|
95
|
+
const contentSize = this._contentSizeByItemId.get(item.id);
|
|
96
|
+
const opacity = item.opacity ?? 1;
|
|
97
|
+
this._program.use(ctx.gl);
|
|
98
|
+
ctx.gl.bindVertexArray(this._vao);
|
|
99
|
+
let unit = texture.bind(ctx.gl, 0);
|
|
100
|
+
if (unit < 0 && this._holdoverTexture !== null) {
|
|
101
|
+
unit = this._holdoverTexture.bind(ctx.gl, 0);
|
|
102
|
+
}
|
|
103
|
+
if (unit < 0)
|
|
104
|
+
return;
|
|
105
|
+
this._program.setUniform1i(ctx.gl, 'uTexture', unit);
|
|
106
|
+
this._program.setUniform1f(ctx.gl, 'uOpacity', opacity);
|
|
107
|
+
this._program.setUniformMatrix3fv(ctx.gl, 'uTransform', false, buildVideoTransformMatrix(item, ctx.stage.width, ctx.stage.height, contentSize?.width, contentSize?.height));
|
|
108
|
+
ctx.gl.drawArrays(ctx.gl.TRIANGLE_STRIP, 0, 4);
|
|
109
|
+
ctx.gl.bindTexture(ctx.gl.TEXTURE_2D, null);
|
|
110
|
+
ctx.gl.bindVertexArray(null);
|
|
111
|
+
}
|
|
112
|
+
dispose() {
|
|
113
|
+
for (const texture of this._textures.values()) {
|
|
114
|
+
texture.dispose();
|
|
115
|
+
}
|
|
116
|
+
this._textures.clear();
|
|
117
|
+
this._srcByItemId.clear();
|
|
118
|
+
this._contentSizeByItemId.clear();
|
|
119
|
+
this._holdoverTexture?.dispose();
|
|
120
|
+
this._holdoverTexture = null;
|
|
121
|
+
for (const entry of this._providers.values()) {
|
|
122
|
+
entry.provider.dispose();
|
|
123
|
+
}
|
|
124
|
+
this._providers.clear();
|
|
125
|
+
if (this._gl) {
|
|
126
|
+
if (this._vao)
|
|
127
|
+
this._gl.deleteVertexArray(this._vao);
|
|
128
|
+
if (this._program)
|
|
129
|
+
this._program.dispose(this._gl);
|
|
130
|
+
}
|
|
131
|
+
this._program = null;
|
|
132
|
+
this._vao = null;
|
|
133
|
+
this._gl = null;
|
|
134
|
+
}
|
|
135
|
+
notifyContextLost() {
|
|
136
|
+
for (const texture of this._textures.values()) {
|
|
137
|
+
texture.handleContextLost();
|
|
138
|
+
}
|
|
139
|
+
this._holdoverTexture?.handleContextLost();
|
|
140
|
+
this._holdoverTexture = null;
|
|
141
|
+
this._program = null;
|
|
142
|
+
this._vao = null;
|
|
143
|
+
this._gl = null;
|
|
144
|
+
}
|
|
145
|
+
disposeGL(gl) {
|
|
146
|
+
for (const texture of this._textures.values()) {
|
|
147
|
+
texture.dispose();
|
|
148
|
+
}
|
|
149
|
+
if (this._vao)
|
|
150
|
+
gl.deleteVertexArray(this._vao);
|
|
151
|
+
if (this._program)
|
|
152
|
+
this._program.dispose(gl);
|
|
153
|
+
this.dispose();
|
|
154
|
+
}
|
|
155
|
+
getProviderForItemId(itemId) {
|
|
156
|
+
return this._providers.get(itemId)?.provider;
|
|
157
|
+
}
|
|
158
|
+
getProviderForSrc(src) {
|
|
159
|
+
for (const [itemId, itemSrc] of this._srcByItemId) {
|
|
160
|
+
if (itemSrc === src)
|
|
161
|
+
return this._providers.get(itemId)?.provider;
|
|
162
|
+
}
|
|
163
|
+
return undefined;
|
|
164
|
+
}
|
|
165
|
+
getProviderRefCount(itemId) {
|
|
166
|
+
return this._providers.get(itemId)?.refCount ?? 0;
|
|
167
|
+
}
|
|
168
|
+
getTextureCount() {
|
|
169
|
+
return this._textures.size;
|
|
170
|
+
}
|
|
171
|
+
getProviderCount() {
|
|
172
|
+
return this._providers.size;
|
|
173
|
+
}
|
|
174
|
+
getDecoderStates() {
|
|
175
|
+
const out = {};
|
|
176
|
+
for (const [src, entry] of this._providers) {
|
|
177
|
+
const provider = entry.provider;
|
|
178
|
+
if (typeof provider.decoderState === 'string') {
|
|
179
|
+
out[src] = provider.decoderState;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return out;
|
|
183
|
+
}
|
|
184
|
+
_ensurePipeline(gl) {
|
|
185
|
+
if (this._program && this._vao)
|
|
186
|
+
return;
|
|
187
|
+
this._program = ShaderProgram.create(gl, QUAD_VERT_SRC, QUAD_FRAG_SRC);
|
|
188
|
+
const vao = gl.createVertexArray();
|
|
189
|
+
if (!vao) {
|
|
190
|
+
throw new Error('VideoLayer: gl.createVertexArray() returned null');
|
|
191
|
+
}
|
|
192
|
+
this._vao = vao;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Transform } from '../../../types';
|
|
2
|
+
export interface DrawRect {
|
|
3
|
+
x: number;
|
|
4
|
+
y: number;
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
rotation: number;
|
|
8
|
+
}
|
|
9
|
+
export declare function buildTransformMatrixFromRect(rect: DrawRect, stageWidth: number, stageHeight: number): Float32Array;
|
|
10
|
+
export declare function resolveTransformRect(transform: Transform, stageWidth: number, stageHeight: number, contentWidth: number, contentHeight: number): DrawRect;
|
|
11
|
+
export declare function resolveDrawRect(transform: Transform | undefined, stageWidth: number, stageHeight: number, contentWidth?: number, contentHeight?: number): DrawRect;
|
|
12
|
+
export declare function transformFromContainRect(contentWidth: number, contentHeight: number, stageWidth: number, stageHeight: number): Transform;
|
|
13
|
+
export declare function buildDrawTransformMatrix(transform: Transform | undefined, stageWidth: number, stageHeight: number, contentWidth?: number, contentHeight?: number): Float32Array;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { computeContainRect } from './objectFit';
|
|
2
|
+
export function buildTransformMatrixFromRect(rect, stageWidth, stageHeight) {
|
|
3
|
+
const xs = rect.x / stageWidth;
|
|
4
|
+
const ys = rect.y / stageHeight;
|
|
5
|
+
const ws = rect.width / stageWidth;
|
|
6
|
+
const hs = rect.height / stageHeight;
|
|
7
|
+
const rotation = rect.rotation;
|
|
8
|
+
const sc = Math.cos(rotation);
|
|
9
|
+
const ss = Math.sin(rotation);
|
|
10
|
+
const tx = 2 * (xs + ws / 2 - 0.5 * sc * ws + 0.5 * ss * hs) - 1;
|
|
11
|
+
const ty = 2 * (ys + hs / 2 - 0.5 * ss * ws - 0.5 * sc * hs) - 1;
|
|
12
|
+
return new Float32Array([
|
|
13
|
+
2 * sc * ws, 2 * ss * ws, 0,
|
|
14
|
+
-2 * ss * hs, 2 * sc * hs, 0,
|
|
15
|
+
tx, ty, 1,
|
|
16
|
+
]);
|
|
17
|
+
}
|
|
18
|
+
export function resolveTransformRect(transform, stageWidth, stageHeight, contentWidth, contentHeight) {
|
|
19
|
+
const width = contentWidth * transform.scale;
|
|
20
|
+
const height = contentHeight * transform.scale;
|
|
21
|
+
const anchorPxX = transform.anchor.x * width;
|
|
22
|
+
const anchorPxY = transform.anchor.y * height;
|
|
23
|
+
const x = transform.x * stageWidth - anchorPxX;
|
|
24
|
+
const y = transform.y * stageHeight - anchorPxY;
|
|
25
|
+
return {
|
|
26
|
+
x,
|
|
27
|
+
y,
|
|
28
|
+
width,
|
|
29
|
+
height,
|
|
30
|
+
rotation: transform.rotation,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
export function resolveDrawRect(transform, stageWidth, stageHeight, contentWidth, contentHeight) {
|
|
34
|
+
if (!transform) {
|
|
35
|
+
if (contentWidth && contentHeight) {
|
|
36
|
+
const fit = computeContainRect(contentWidth, contentHeight, stageWidth, stageHeight);
|
|
37
|
+
return { x: fit.x, y: fit.y, width: fit.width, height: fit.height, rotation: 0 };
|
|
38
|
+
}
|
|
39
|
+
return { x: 0, y: 0, width: stageWidth, height: stageHeight, rotation: 0 };
|
|
40
|
+
}
|
|
41
|
+
return resolveTransformRect(transform, stageWidth, stageHeight, contentWidth ?? stageWidth, contentHeight ?? stageHeight);
|
|
42
|
+
}
|
|
43
|
+
export function transformFromContainRect(contentWidth, contentHeight, stageWidth, stageHeight) {
|
|
44
|
+
const fit = computeContainRect(contentWidth, contentHeight, stageWidth, stageHeight);
|
|
45
|
+
return {
|
|
46
|
+
x: stageWidth > 0 ? (fit.x + fit.width / 2) / stageWidth : 0.5,
|
|
47
|
+
y: stageHeight > 0 ? (fit.y + fit.height / 2) / stageHeight : 0.5,
|
|
48
|
+
scale: contentWidth > 0 ? fit.width / contentWidth : 1,
|
|
49
|
+
rotation: 0,
|
|
50
|
+
anchor: { x: 0.5, y: 0.5 },
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export function buildDrawTransformMatrix(transform, stageWidth, stageHeight, contentWidth, contentHeight) {
|
|
54
|
+
return buildTransformMatrixFromRect(resolveDrawRect(transform, stageWidth, stageHeight, contentWidth, contentHeight), stageWidth, stageHeight);
|
|
55
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function computeContainRect(contentWidth, contentHeight, stageWidth, stageHeight) {
|
|
2
|
+
if (contentWidth <= 0 ||
|
|
3
|
+
contentHeight <= 0 ||
|
|
4
|
+
stageWidth <= 0 ||
|
|
5
|
+
stageHeight <= 0) {
|
|
6
|
+
return { x: 0, y: 0, width: Math.max(stageWidth, 0), height: Math.max(stageHeight, 0) };
|
|
7
|
+
}
|
|
8
|
+
const stageAspect = stageWidth / stageHeight;
|
|
9
|
+
const contentAspect = contentWidth / contentHeight;
|
|
10
|
+
let width;
|
|
11
|
+
let height;
|
|
12
|
+
if (stageAspect > contentAspect) {
|
|
13
|
+
height = stageHeight;
|
|
14
|
+
width = height * contentAspect;
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
width = stageWidth;
|
|
18
|
+
height = width / contentAspect;
|
|
19
|
+
}
|
|
20
|
+
return {
|
|
21
|
+
x: (stageWidth - width) / 2,
|
|
22
|
+
y: (stageHeight - height) / 2,
|
|
23
|
+
width,
|
|
24
|
+
height,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import type { ActiveTextClip } from '../../../resolver/scene';
|
|
2
|
+
export declare const DEFAULT_FONT_SIZE = 48;
|
|
3
|
+
export declare const DEFAULT_COLOR = "#ffffff";
|
|
4
|
+
export declare const DEFAULT_FONT_FAMILY = "sans-serif";
|
|
5
|
+
export declare const DEFAULT_FONT_WEIGHT: 'normal' | 'bold';
|
|
6
|
+
export declare const DEFAULT_TEXT_ALIGN: 'left' | 'center' | 'right';
|
|
7
|
+
export declare const SIDE_MARGIN = 0.05;
|
|
8
|
+
export declare const LINE_HEIGHT = 1.2;
|
|
9
|
+
export type TextMeasurer = Pick<CanvasRenderingContext2D, 'font' | 'measureText'>;
|
|
10
|
+
export interface ResolvedTextStyle {
|
|
11
|
+
fontSize: number;
|
|
12
|
+
color: string;
|
|
13
|
+
fontFamily: string;
|
|
14
|
+
fontWeight: 'normal' | 'bold';
|
|
15
|
+
textAlign: 'left' | 'center' | 'right';
|
|
16
|
+
}
|
|
17
|
+
export interface StageRect {
|
|
18
|
+
x: number;
|
|
19
|
+
y: number;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
}
|
|
23
|
+
export interface TextLayout {
|
|
24
|
+
style: ResolvedTextStyle;
|
|
25
|
+
font: string;
|
|
26
|
+
lines: string[];
|
|
27
|
+
lineAdvance: number;
|
|
28
|
+
anchorX: number;
|
|
29
|
+
firstLineY: number;
|
|
30
|
+
box: StageRect;
|
|
31
|
+
center: {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
export declare function resolveTextStyle(item: {
|
|
37
|
+
fontSize?: number;
|
|
38
|
+
color?: string;
|
|
39
|
+
fontFamily?: string;
|
|
40
|
+
fontWeight?: 'normal' | 'bold';
|
|
41
|
+
textAlign?: 'left' | 'center' | 'right';
|
|
42
|
+
}): ResolvedTextStyle;
|
|
43
|
+
export declare function wrapText(measure: TextMeasurer, text: string, maxWidth: number): string[];
|
|
44
|
+
export declare function computeTextLayout(measure: TextMeasurer, item: Pick<ActiveTextClip, 'content' | 'transform'> & Partial<ResolvedTextStyle>, stage: {
|
|
45
|
+
width: number;
|
|
46
|
+
height: number;
|
|
47
|
+
}): TextLayout;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export const DEFAULT_FONT_SIZE = 48;
|
|
2
|
+
export const DEFAULT_COLOR = '#ffffff';
|
|
3
|
+
export const DEFAULT_FONT_FAMILY = 'sans-serif';
|
|
4
|
+
export const DEFAULT_FONT_WEIGHT = 'normal';
|
|
5
|
+
export const DEFAULT_TEXT_ALIGN = 'center';
|
|
6
|
+
export const SIDE_MARGIN = 0.05;
|
|
7
|
+
export const LINE_HEIGHT = 1.2;
|
|
8
|
+
export function resolveTextStyle(item) {
|
|
9
|
+
return {
|
|
10
|
+
fontSize: item.fontSize ?? DEFAULT_FONT_SIZE,
|
|
11
|
+
color: item.color ?? DEFAULT_COLOR,
|
|
12
|
+
fontFamily: item.fontFamily ?? DEFAULT_FONT_FAMILY,
|
|
13
|
+
fontWeight: item.fontWeight ?? DEFAULT_FONT_WEIGHT,
|
|
14
|
+
textAlign: item.textAlign ?? DEFAULT_TEXT_ALIGN,
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
export function wrapText(measure, text, maxWidth) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const paragraph of text.split('\n')) {
|
|
20
|
+
const words = paragraph.split(' ');
|
|
21
|
+
let line = '';
|
|
22
|
+
for (const word of words) {
|
|
23
|
+
const candidate = line ? `${line} ${word}` : word;
|
|
24
|
+
if (line && measure.measureText(candidate).width > maxWidth) {
|
|
25
|
+
out.push(line);
|
|
26
|
+
line = word;
|
|
27
|
+
}
|
|
28
|
+
else {
|
|
29
|
+
line = candidate;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
out.push(line);
|
|
33
|
+
}
|
|
34
|
+
return out;
|
|
35
|
+
}
|
|
36
|
+
export function computeTextLayout(measure, item, stage) {
|
|
37
|
+
const style = resolveTextStyle(item);
|
|
38
|
+
const scale = item.transform?.scale ?? 1;
|
|
39
|
+
if (scale !== 1)
|
|
40
|
+
style.fontSize *= scale;
|
|
41
|
+
const font = `${style.fontWeight} ${style.fontSize}px ${style.fontFamily}`;
|
|
42
|
+
measure.font = font;
|
|
43
|
+
const maxWidth = stage.width * (1 - 2 * SIDE_MARGIN);
|
|
44
|
+
const lines = wrapText(measure, item.content, maxWidth);
|
|
45
|
+
const lineAdvance = style.fontSize * LINE_HEIGHT;
|
|
46
|
+
const blockHeight = lines.length * lineAdvance;
|
|
47
|
+
let maxLineWidth = 0;
|
|
48
|
+
for (const line of lines) {
|
|
49
|
+
const w = measure.measureText(line).width;
|
|
50
|
+
if (w > maxLineWidth)
|
|
51
|
+
maxLineWidth = w;
|
|
52
|
+
}
|
|
53
|
+
const center = {
|
|
54
|
+
x: item.transform ? item.transform.x : 0.5,
|
|
55
|
+
y: item.transform ? item.transform.y : 0.5,
|
|
56
|
+
};
|
|
57
|
+
const centerX = center.x * stage.width;
|
|
58
|
+
const centerY = center.y * stage.height;
|
|
59
|
+
const boxX = centerX - maxLineWidth / 2;
|
|
60
|
+
const boxY = centerY - blockHeight / 2;
|
|
61
|
+
let anchorX;
|
|
62
|
+
if (style.textAlign === 'left') {
|
|
63
|
+
anchorX = boxX;
|
|
64
|
+
}
|
|
65
|
+
else if (style.textAlign === 'right') {
|
|
66
|
+
anchorX = boxX + maxLineWidth;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
anchorX = centerX;
|
|
70
|
+
}
|
|
71
|
+
const firstLineY = boxY + lineAdvance / 2;
|
|
72
|
+
return {
|
|
73
|
+
style,
|
|
74
|
+
font,
|
|
75
|
+
lines,
|
|
76
|
+
lineAdvance,
|
|
77
|
+
anchorX,
|
|
78
|
+
firstLineY,
|
|
79
|
+
box: { x: boxX, y: boxY, width: maxLineWidth, height: blockHeight },
|
|
80
|
+
center,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
export interface LayerContext {
|
|
2
|
+
gl: WebGL2RenderingContext;
|
|
3
|
+
stage: {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
};
|
|
7
|
+
viewport: {
|
|
8
|
+
width: number;
|
|
9
|
+
height: number;
|
|
10
|
+
};
|
|
11
|
+
fps: number;
|
|
12
|
+
}
|
|
13
|
+
export interface Layer<TItem = unknown> {
|
|
14
|
+
acquire(item: TItem, ctx: LayerContext): void;
|
|
15
|
+
release(itemId: string): void;
|
|
16
|
+
draw(item: TItem, ctx: LayerContext): void;
|
|
17
|
+
dispose(): void;
|
|
18
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const QUAD_FRAG_SRC = "#version 300 es\nprecision mediump float;\n\nuniform sampler2D uTexture;\nuniform float uOpacity;\n\nin vec2 vTexCoord;\nout vec4 fragColor;\n\nvoid main() {\n vec4 texel = texture(uTexture, vTexCoord);\n fragColor = vec4(texel.rgb * uOpacity, texel.a * uOpacity);\n}\n";
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const QUAD_FRAG_SRC = `#version 300 es
|
|
2
|
+
precision mediump float;
|
|
3
|
+
|
|
4
|
+
uniform sampler2D uTexture;
|
|
5
|
+
uniform float uOpacity;
|
|
6
|
+
|
|
7
|
+
in vec2 vTexCoord;
|
|
8
|
+
out vec4 fragColor;
|
|
9
|
+
|
|
10
|
+
void main() {
|
|
11
|
+
vec4 texel = texture(uTexture, vTexCoord);
|
|
12
|
+
fragColor = vec4(texel.rgb * uOpacity, texel.a * uOpacity);
|
|
13
|
+
}
|
|
14
|
+
`;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const QUAD_VERT_SRC = "#version 300 es\nprecision highp float;\n\n// Positions for a unit quad in normalized stage space (0..1, origin top-left).\n// Laid out for TRIANGLE_STRIP: TL, BL, TR, BR.\nconst vec2 POSITIONS[4] = vec2[4](\n vec2(0.0, 0.0),\n vec2(0.0, 1.0),\n vec2(1.0, 0.0),\n vec2(1.0, 1.0)\n);\n\n// 3\u00D73 column-major transform: maps normalized stage coords \u2192 clip space.\n// Built by the CPU from the clip's Transform + stage/viewport geometry.\nuniform mat3 uTransform;\n\nout vec2 vTexCoord;\n\nvoid main() {\n vec2 pos = POSITIONS[gl_VertexID];\n vTexCoord = vec2(pos.x, 1.0 - pos.y); // flip Y for GL texture convention\n\n // Homogeneous multiply, then convert to clip space: stage Y is top-down,\n // GL NDC is bottom-up, so we negate the Y component produced by the matrix.\n vec3 ndc = uTransform * vec3(pos, 1.0);\n gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);\n}\n";
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const QUAD_VERT_SRC = `#version 300 es
|
|
2
|
+
precision highp float;
|
|
3
|
+
|
|
4
|
+
// Positions for a unit quad in normalized stage space (0..1, origin top-left).
|
|
5
|
+
// Laid out for TRIANGLE_STRIP: TL, BL, TR, BR.
|
|
6
|
+
const vec2 POSITIONS[4] = vec2[4](
|
|
7
|
+
vec2(0.0, 0.0),
|
|
8
|
+
vec2(0.0, 1.0),
|
|
9
|
+
vec2(1.0, 0.0),
|
|
10
|
+
vec2(1.0, 1.0)
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
// 3×3 column-major transform: maps normalized stage coords → clip space.
|
|
14
|
+
// Built by the CPU from the clip's Transform + stage/viewport geometry.
|
|
15
|
+
uniform mat3 uTransform;
|
|
16
|
+
|
|
17
|
+
out vec2 vTexCoord;
|
|
18
|
+
|
|
19
|
+
void main() {
|
|
20
|
+
vec2 pos = POSITIONS[gl_VertexID];
|
|
21
|
+
vTexCoord = vec2(pos.x, 1.0 - pos.y); // flip Y for GL texture convention
|
|
22
|
+
|
|
23
|
+
// Homogeneous multiply, then convert to clip space: stage Y is top-down,
|
|
24
|
+
// GL NDC is bottom-up, so we negate the Y component produced by the matrix.
|
|
25
|
+
vec3 ndc = uTransform * vec3(pos, 1.0);
|
|
26
|
+
gl_Position = vec4(ndc.x, -ndc.y, 0.0, 1.0);
|
|
27
|
+
}
|
|
28
|
+
`;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { VideoFrameProviderFactory } from './layers/VideoLayer';
|
|
2
|
+
import type { DemuxerFactory } from '../../media/video/demuxer/MediabunnyDemuxer';
|
|
3
|
+
import type { VideoDecoderFactory } from '../../media/video/VideoDecoderManager';
|
|
4
|
+
export interface Viewport {
|
|
5
|
+
width: number;
|
|
6
|
+
height: number;
|
|
7
|
+
}
|
|
8
|
+
export interface RendererOptions {
|
|
9
|
+
maxTextures?: number;
|
|
10
|
+
clearColor?: [number, number, number, number];
|
|
11
|
+
providerFactory?: VideoFrameProviderFactory;
|
|
12
|
+
demuxerFactory?: DemuxerFactory;
|
|
13
|
+
decoderFactory?: VideoDecoderFactory;
|
|
14
|
+
maxOutstandingDecodes?: number;
|
|
15
|
+
preserveDrawingBuffer?: boolean;
|
|
16
|
+
probeLayer?: boolean;
|
|
17
|
+
}
|
|
18
|
+
export interface SceneDiff<TItem> {
|
|
19
|
+
entering: TItem[];
|
|
20
|
+
leaving: string[];
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function computeContainViewport(canvasWidth, canvasHeight, stageWidth, stageHeight) {
|
|
2
|
+
if (canvasWidth <= 0 ||
|
|
3
|
+
canvasHeight <= 0 ||
|
|
4
|
+
stageWidth <= 0 ||
|
|
5
|
+
stageHeight <= 0) {
|
|
6
|
+
return {
|
|
7
|
+
x: 0,
|
|
8
|
+
y: 0,
|
|
9
|
+
width: Math.max(canvasWidth, 0),
|
|
10
|
+
height: Math.max(canvasHeight, 0),
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
const canvasAspect = canvasWidth / canvasHeight;
|
|
14
|
+
const stageAspect = stageWidth / stageHeight;
|
|
15
|
+
let width;
|
|
16
|
+
let height;
|
|
17
|
+
if (canvasAspect > stageAspect) {
|
|
18
|
+
height = canvasHeight;
|
|
19
|
+
width = height * stageAspect;
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
width = canvasWidth;
|
|
23
|
+
height = width / stageAspect;
|
|
24
|
+
}
|
|
25
|
+
const w = Math.round(width);
|
|
26
|
+
const h = Math.round(height);
|
|
27
|
+
return {
|
|
28
|
+
x: Math.round((canvasWidth - w) / 2),
|
|
29
|
+
y: Math.round((canvasHeight - h) / 2),
|
|
30
|
+
width: w,
|
|
31
|
+
height: h,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|