Add runtime/render related functionality back to VM.

This commit is contained in:
Karishma Chadha 2018-04-26 19:17:41 -04:00
parent 5f4139cbe4
commit 271a19c05d

View file

@ -1,7 +1,42 @@
class Video { class Video {
constructor (runtime) { constructor (runtime) {
this.runtime = runtime; this.runtime = runtime;
/**
* @typedef VideoProvider
* @property {Function} enableVideo - Requests camera access from the user, and upon success,
* enables the video feed
* @property {Function} disableVideo - Turns off the video feed
* @property {Function} getFrame - Return frame data from the video feed in
* specified dimensions, format, and mirroring.
*/
this.provider = null; this.provider = null;
/**
* Id representing a Scratch Renderer skin the video is rendered to for
* previewing.
* @type {number}
*/
this._skinId = -1;
/**
* The Scratch Renderer Skin object.
* @type {Skin}
*/
this._skin = null;
/**
* Id for a drawable using the video's skin that will render as a video
* preview.
* @type {Drawable}
*/
this._drawable = -1;
/**
* Store the last state of the video transparency ghost effect
* @type {number}
*/
this._ghost = 0;
} }
static get FORMAT_IMAGE_DATA () { static get FORMAT_IMAGE_DATA () {
@ -29,6 +64,14 @@ class Video {
return 1; return 1;
} }
/**
* Set a video provider for this device.
* @param {VideoProvider} provider - Video provider to use
*/
setProvider (provider) {
this.provider = provider;
}
/** /**
* Request video be enabled. Sets up video, creates video skin and enables preview. * Request video be enabled. Sets up video, creates video skin and enables preview.
* *
@ -37,8 +80,8 @@ class Video {
* @return {Promise.<Video>} resolves a promise to this IO device when video is ready. * @return {Promise.<Video>} resolves a promise to this IO device when video is ready.
*/ */
enableVideo () { enableVideo () {
if (this.provider) return this.provider.enableVideo(); if (!this.provider) return null;
return null; return this.provider.enableVideo().then(() => this._setupPreview());
} }
/** /**
@ -46,8 +89,9 @@ class Video {
* @return {void} * @return {void}
*/ */
disableVideo () { disableVideo () {
if (this.provider) return this.provider.disableVideo(); if (!this.provider) return null;
return null; this._disablePreview();
this.provider.disableVideo();
} }
/** /**
@ -79,36 +123,75 @@ class Video {
/** /**
* Set the preview ghost effect * Set the preview ghost effect
* @param {number} ghost from 0 (visible) to 100 (invisible) - ghost effect * @param {number} ghost from 0 (visible) to 100 (invisible) - ghost effect
* @return {void}
*/ */
setPreviewGhost (ghost) { setPreviewGhost (ghost) {
if (this.provider) return this.provider.setPreviewGhost(ghost); this._ghost = ghost;
return null; if (this._drawable) {
this.runtime.renderer.updateDrawableProperties(this._drawable, {ghost});
}
}
_disablePreview () {
if (this._skin) {
this._skin.clear();
this.runtime.renderer.updateDrawableProperties(this._drawable, {visible: false});
}
this._renderPreviewFrame = null;
}
_setupPreview () {
const {renderer} = this.runtime;
if (!renderer) return;
if (this._skinId === -1 && this._skin === null && this._drawable === -1) {
this._skinId = renderer.createPenSkin();
this._skin = renderer._allSkins[this._skinId];
this._drawable = renderer.createDrawable();
renderer.setDrawableOrder(
this._drawable,
Video.ORDER
);
renderer.updateDrawableProperties(this._drawable, {
skinId: this._skinId
});
}
// if we haven't already created and started a preview frame render loop, do so
if (!this._renderPreviewFrame) {
renderer.updateDrawableProperties(this._drawable, {
ghost: this._ghost,
visible: true
});
this._renderPreviewFrame = () => {
clearTimeout(this._renderPreviewTimeout);
if (!this._renderPreviewFrame) {
return;
}
this._renderPreviewTimeout = setTimeout(this._renderPreviewFrame, this.runtime.currentStepTime);
const canvas = this.getFrame({format: Video.FORMAT_CANVAS});
if (!canvas) {
this._skin.clear();
return;
}
const xOffset = Video.DIMENSIONS[0] / -2;
const yOffset = Video.DIMENSIONS[1] / 2;
this._skin.drawStamp(canvas, xOffset, yOffset);
this.runtime.requestRedraw();
};
this._renderPreviewFrame();
}
} }
get videoReady () { get videoReady () {
if (this.provider) return this.provider.videoReady(); if (this.provider) return this.provider.videoReady;
return false; return false;
} }
/**
* @typedef VideoProvider
* @property {Function} enableVideo - Requests camera access from the user, and upon success,
* enables the video feed
* @property {Function} disableVideo - Turns off the video feed
* @property {Function} setGhostPreview - Controls the transparency of a visual layer
* over the video feed
* @property {Function} getFrame - Return frame data from the video feed in
* specified dimensions, format, and mirroring.
*/
/**
* Set a video provider for this device.
* @param {VideoProvider} provider - Video provider to use
*/
setProvider (provider) {
this.provider = provider;
}
} }