mirror of
https://github.com/storytold/artcraft.git
synced 2026-11-15 14:22:14 +00:00
feature / Preview Button (#65)
* preview button done * error if there's no video * fix playing problem with chroma key * fix the problem of videonode unable to play after being processed
This commit is contained in:
8 files changed
+187
-90
No files matched your search
+73
-17
@@ -272,6 +272,18 @@ export class Engine {
|
||||
document.body.style.cursor = "default";
|
||||
return;
|
||||
}
|
||||
case AppModes.PREVIEW: {
|
||||
console.log("APPMODE: RENDER");
|
||||
this.selectorSquare.disable();
|
||||
this.selectionManager.disable();
|
||||
uiAccess.toolbarMain.disable();
|
||||
uiAccess.toolbarMain.changeButtonState(ToolbarMainButtonNames.SELECT, {
|
||||
active: false,
|
||||
});
|
||||
this.matteBox.enable();
|
||||
document.body.style.cursor = "not-allowed";
|
||||
return;
|
||||
}
|
||||
case AppModes.RENDERING: {
|
||||
console.log("APPMODE: RENDER");
|
||||
this.selectorSquare.disable();
|
||||
@@ -426,8 +438,14 @@ export class Engine {
|
||||
uiEvents.toolbarMain.SAVE.onClick(async (/*event*/) => {
|
||||
this.sceneManager.saveScene();
|
||||
});
|
||||
uiEvents.toolbarMain.PREVIEW.onClick(async () => {
|
||||
console.log("Toolbar Main >> Preview");
|
||||
this.setAppMode(AppModes.PREVIEW);
|
||||
await this.handlePreview();
|
||||
this.setAppMode(AppModes.SELECT);
|
||||
});
|
||||
uiEvents.toolbarMain.DOWNLOAD.onClick(async () => {
|
||||
console.log("Toolbar Main Render and Download");
|
||||
console.log("Toolbar Main >> Render Download");
|
||||
try {
|
||||
this.setAppMode(AppModes.RENDERING);
|
||||
await this.renderEngine.startProcessing();
|
||||
@@ -558,30 +576,27 @@ export class Engine {
|
||||
}
|
||||
|
||||
public async setupStage() {
|
||||
var textNode = new Konva.Text({
|
||||
x: 0,
|
||||
y: 0,
|
||||
// Frame rate inicator
|
||||
const textNode = new Konva.Text({
|
||||
x: 5,
|
||||
y: 5,
|
||||
text: "",
|
||||
fontSize: 32,
|
||||
fontFamily: "Calibri",
|
||||
fontFamily: "Source Sans 3",
|
||||
fill: "black",
|
||||
});
|
||||
|
||||
var anim = new Konva.Animation((frame) => {
|
||||
if (frame) {
|
||||
if (import.meta.env.DEV) {
|
||||
const timeDiff = frame.timeDiff;
|
||||
const frameRate = frame.frameRate;
|
||||
textNode.setText(
|
||||
`FrameTime:${timeDiff.toFixed(0)} ms\nFrameRate:${frameRate.toFixed(0)} fps`,
|
||||
);
|
||||
}
|
||||
const anim = new Konva.Animation((frame) => {
|
||||
if (frame && import.meta.env.DEV) {
|
||||
const timeDiff = frame.timeDiff;
|
||||
const frameRate = frame.frameRate;
|
||||
textNode.setText(
|
||||
`FrameTime: ${timeDiff.toFixed(0)} ms\nFrameRate: ${frameRate.toFixed(0)} fps`,
|
||||
);
|
||||
}
|
||||
}, this.mediaLayer);
|
||||
|
||||
anim.start();
|
||||
|
||||
this.uiLayer.add(textNode);
|
||||
|
||||
this.addKeyboardShortcuts();
|
||||
}
|
||||
|
||||
@@ -638,6 +653,47 @@ export class Engine {
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private async handlePreview(): Promise<void> {
|
||||
return new Promise((resolve) => {
|
||||
const allNodes = this.nodesManager.getAllNodes();
|
||||
let longestVideoNode: VideoNode | undefined;
|
||||
allNodes.forEach((node) => {
|
||||
if (node instanceof VideoNode) {
|
||||
node.videoComponent.pause();
|
||||
node.videoComponent.currentTime = 0;
|
||||
if (
|
||||
longestVideoNode === undefined ||
|
||||
node.videoComponent.duration >
|
||||
longestVideoNode.videoComponent.duration
|
||||
) {
|
||||
longestVideoNode = node;
|
||||
}
|
||||
}
|
||||
});
|
||||
const timer = setTimeout(() => {
|
||||
resolve();
|
||||
}, 7000);
|
||||
if (longestVideoNode !== undefined) {
|
||||
longestVideoNode.videoComponent.addEventListener("ended", () => {
|
||||
clearTimeout(timer);
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
// no videonode
|
||||
uiAccess.dialogError.show({
|
||||
title: "No Video Node",
|
||||
message: "You have not yet put a video on the board",
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
allNodes.forEach((node) => {
|
||||
if (node instanceof VideoNode) {
|
||||
node.togglePlay();
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function downloadURI(uri: string, name: string) {
|
||||
|
||||
@@ -41,8 +41,8 @@ export abstract class BaseNode {
|
||||
// Do any other clean up and delete the konva node.
|
||||
this.kNode.destroy();
|
||||
}
|
||||
protected async setProcessing() {
|
||||
this.isProcessing = true;
|
||||
public async setProcessing(val: boolean) {
|
||||
this.isProcessing = val;
|
||||
}
|
||||
public isKEventRef() {
|
||||
return this._isKDragEventListening && this._isKTranformEventListening;
|
||||
|
||||
@@ -152,26 +152,7 @@ export class VideoNode extends NetworkedNode {
|
||||
private listenToVideoPlayPause() {
|
||||
// TODO: for controling video playpause, can be improved with bette ui
|
||||
this.kNode.on("click", () => {
|
||||
// console.log("click");
|
||||
// Shouldn't play if anything things are true
|
||||
if (this.didFinishLoading == false) {
|
||||
return;
|
||||
}
|
||||
if (this.isProcessing == true) {
|
||||
return;
|
||||
}
|
||||
if (this.isSegmentationMode) {
|
||||
// console.log("Not Playing because Segmenting");
|
||||
return;
|
||||
}
|
||||
if (this.videoComponent.paused) {
|
||||
console.log("Playing", this.videoComponent.src);
|
||||
this.videoComponent.play();
|
||||
this.chromaKeyRender(0); // For starting Chroma
|
||||
} else {
|
||||
console.log("Pause", this.videoComponent.src);
|
||||
this.videoComponent.pause();
|
||||
}
|
||||
this.togglePlay();
|
||||
});
|
||||
}
|
||||
private removeLisentoVideoPlayPause() {
|
||||
@@ -296,10 +277,29 @@ export class VideoNode extends NetworkedNode {
|
||||
// TODO: impolement retry
|
||||
}
|
||||
}
|
||||
public togglePlay() {
|
||||
// Shouldn't play in these situations
|
||||
if (this.didFinishLoading == false) {
|
||||
return;
|
||||
}
|
||||
if (this.isProcessing == true) {
|
||||
return;
|
||||
}
|
||||
if (this.isSegmentationMode) {
|
||||
// console.log("Not Playing because Segmenting");
|
||||
return;
|
||||
}
|
||||
|
||||
async setProcessing() {
|
||||
this.isProcessing = true;
|
||||
if (this.videoComponent.paused) {
|
||||
console.log("Playing", this.videoComponent.src);
|
||||
this.videoComponent.play();
|
||||
this.chromaKeyRender(0); // For starting Chroma
|
||||
} else {
|
||||
console.log("Pause", this.videoComponent.src);
|
||||
this.videoComponent.pause();
|
||||
}
|
||||
}
|
||||
|
||||
async reset() {
|
||||
this.videoComponent.pause();
|
||||
await this.seek(0);
|
||||
|
||||
@@ -342,7 +342,7 @@ export class RenderEngine {
|
||||
setTimeout(this.startProcessing.bind(this), 1000);
|
||||
break;
|
||||
}
|
||||
item.setProcessing();
|
||||
item.setProcessing(true);
|
||||
}
|
||||
|
||||
// todo remove
|
||||
@@ -371,14 +371,15 @@ export class RenderEngine {
|
||||
if (!item.kNode) {
|
||||
return;
|
||||
}
|
||||
item.setProcessing(false);
|
||||
item.kNode.listening(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public stopProcessing() {
|
||||
this.isProcessing = false;
|
||||
}
|
||||
// public stopProcessing() {
|
||||
// this.isProcessing = false;
|
||||
// }
|
||||
|
||||
// find the frame time given the frame number
|
||||
private calculateFrameTime(frameNumber: number, frameRate: number): number {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
export enum AppModes {
|
||||
INIT = "INIT",
|
||||
PREVIEW = "PREVIEW",
|
||||
SELECT = "SELECT",
|
||||
RENDERING = "RENDERING",
|
||||
}
|
||||
|
||||
export const VideoResolutions = {
|
||||
VERTICAL_720: { width: 720, height: 1280 },
|
||||
LANDSCAPE_720: { width: 1280, height: 720 },
|
||||
};
|
||||
|
||||
export const Colors = {
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
import { faCameraMovie, faPlayCircle } from "@fortawesome/pro-solid-svg-icons";
|
||||
import { Button, Tooltip } from "~/components/ui";
|
||||
import { ToolbarButtonProps } from "../ToolbarButton";
|
||||
|
||||
export const ButtonPreviewAndRender = ({
|
||||
buttonPreviewProps,
|
||||
buttonRenderProps,
|
||||
}: {
|
||||
buttonPreviewProps: ToolbarButtonProps;
|
||||
buttonRenderProps: ToolbarButtonProps;
|
||||
}) => {
|
||||
return (
|
||||
<div className="flex">
|
||||
<ButtonPreview {...buttonPreviewProps} />
|
||||
<ButtonRender {...buttonRenderProps} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
const ButtonPreview = (buttonProps: ToolbarButtonProps) => {
|
||||
const {
|
||||
className: customButtonClassNames,
|
||||
disabled,
|
||||
active,
|
||||
hidden,
|
||||
onClick,
|
||||
...restButtonProps
|
||||
} = buttonProps;
|
||||
return (
|
||||
<Tooltip tip="Preview">
|
||||
<Button
|
||||
className="text-nowrap rounded-r-none border-r border-white"
|
||||
icon={faPlayCircle}
|
||||
disabled={disabled}
|
||||
{...restButtonProps}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
}}
|
||||
{...restButtonProps}
|
||||
/>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
const ButtonRender = (buttonProps: ToolbarButtonProps) => {
|
||||
const {
|
||||
className: customButtonClassNames,
|
||||
disabled,
|
||||
active,
|
||||
hidden,
|
||||
onClick,
|
||||
...restButtonProps
|
||||
} = buttonProps;
|
||||
return (
|
||||
<Tooltip tip="Click to Finish Movie">
|
||||
<Button
|
||||
className="text-nowrap rounded-l-none"
|
||||
icon={faCameraMovie}
|
||||
disabled={disabled}
|
||||
{...restButtonProps}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
}}
|
||||
{...restButtonProps}
|
||||
>
|
||||
Render Movie
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -6,10 +6,6 @@ import {
|
||||
faArrowRotateLeft,
|
||||
faArrowRotateRight,
|
||||
faBars,
|
||||
faCameraMovie,
|
||||
// faCameraRotate,
|
||||
// faDownload,
|
||||
// faCloudArrowDown,
|
||||
faFilePlus,
|
||||
faFilm,
|
||||
faFloppyDisk,
|
||||
@@ -19,12 +15,12 @@ import {
|
||||
faText,
|
||||
} from "@fortawesome/pro-solid-svg-icons";
|
||||
|
||||
import { ToolbarButton, ToolbarButtonProps } from "../ToolbarButton";
|
||||
import { ToolbarButton } from "../ToolbarButton";
|
||||
|
||||
// style and constants
|
||||
import { paperWrapperStyles, toolTipStyles } from "~/components/styles";
|
||||
import { ToolbarMainButtonNames } from "./enum";
|
||||
import { Button, Tooltip } from "~/components/ui";
|
||||
import { ButtonPreviewAndRender } from "./ButtonPreviewAndRender";
|
||||
|
||||
export const ToolbarMain = ({
|
||||
disabled = false,
|
||||
@@ -92,11 +88,6 @@ export const ToolbarMain = ({
|
||||
</ToolbarButton>
|
||||
</PopoverPanel>
|
||||
</Popover>
|
||||
{/* <ToolbarButton
|
||||
icon={faCameraRotate}
|
||||
buttonProps={buttonProps.CHANGE_CAMERA_ORIENTATION}
|
||||
tooltip="Change Orientation"
|
||||
/> */}
|
||||
<ToolbarButton
|
||||
icon={faHatWizard}
|
||||
buttonProps={buttonProps.AI_STYLIZE}
|
||||
@@ -119,41 +110,12 @@ export const ToolbarMain = ({
|
||||
buttonProps={buttonProps.SAVE}
|
||||
tooltip="Save"
|
||||
/>
|
||||
<DownloadButton {...buttonProps.DOWNLOAD} />
|
||||
<ButtonPreviewAndRender
|
||||
buttonPreviewProps={buttonProps.PREVIEW}
|
||||
buttonRenderProps={buttonProps.DOWNLOAD}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const DownloadButton = (buttonProps: ToolbarButtonProps) => {
|
||||
const {
|
||||
className: customButtonClassNames,
|
||||
disabled,
|
||||
active,
|
||||
hidden,
|
||||
onClick,
|
||||
...restButtonProps
|
||||
} = buttonProps;
|
||||
|
||||
return (
|
||||
<Tooltip tip="Click to Finish Movie">
|
||||
<Button
|
||||
className="text-nowrap"
|
||||
icon={faCameraMovie}
|
||||
disabled={disabled}
|
||||
{...restButtonProps}
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (onClick) {
|
||||
onClick(e);
|
||||
}
|
||||
}}
|
||||
{...restButtonProps}
|
||||
>
|
||||
Render Movie
|
||||
</Button>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
@@ -4,10 +4,10 @@ export enum ToolbarMainButtonNames {
|
||||
ADD_TEXT = "ADD_TEXT",
|
||||
ADD_IMAGE = "ADD_IMAGE",
|
||||
ADD_VIDEO = "ADD_VIDEO",
|
||||
// CHANGE_CAMERA_ORIENTATION = "CHANGE_CAMERA_ORIENTATION",
|
||||
AI_STYLIZE = "AI_STYLIZE",
|
||||
UNDO = "UNDO",
|
||||
REDO = "REDO",
|
||||
SAVE = "SAVE",
|
||||
PREVIEW = "PREVIEW",
|
||||
DOWNLOAD = "DOWNLOAD",
|
||||
}
|
||||
Reference in new issue
Block a user