New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor engine #181

Merged
merged 13 commits into from Sep 24, 2018

Refactor keyframe calculation

  • Loading branch information...
ra-gg committed Sep 24, 2018
commit 9f3eb186cd60ad70b21aded7b42737407d735cda
@@ -358,9 +358,7 @@ export default class Engine
_.each(clipRenderTask.effectRenderTask, task => {
if (task.effectEntity.referenceName == null) return
referenceableEffectParams[task.effectEntity.referenceName] = _.fromPairs(task.effectorParams.properties.map(desc => {
return [desc.paramName, task.keyframeLUT[desc.paramName][baseContext.frame]]
}))
referenceableEffectParams[task.effectEntity.referenceName] = task.keyframeTable.getParametersAt(baseContext.frame)
})
for (const effectRenderTask of effects) {
@@ -437,23 +435,20 @@ export default class Engine
destAudioBuffer: channelAudioBuffers,
})
// Lookup current frame prop value from pre-calculated lookup-table
const beforeExpressionParams = _.fromPairs(clipTask.rendererParams.properties.map(desc => {
return [desc.paramName, clipTask.keyframeLUT[desc.paramName][context.frame]]
}))
// Lookup before apply expression referenceable effect params expression
const referenceableEffectParams: ExpressionContext.ReferenceableEffectsParams = Object.create(null)
_.each(clipTask.effectRenderTask, task => {
if (task.effectEntity.referenceName == null) return
referenceableEffectParams[task.effectEntity.referenceName] = _.fromPairs(task.effectorParams.properties.map(desc => {
return [desc.paramName, task.keyframeLUT[desc.paramName][context.frame]]
}))
referenceableEffectParams[task.effectEntity.referenceName] = task.keyframeTable.getParametersAt(context.frame)
})
// Apply expression
const afterExpressionParams = applyExpression(clipRenderContext, beforeExpressionParams, referenceableEffectParams, clipTask.expressions)
const beforeClipExpressionParams = clipTask.keyframeTable.getParametersAt(context.frame)
const afterExpressionParams = clipTask.keyframeTable.getParameterWithExpressionAt(context.frame, {
context: clipRenderContext,
clipParams: beforeClipExpressionParams,
referenceableEffectParams,
})
clipRenderContext.parameters = afterExpressionParams
clipRenderContext.clipEffectParams = referenceableEffectParams
@@ -472,12 +467,11 @@ export default class Engine
parameters: {},
})
const beforeExpressionEffectorParams = _.fromPairs(effectTask.effectorParams.properties.map(desc => {
return [desc.paramName, effectTask.keyframeLUT[desc.paramName][context.frame]]
})) as {[paramName: string]: ParameterValueTypes}
const afterExpressionEffectorParams = applyExpression(clipRenderContext, beforeExpressionEffectorParams, referenceableEffectParams, effectTask.expressions)
effectRenderContext.parameters = afterExpressionEffectorParams
effectRenderContext.parameters = effectTask.keyframeTable.getParameterWithExpressionAt(context.frame, {
context: effectRenderContext,
clipParams: beforeClipExpressionParams,
referenceableEffectParams,
})
await effectTask.effectRenderer.render(effectRenderContext)
@@ -0,0 +1,68 @@
import { Clip, Keyframe } from '../Entity'
import { safeAssign } from '../helper/safeAssign'
import { Expression } from '../Values'
import { ParametersTable } from './ParametersTable'
import { IRenderContextBase } from './RenderContext/IRenderContextBase'
import { RenderContextBase } from './RenderContext/RenderContextBase'
import * as RendererFactory from './renderer'
describe('KeyframeTable', () => {
let context: RenderContextBase
let table: ParametersTable
beforeEach(() => {
context = new RenderContextBase({
durationFrames: 100,
framerate: 50,
} as Partial<IRenderContextBase> as any)
const clip = safeAssign(new Clip(), {
renderer: 'video',
placedFrame: 0,
durationFrames: 100,
keyframes: {
'x': [
safeAssign(new Keyframe(), { frameOnClip: 0, value: 0 }),
safeAssign(new Keyframe(), { frameOnClip: 100, value: 100 }),
],
},
expressions: {
'x': new Expression('typescript', 'ctx.currentValue * 10')
}
})
table = ParametersTable.build(context, clip, clip.keyframes, clip.expressions, RendererFactory.getInfo('text').parameter)
})
it('Should correctly build table', () => {
expect(table.initialParams).toMatchObject({ x: 0 })
expect(table.lookUpTable).toMatchObject({ x: { '0': 0 } })
})
it('Should get parameters', () => {
expect(table.getParametersAt(0)).toMatchObject({ x: 0 })
expect(table.getParametersAt(100)).toMatchObject({ x: 100 })
})
it('Should get parameters with expression', () => {
const frame = 100
const clipRenderContext = context.toClipRenderContext({
parameters: table.getParametersAt(frame),
clipEffectParams: {},
frameOnClip: frame,
timeOnClip: frame / context.framerate,
srcCanvas: null,
destAudioBuffer: null,
destCanvas: null,
})
expect(table.getParameterWithExpressionAt(100, {
context: clipRenderContext,
clipParams: {},
referenceableEffectParams: {}
})).toMatchObject({ x: 1000 })
})
})
@@ -0,0 +1,106 @@
import * as _ from 'lodash'
import { EffectRenderContext } from '..'
import { Clip, Keyframe } from '../Entity'
import { ParameterValueTypes, TypeDescriptor } from '../PluginSupport/type-descriptor'
import { AssetPointer, Expression } from '../Values'
import { RealParameterValues, RealParameterValueTypes } from './Engine'
import { compileTypeScript } from './ExpressionSupport/ExpressionCompiler'
import * as ExpressionContext from './ExpressionSupport/ExpressionContext'
import ExpressionVM from './ExpressionSupport/ExpressionVM'
import * as KeyframeCalcurator from './KeyframeCalcurator'
import { ClipRenderContext } from './RenderContext/ClipRenderContext'
import { RenderContextBase } from './RenderContext/RenderContextBase'
export class ParametersTable {
public static build(
context: RenderContextBase,
clip: Clip,
keyframes: {
[paramName: string]: Keyframe[]
},
expressions: {
[paramName: string]: Expression,
},
paramTypes: TypeDescriptor,
): ParametersTable {
const table = new ParametersTable()
const assetPramNames = paramTypes.properties.filter(prop => prop.type === 'ASSET').map(prop => prop.paramName)
// Calculate initial parameters
const rawRendererInitParam = KeyframeCalcurator.calcKeyframeValuesAt(0, clip.placedFrame, paramTypes, keyframes)
const initialParams: RealParameterValues = { ...(rawRendererInitParam as any) }
assetPramNames.forEach(propName => {
// resolve asset
initialParams[propName] = rawRendererInitParam[propName]
? context.resolver.resolveAsset((rawRendererInitParam[propName] as AssetPointer).assetId)
: null
})
// Calculate look up table
const rawKeyframeLUT = KeyframeCalcurator.calcKeyFrames(paramTypes, keyframes, clip.placedFrame, 0, context.durationFrames)
const lookupTable: { [paramName: string]: { [frame: number]: RealParameterValueTypes } } = { ...(rawKeyframeLUT as any) }
assetPramNames.forEach(paramName => {
// resolve asset
lookupTable[paramName] = _.map(rawKeyframeLUT[paramName], value => {
return value ? context.resolver.resolveAsset((value as AssetPointer).assetId) : null
})
})
// Compile Expression code
const rendererExpressions = _(expressions).mapValues((expr: Expression) => {
const code = compileTypeScript(expr.code)
return (exposes: ExpressionContext.ContextSource) => {
return ExpressionVM.execute(code, ExpressionContext.buildContext(exposes), {filename: `${clip.id}.expression.ts`})
}
}).pickBy(value => value !== null).value()
table.paramTypes = paramTypes
table.initialParams = initialParams
table.lookUpTable = lookupTable
table.expressions = rendererExpressions
return table
}
public initialParams: {
[paramName: string]: RealParameterValueTypes
}
public lookUpTable: {
[paramName: string]: {
[frame: number]: RealParameterValueTypes
}
}
public expressions: {
[paramName: string]: (exposes: ExpressionContext.ContextSource) => any
}
private paramTypes: TypeDescriptor
public getParametersAt(frame: number) {
return _.fromPairs(this.paramTypes.properties.map(desc => {
return [desc.paramName, this.lookUpTable[desc.paramName][frame]]
}))
}
public getParameterWithExpressionAt(frame: number, exposes: {
context: ClipRenderContext<any> | EffectRenderContext<any>,
clipParams: {[paramName: string]: ParameterValueTypes},
referenceableEffectParams: ExpressionContext.ReferenceableEffectsParams,
}) {
const params = this.getParametersAt(frame)
return _.mapValues(params, (value, paramName) => {
if (!this.expressions[paramName]) return value
return this.expressions[paramName]({
context: exposes.context,
clipParams: exposes.clipParams,
clipEffectParams: exposes.referenceableEffectParams,
currentValue: params[paramName],
})
})
}
}
@@ -1,13 +1,8 @@
import * as _ from 'lodash'
import { TypeDescriptor } from '../..'
import { Clip } from '../../Entity'
import { TypeDescriptor } from '../../PluginSupport/type-descriptor'
import { AssetPointer, Expression } from '../../Values'
import { RealParameterValues, RealParameterValueTypes } from '../Engine'
import { compileTypeScript } from '../ExpressionSupport/ExpressionCompiler'
import * as ExpressionContext from '../ExpressionSupport/ExpressionContext'
import ExpressionVM from '../ExpressionSupport/ExpressionVM'
import * as KeyframeHelper from '../KeyframeCalcurator'
import { ParametersTable } from '../ParametersTable'
import { RenderContextBase } from '../RenderContext/RenderContextBase'
import * as RendererFactory from '../Renderer'
import { IRenderer } from '../Renderer/RendererBase'
@@ -20,66 +15,36 @@ export default class ClipRenderTask {
context: RenderContextBase,
}): ClipRenderTask {
const rendererParams = RendererFactory.getInfo(clip.renderer).parameter
const rendererAssetParamNames = rendererParams.properties.filter(prop => prop.type === 'ASSET').map(prop => prop.paramName)
const rawRendererInitParam = KeyframeHelper.calcKeyframeValuesAt(0, clip.placedFrame, rendererParams, clip.keyframes)
const rendererInitParam: RealParameterValues = { ...(rawRendererInitParam as any) }
rendererAssetParamNames.forEach(propName => {
// resolve asset
rendererInitParam[propName] = rawRendererInitParam[propName]
? context.resolver.resolveAsset((rawRendererInitParam[propName] as AssetPointer).assetId)
: null
})
const keyframeTable = ParametersTable.build(context, clip, clip.keyframes, clip.expressions, rendererParams)
let clipRenderer = clipRendererCache.get(clip)
if (!clipRenderer) {
clipRenderer = RendererFactory.create(clip.renderer)
clipRendererCache.set(clip, clipRenderer)
}
const rawRendererKeyframeLUT = KeyframeHelper.calcKeyFrames(rendererParams, clip.keyframes, clip.placedFrame, 0, context.durationFrames)
const rendererKeyframeLUT: { [paramName: string]: { [frame: number]: RealParameterValueTypes } } = { ...(rawRendererKeyframeLUT as any) }
rendererAssetParamNames.forEach(paramName => {
// resolve asset
rendererKeyframeLUT[paramName] = _.map(rawRendererKeyframeLUT[paramName], value => {
return value ? context.resolver.resolveAsset((value as AssetPointer).assetId) : null
})
})
const rendererExpressions = _(clip.expressions).mapValues((expr: Expression) => {
const code = compileTypeScript(expr.code)
return (exposes: ExpressionContext.ContextSource) => {
return ExpressionVM.execute(code, ExpressionContext.buildContext(exposes), {filename: `${clip.id}.expression.ts`})
}
}).pickBy(value => value !== null).value()
const task = new ClipRenderTask()
task.clipRenderer = clipRenderer
task.rendererParams = rendererParams
task.rendererType = clip.renderer
task.clipPlacedFrame = clip.placedFrame
task.clipDurationFrames = clip.durationFrames
task.keyframeLUT = rendererKeyframeLUT
// FIXME: typing
task.expressions = rendererExpressions as any
task.initialKeyframeValues = rendererInitParam
task.paramTypes = rendererParams
task.keyframeTable = keyframeTable
return task
}
public clipRenderer: IRenderer<any>
public rendererParams: TypeDescriptor
public rendererType: RendererFactory.AvailableRenderer
public clipPlacedFrame: number
public clipDurationFrames: number
public keyframeLUT: { [paramName: string]: { [frame: number]: RealParameterValueTypes } }
public expressions: { [paramName: string]: (context: ExpressionContext.ContextSource) => any }
public paramTypes: TypeDescriptor
public effectRenderTask: EffectRenderTask[]
private initialKeyframeValues: RealParameterValues
public keyframeTable: ParametersTable
public async initialize(context: RenderContextBase) {
const preRenderReq = context.toClipPreRenderContext({
parameters: this.initialKeyframeValues
parameters: this.keyframeTable.initialParams
})
await this.clipRenderer.beforeRender(preRenderReq)
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.