Compare commits
No commits in common. "c86ff9ef1a2b8cf7e89c892962e8b487aef9f35b" and "5b0635270c0a9cde58da7bdb9c9a3271eef35f20" have entirely different histories.
c86ff9ef1a
...
5b0635270c
@ -39,7 +39,7 @@ class ClipList extends Component<IClipListProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getClipInfo(clip: Clip): string {
|
private getClipInfo(clip: Clip): string {
|
||||||
let fps = Math.round((clip.frames.length - 1) / clip.time);
|
let fps = Math.floor(clip.frames.length / clip.time);
|
||||||
if (isNaN(fps)) fps = 0;
|
if (isNaN(fps)) fps = 0;
|
||||||
return `${this.parseTime(clip.time)} ${fps}fps`;
|
return `${this.parseTime(clip.time)} ${fps}fps`;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,6 @@ import { SettingPopup } from "@Component/SettingPopup/SettingPopup";
|
|||||||
import { BehaviorPopup } from "@Component/BehaviorPopup/BehaviorPopup";
|
import { BehaviorPopup } from "@Component/BehaviorPopup/BehaviorPopup";
|
||||||
import { MouseMod } from "@GLRender/ClassicRenderer";
|
import { MouseMod } from "@GLRender/ClassicRenderer";
|
||||||
import { ArchiveSave } from "@Context/Archive";
|
import { ArchiveSave } from "@Context/Archive";
|
||||||
import { ActuatorModel } from "@Model/Actuator";
|
|
||||||
import "./CommandBar.scss";
|
import "./CommandBar.scss";
|
||||||
|
|
||||||
const COMMAND_BAR_WIDTH = 45;
|
const COMMAND_BAR_WIDTH = 45;
|
||||||
@ -51,62 +50,6 @@ class CommandBar extends Component<IMixinSettingProps & IMixinStatusProps, IComm
|
|||||||
isSaveRunning: false
|
isSaveRunning: false
|
||||||
};
|
};
|
||||||
|
|
||||||
private renderPlayActionButton(): ReactNode {
|
|
||||||
|
|
||||||
let icon: string = "Play";
|
|
||||||
let handel: () => any = () => {};
|
|
||||||
|
|
||||||
// 播放模式
|
|
||||||
if (this.props.status?.focusClip) {
|
|
||||||
|
|
||||||
// 暂停播放
|
|
||||||
if (this.props.status?.actuator.mod === ActuatorModel.Play) {
|
|
||||||
icon = "Pause";
|
|
||||||
handel = () => {
|
|
||||||
this.props.status?.actuator.pausePlay();
|
|
||||||
console.log("ClipRecorder: Pause play...");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 开始播放
|
|
||||||
else {
|
|
||||||
icon = "Play";
|
|
||||||
handel = () => {
|
|
||||||
this.props.status?.actuator.playing();
|
|
||||||
console.log("ClipRecorder: Play start...");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正在录制中
|
|
||||||
else if (
|
|
||||||
this.props.status?.actuator.mod === ActuatorModel.Record ||
|
|
||||||
this.props.status?.actuator.mod === ActuatorModel.Offline
|
|
||||||
) {
|
|
||||||
|
|
||||||
// 暂停录制
|
|
||||||
icon = "Stop";
|
|
||||||
handel = () => {
|
|
||||||
this.props.status?.actuator.endRecord();
|
|
||||||
console.log("ClipRecorder: Rec end...");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// 正常控制主时钟
|
|
||||||
else {
|
|
||||||
icon = this.props.status?.actuator.start() ? "Pause" : "Play";
|
|
||||||
handel = () => this.props.status?.actuator.start(
|
|
||||||
!this.props.status?.actuator.start()
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return <CommandButton
|
|
||||||
iconName={icon}
|
|
||||||
i18NKey="Command.Bar.Play.Info"
|
|
||||||
click={handel}
|
|
||||||
/>;
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
|
|
||||||
const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag;
|
const mouseMod = this.props.status?.mouseMod ?? MouseMod.Drag;
|
||||||
@ -141,7 +84,13 @@ class CommandBar extends Component<IMixinSettingProps & IMixinStatusProps, IComm
|
|||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{this.renderPlayActionButton()}
|
<CommandButton
|
||||||
|
iconName={this.props.status?.actuator.start() ? "Pause" : "Play"}
|
||||||
|
i18NKey="Command.Bar.Play.Info"
|
||||||
|
click={() => this.props.status ? this.props.status.actuator.start(
|
||||||
|
!this.props.status.actuator.start()
|
||||||
|
) : undefined}
|
||||||
|
/>
|
||||||
|
|
||||||
<CommandButton
|
<CommandButton
|
||||||
iconName="HandsFree"
|
iconName="HandsFree"
|
||||||
|
@ -1,8 +0,0 @@
|
|||||||
@import "../Theme/Theme.scss";
|
|
||||||
|
|
||||||
div.offline-render-popup {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 10px;
|
|
||||||
}
|
|
@ -1,124 +0,0 @@
|
|||||||
import { Component, ReactNode } from "react";
|
|
||||||
import { Popup } from "@Context/Popups";
|
|
||||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
|
||||||
import { Localization } from "@Component/Localization/Localization";
|
|
||||||
import { AttrInput } from "@Input/AttrInput/AttrInput";
|
|
||||||
import { Message } from "@Input/Message/Message";
|
|
||||||
import { ConfirmContent } from "@Component/ConfirmPopup/ConfirmPopup";
|
|
||||||
import { ProcessPopup } from "@Component/ProcessPopup/ProcessPopup";
|
|
||||||
import { Emitter } from "@Model/Emitter";
|
|
||||||
import "./OfflineRender.scss";
|
|
||||||
|
|
||||||
interface IOfflineRenderProps {
|
|
||||||
close?: () => any;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IOfflineRenderState {
|
|
||||||
time: number;
|
|
||||||
fps: number;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
class OfflineRender extends Popup<IOfflineRenderProps> {
|
|
||||||
|
|
||||||
public minWidth: number = 250;
|
|
||||||
public minHeight: number = 150;
|
|
||||||
public width: number = 400;
|
|
||||||
public height: number = 300;
|
|
||||||
|
|
||||||
public maskForSelf: boolean = true;
|
|
||||||
|
|
||||||
public onRenderHeader(): ReactNode {
|
|
||||||
return <Localization i18nKey="Popup.Offline.Render.Title"/>
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
|
||||||
return <OfflineRenderComponent {...this.props} close={() => {
|
|
||||||
this.close();
|
|
||||||
}}/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@useStatusWithEvent()
|
|
||||||
class OfflineRenderComponent extends Component<IOfflineRenderProps & IMixinStatusProps, IOfflineRenderState> {
|
|
||||||
|
|
||||||
public constructor(props: IOfflineRenderProps & IMixinStatusProps) {
|
|
||||||
super(props);
|
|
||||||
this.state = {
|
|
||||||
name: this.props.status?.getNewClipName() ?? "",
|
|
||||||
time: 10,
|
|
||||||
fps: 60
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
|
||||||
return <ConfirmContent
|
|
||||||
className="offline-render-popup"
|
|
||||||
actions={[{
|
|
||||||
i18nKey: "Popup.Offline.Render.Input.Start",
|
|
||||||
onClick: () => {
|
|
||||||
|
|
||||||
// 获取新实例
|
|
||||||
let newClip = this.props.status?.newClip();
|
|
||||||
|
|
||||||
if (newClip) {
|
|
||||||
newClip.name = this.state.name;
|
|
||||||
this.props.status?.actuator.offlineRender(newClip, this.state.time, this.state.fps);
|
|
||||||
|
|
||||||
// 开启进度条弹窗
|
|
||||||
this.props.status?.popup.showPopup(ProcessPopup, {});
|
|
||||||
}
|
|
||||||
|
|
||||||
// 关闭这个弹窗
|
|
||||||
this.props.close && this.props.close();
|
|
||||||
}
|
|
||||||
}]}
|
|
||||||
>
|
|
||||||
|
|
||||||
<Message i18nKey="Popup.Offline.Render.Message" isTitle first/>
|
|
||||||
|
|
||||||
<AttrInput
|
|
||||||
id={"Render-Name"}
|
|
||||||
value={this.state.name}
|
|
||||||
keyI18n="Popup.Offline.Render.Input.Name"
|
|
||||||
maxLength={15}
|
|
||||||
valueChange={(val) => {
|
|
||||||
this.setState({
|
|
||||||
name: val
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AttrInput
|
|
||||||
isNumber
|
|
||||||
id={"Render-Time"}
|
|
||||||
value={this.state.time}
|
|
||||||
keyI18n="Popup.Offline.Render.Input.Time"
|
|
||||||
max={3600}
|
|
||||||
min={1}
|
|
||||||
valueChange={(val) => {
|
|
||||||
this.setState({
|
|
||||||
time: parseFloat(val)
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<AttrInput
|
|
||||||
isNumber
|
|
||||||
id={"Render-FPS"}
|
|
||||||
max={1000}
|
|
||||||
min={1}
|
|
||||||
value={this.state.fps}
|
|
||||||
keyI18n="Popup.Offline.Render.Input.Fps"
|
|
||||||
valueChange={(val) => {
|
|
||||||
this.setState({
|
|
||||||
fps: parseFloat(val)
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</ConfirmContent>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { OfflineRender };
|
|
@ -1,42 +0,0 @@
|
|||||||
@import "../Theme/Theme.scss";
|
|
||||||
|
|
||||||
div.process-popup {
|
|
||||||
width: 100%;
|
|
||||||
height: 100%;
|
|
||||||
box-sizing: border-box;
|
|
||||||
padding: 10px;
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator {
|
|
||||||
transform: none;
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressTrack {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressBar {
|
|
||||||
transform: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.confirm-root.dark div.ms-ProgressIndicator {
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressTrack {
|
|
||||||
background-color: $lt-bg-color-lvl3-dark;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressBar {
|
|
||||||
background-color: $lt-font-color-normal-dark;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
div.confirm-root.light div.ms-ProgressIndicator {
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressTrack {
|
|
||||||
background-color: $lt-bg-color-lvl3-light;
|
|
||||||
}
|
|
||||||
|
|
||||||
div.ms-ProgressIndicator-progressBar {
|
|
||||||
background-color: $lt-font-color-normal-light;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,89 +0,0 @@
|
|||||||
import { Component, ReactNode } from "react";
|
|
||||||
import { Popup } from "@Context/Popups";
|
|
||||||
import { Localization } from "@Component/Localization/Localization";
|
|
||||||
import { ConfirmContent } from "@Component/ConfirmPopup/ConfirmPopup";
|
|
||||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
|
||||||
import { ProgressIndicator } from "@fluentui/react";
|
|
||||||
import { ActuatorModel } from "@Model/Actuator";
|
|
||||||
import "./ProcessPopup.scss";
|
|
||||||
|
|
||||||
interface IProcessPopupProps {
|
|
||||||
close?: () => void;
|
|
||||||
}
|
|
||||||
|
|
||||||
class ProcessPopup extends Popup<IProcessPopupProps> {
|
|
||||||
|
|
||||||
public minWidth: number = 400;
|
|
||||||
public minHeight: number = 150;
|
|
||||||
public width: number = 400;
|
|
||||||
public height: number = 150;
|
|
||||||
|
|
||||||
public maskForSelf: boolean = true;
|
|
||||||
|
|
||||||
public onClose(): void {}
|
|
||||||
|
|
||||||
public onRenderHeader(): ReactNode {
|
|
||||||
return <Localization i18nKey="Popup.Offline.Render.Process.Title"/>
|
|
||||||
}
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
|
||||||
return <ProcessPopupComponent {...this.props} close={() => this.close()}/>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@useStatusWithEvent("offlineLoop", "actuatorStartChange", "recordLoop")
|
|
||||||
class ProcessPopupComponent extends Component<IProcessPopupProps & IMixinStatusProps> {
|
|
||||||
|
|
||||||
public render(): ReactNode {
|
|
||||||
|
|
||||||
let current = this.props.status?.actuator.offlineCurrentFrame ?? 0;
|
|
||||||
let all = this.props.status?.actuator.offlineAllFrame ?? 0;
|
|
||||||
|
|
||||||
const isRendering = this.props.status?.actuator.mod === ActuatorModel.Offline;
|
|
||||||
let i18nKey = "";
|
|
||||||
let color: undefined | "red";
|
|
||||||
let onClick = () => {};
|
|
||||||
|
|
||||||
if (isRendering) {
|
|
||||||
i18nKey = "Popup.Offline.Render.Input.End";
|
|
||||||
color = "red";
|
|
||||||
onClick = () => {
|
|
||||||
this.props.status?.actuator.endOfflineRender();
|
|
||||||
this.forceUpdate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
i18nKey = "Popup.Offline.Render.Input.Finished";
|
|
||||||
onClick = () => {
|
|
||||||
this.props.close && this.props.close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return <ConfirmContent
|
|
||||||
className="process-popup"
|
|
||||||
actions={[{
|
|
||||||
i18nKey: i18nKey,
|
|
||||||
color: color,
|
|
||||||
onClick: onClick
|
|
||||||
}]}
|
|
||||||
>
|
|
||||||
|
|
||||||
<ProgressIndicator
|
|
||||||
percentComplete={current / all}
|
|
||||||
barHeight={3}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<Localization
|
|
||||||
i18nKey="Popup.Offline.Render.Process"
|
|
||||||
options={{
|
|
||||||
current: current.toString(),
|
|
||||||
all: all.toString()
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
</ConfirmContent>
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export { ProcessPopup };
|
|
@ -7,11 +7,9 @@ div.recorder-root {
|
|||||||
|
|
||||||
div.recorder-slider {
|
div.recorder-slider {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
transition: none;
|
|
||||||
|
|
||||||
div.ms-Slider-slideBox {
|
div.ms-Slider-slideBox {
|
||||||
height: 16px;
|
height: 16px;
|
||||||
transition: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span.ms-Slider-thumb {
|
span.ms-Slider-thumb {
|
||||||
@ -19,18 +17,15 @@ div.recorder-root {
|
|||||||
height: 12px;
|
height: 12px;
|
||||||
line-height: 16px;
|
line-height: 16px;
|
||||||
border-width: 3px;
|
border-width: 3px;
|
||||||
transition: none;
|
|
||||||
top: -4px;
|
top: -4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
span.ms-Slider-active {
|
span.ms-Slider-active {
|
||||||
height: 3px;
|
height: 3px;
|
||||||
transition: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span.ms-Slider-inactive {
|
span.ms-Slider-inactive {
|
||||||
height: 3px;
|
height: 3px;
|
||||||
transition: none;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,6 @@ interface IRecorderProps {
|
|||||||
allTime?: number;
|
allTime?: number;
|
||||||
currentTime?: number;
|
currentTime?: number;
|
||||||
action?: () => void;
|
action?: () => void;
|
||||||
valueChange?: (value: number) => any;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class Recorder extends Component<IRecorderProps> {
|
class Recorder extends Component<IRecorderProps> {
|
||||||
@ -86,38 +85,19 @@ class Recorder extends Component<IRecorderProps> {
|
|||||||
max={this.props.allFrame}
|
max={this.props.allFrame}
|
||||||
className={"recorder-slider" + (isSliderDisable ? " disable" : "")}
|
className={"recorder-slider" + (isSliderDisable ? " disable" : "")}
|
||||||
showValue={false}
|
showValue={false}
|
||||||
onChange={(value) => {
|
|
||||||
if (this.props.valueChange && !isSliderDisable) {
|
|
||||||
this.props.valueChange(value);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
/>
|
/>
|
||||||
<div className="recorder-content">
|
<div className="recorder-content">
|
||||||
<div className="time-view">
|
<div className="time-view">
|
||||||
{this.getRecordInfo()}
|
{this.getRecordInfo()}
|
||||||
</div>
|
</div>
|
||||||
<div className="ctrl-button">
|
<div className="ctrl-button">
|
||||||
<div
|
<div className={"ctrl-action" + (isJumpDisable ? " disable" : "")}>
|
||||||
className={"ctrl-action" + (isJumpDisable ? " disable" : "")}
|
|
||||||
onClick={() => {
|
|
||||||
if (this.props.valueChange && !isJumpDisable && this.props.currentFrame !== undefined) {
|
|
||||||
this.props.valueChange(this.props.currentFrame - 1);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon iconName="Back"/>
|
<Icon iconName="Back"/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ctrl-action ctrl-action-main" onClick={this.props.action}>
|
<div className="ctrl-action ctrl-action-main" onClick={this.props.action}>
|
||||||
<Icon iconName={this.getActionIcon()}/>
|
<Icon iconName={this.getActionIcon()}/>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div className={"ctrl-action" + (isJumpDisable ? " disable" : "")}>
|
||||||
className={"ctrl-action" + (isJumpDisable ? " disable" : "")}
|
|
||||||
onClick={() => {
|
|
||||||
if (this.props.valueChange && !isJumpDisable && this.props.currentFrame !== undefined) {
|
|
||||||
this.props.valueChange(this.props.currentFrame + 1);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Icon iconName="Forward"/>
|
<Icon iconName="Forward"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -37,7 +37,6 @@ interface IStatusEvent {
|
|||||||
renderLoop: number;
|
renderLoop: number;
|
||||||
physicsLoop: number;
|
physicsLoop: number;
|
||||||
recordLoop: number;
|
recordLoop: number;
|
||||||
offlineLoop: number;
|
|
||||||
mouseModChange: void;
|
mouseModChange: void;
|
||||||
focusObjectChange: void;
|
focusObjectChange: void;
|
||||||
focusLabelChange: void;
|
focusLabelChange: void;
|
||||||
@ -130,7 +129,6 @@ class Status extends Emitter<IStatusEvent> {
|
|||||||
// 循环事件
|
// 循环事件
|
||||||
this.actuator.on("loop", (t) => { this.emit("physicsLoop", t) });
|
this.actuator.on("loop", (t) => { this.emit("physicsLoop", t) });
|
||||||
this.actuator.on("record", (t) => { this.emit("recordLoop", t) });
|
this.actuator.on("record", (t) => { this.emit("recordLoop", t) });
|
||||||
this.actuator.on("offline", (t) => { this.emit("offlineLoop", t) });
|
|
||||||
|
|
||||||
// 对象变化事件
|
// 对象变化事件
|
||||||
this.model.on("objectChange", () => this.emit("objectChange"));
|
this.model.on("objectChange", () => this.emit("objectChange"));
|
||||||
@ -426,7 +424,7 @@ class Status extends Emitter<IStatusEvent> {
|
|||||||
return label;
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getNewClipName() {
|
public newClip() {
|
||||||
let searchKey = I18N(this.setting.language, "Object.List.New.Clip", { id: "" });
|
let searchKey = I18N(this.setting.language, "Object.List.New.Clip", { id: "" });
|
||||||
let nextIndex = 1;
|
let nextIndex = 1;
|
||||||
this.model.clipPool.forEach((obj) => {
|
this.model.clipPool.forEach((obj) => {
|
||||||
@ -434,13 +432,11 @@ class Status extends Emitter<IStatusEvent> {
|
|||||||
obj.name, searchKey
|
obj.name, searchKey
|
||||||
));
|
));
|
||||||
});
|
});
|
||||||
return I18N(this.setting.language, "Object.List.New.Clip", {
|
const clip = this.model.addClip(
|
||||||
id: nextIndex.toString()
|
I18N(this.setting.language, "Object.List.New.Clip", {
|
||||||
});
|
id: nextIndex.toString()
|
||||||
}
|
})
|
||||||
|
);
|
||||||
public newClip() {
|
|
||||||
const clip = this.model.addClip(this.getNewClipName());
|
|
||||||
return clip;
|
return clip;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -69,19 +69,8 @@ const EN_US = {
|
|||||||
"Popup.Action.Objects.Confirm.Restore": "Restore",
|
"Popup.Action.Objects.Confirm.Restore": "Restore",
|
||||||
"Popup.Delete.Objects.Confirm": "Are you sure you want to delete this object(s)? The object is deleted and cannot be recalled.",
|
"Popup.Delete.Objects.Confirm": "Are you sure you want to delete this object(s)? The object is deleted and cannot be recalled.",
|
||||||
"Popup.Delete.Behavior.Confirm": "Are you sure you want to delete this behavior? The behavior is deleted and cannot be recalled.",
|
"Popup.Delete.Behavior.Confirm": "Are you sure you want to delete this behavior? The behavior is deleted and cannot be recalled.",
|
||||||
"Popup.Delete.Clip.Confirm": "Are you sure you want to delete this clip? The clip cannot be restored after deletion.",
|
|
||||||
"Popup.Restore.Behavior.Confirm": "Are you sure you want to reset all parameters of this behavior? This operation cannot be recalled.",
|
"Popup.Restore.Behavior.Confirm": "Are you sure you want to reset all parameters of this behavior? This operation cannot be recalled.",
|
||||||
"Popup.Setting.Title": "Preferences setting",
|
"Popup.Setting.Title": "Preferences setting",
|
||||||
"Popup.Offline.Render.Title": "Offline rendering",
|
|
||||||
"Popup.Offline.Render.Process.Title": "Rendering progress",
|
|
||||||
"Popup.Offline.Render.Message": "Rendering Parameters",
|
|
||||||
"Popup.Offline.Render.Input.Name": "Clip name",
|
|
||||||
"Popup.Offline.Render.Input.Time": "Duration (s)",
|
|
||||||
"Popup.Offline.Render.Input.Fps": "FPS (f/s)",
|
|
||||||
"Popup.Offline.Render.Input.Start": "Start rendering",
|
|
||||||
"Popup.Offline.Render.Input.End": "Terminate rendering",
|
|
||||||
"Popup.Offline.Render.Input.Finished": "Finished",
|
|
||||||
"Popup.Offline.Render.Process": "Number of frames completed: {current} / {all}",
|
|
||||||
"Popup.Load.Save.Title": "Load save",
|
"Popup.Load.Save.Title": "Load save",
|
||||||
"Popup.Load.Save.confirm": "Got it",
|
"Popup.Load.Save.confirm": "Got it",
|
||||||
"Popup.Load.Save.Overwrite": "Overwrite and continue",
|
"Popup.Load.Save.Overwrite": "Overwrite and continue",
|
||||||
|
@ -69,19 +69,8 @@ const ZH_CN = {
|
|||||||
"Popup.Action.Objects.Confirm.Restore": "重置",
|
"Popup.Action.Objects.Confirm.Restore": "重置",
|
||||||
"Popup.Delete.Objects.Confirm": "你确定要删除这个(些)对象吗?对象被删除将无法撤回。",
|
"Popup.Delete.Objects.Confirm": "你确定要删除这个(些)对象吗?对象被删除将无法撤回。",
|
||||||
"Popup.Delete.Behavior.Confirm": "你确定要删除这个行为吗?行为被删除将无法撤回。",
|
"Popup.Delete.Behavior.Confirm": "你确定要删除这个行为吗?行为被删除将无法撤回。",
|
||||||
"Popup.Delete.Clip.Confirm": "你确定删除这个剪辑片段,剪辑片段删除后将无法恢复。",
|
|
||||||
"Popup.Restore.Behavior.Confirm": "你确定要重置此行为的全部参数吗?此操作无法撤回。",
|
"Popup.Restore.Behavior.Confirm": "你确定要重置此行为的全部参数吗?此操作无法撤回。",
|
||||||
"Popup.Setting.Title": "首选项设置",
|
"Popup.Setting.Title": "首选项设置",
|
||||||
"Popup.Offline.Render.Title": "离线渲染",
|
|
||||||
"Popup.Offline.Render.Process.Title": "渲染进度",
|
|
||||||
"Popup.Offline.Render.Message": "渲染参数",
|
|
||||||
"Popup.Offline.Render.Input.Name": "剪辑名称",
|
|
||||||
"Popup.Offline.Render.Input.Time": "时长 (s)",
|
|
||||||
"Popup.Offline.Render.Input.Fps": "帧率 (f/s)",
|
|
||||||
"Popup.Offline.Render.Input.Start": "开始渲染",
|
|
||||||
"Popup.Offline.Render.Input.End": "终止渲染",
|
|
||||||
"Popup.Offline.Render.Input.Finished": "完成",
|
|
||||||
"Popup.Offline.Render.Process": "完成帧数: {current} / {all}",
|
|
||||||
"Popup.Load.Save.Title": "加载存档",
|
"Popup.Load.Save.Title": "加载存档",
|
||||||
"Popup.Load.Save.confirm": "我知道了",
|
"Popup.Load.Save.confirm": "我知道了",
|
||||||
"Popup.Load.Save.Overwrite": "覆盖并继续",
|
"Popup.Load.Save.Overwrite": "覆盖并继续",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Model } from "@Model/Model";
|
import { Model } from "@Model/Model";
|
||||||
import { Emitter } from "@Model/Emitter";
|
import { Emitter } from "@Model/Emitter";
|
||||||
import { Clip, IFrame } from "@Model/Clip";
|
import { Clip } from "@Model/Clip";
|
||||||
|
|
||||||
enum ActuatorModel {
|
enum ActuatorModel {
|
||||||
Play = 1,
|
Play = 1,
|
||||||
@ -13,7 +13,6 @@ interface IActuatorEvent {
|
|||||||
startChange: boolean;
|
startChange: boolean;
|
||||||
record: number;
|
record: number;
|
||||||
loop: number;
|
loop: number;
|
||||||
offline: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -46,21 +45,6 @@ class Actuator extends Emitter<IActuatorEvent> {
|
|||||||
*/
|
*/
|
||||||
public recordClip?: Clip;
|
public recordClip?: Clip;
|
||||||
|
|
||||||
/**
|
|
||||||
* 播放剪辑
|
|
||||||
*/
|
|
||||||
public playClip?: Clip;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 播放帧
|
|
||||||
*/
|
|
||||||
public playFrame?: IFrame;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 播放帧数
|
|
||||||
*/
|
|
||||||
public playFrameId: number = 0;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 开始录制
|
* 开始录制
|
||||||
*/
|
*/
|
||||||
@ -92,98 +76,6 @@ class Actuator extends Emitter<IActuatorEvent> {
|
|||||||
this.mod = ActuatorModel.View;
|
this.mod = ActuatorModel.View;
|
||||||
}
|
}
|
||||||
|
|
||||||
public startPlay(clip: Clip) {
|
|
||||||
|
|
||||||
// 如果仿真正在进行,停止仿真
|
|
||||||
if (this.start()) this.start(false);
|
|
||||||
|
|
||||||
// 如果正在录制,阻止播放
|
|
||||||
if (this.mod === ActuatorModel.Record) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果正在播放,暂停播放
|
|
||||||
if (this.mod === ActuatorModel.Play) {
|
|
||||||
this.pausePlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置播放对象
|
|
||||||
this.playClip = clip;
|
|
||||||
|
|
||||||
// 设置播放帧数
|
|
||||||
this.playFrameId = 0;
|
|
||||||
this.playFrame = clip.frames[this.playFrameId];
|
|
||||||
|
|
||||||
// 播放第一帧
|
|
||||||
clip.play(this.playFrame);
|
|
||||||
|
|
||||||
// 激发时钟状态事件
|
|
||||||
this.emit("startChange", true);
|
|
||||||
}
|
|
||||||
|
|
||||||
public endPlay() {
|
|
||||||
|
|
||||||
// 如果正在播放,暂停播放
|
|
||||||
if (this.mod === ActuatorModel.Play) {
|
|
||||||
this.pausePlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新模式
|
|
||||||
this.mod = ActuatorModel.View;
|
|
||||||
|
|
||||||
// 清除状态
|
|
||||||
this.playClip = undefined;
|
|
||||||
this.playFrameId = 0;
|
|
||||||
this.playFrame = undefined;
|
|
||||||
|
|
||||||
// 渲染模型
|
|
||||||
this.model.draw();
|
|
||||||
|
|
||||||
// 激发时钟状态事件
|
|
||||||
this.emit("startChange", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否播放完毕
|
|
||||||
*/
|
|
||||||
public isPlayEnd() {
|
|
||||||
if (this.playClip && this.playFrame) {
|
|
||||||
if (this.playFrameId >= (this.playClip.frames.length - 1)) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public playing() {
|
|
||||||
|
|
||||||
// 如果播放完毕了,从头开始播放
|
|
||||||
if (this.isPlayEnd() && this.playClip) {
|
|
||||||
this.startPlay(this.playClip);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新模式
|
|
||||||
this.mod = ActuatorModel.Play;
|
|
||||||
|
|
||||||
// 启动播放时钟
|
|
||||||
this.playTicker();
|
|
||||||
|
|
||||||
// 激发时钟状态事件
|
|
||||||
this.emit("startChange", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public pausePlay() {
|
|
||||||
|
|
||||||
// 更新模式
|
|
||||||
this.mod = ActuatorModel.View;
|
|
||||||
|
|
||||||
// 激发时钟状态事件
|
|
||||||
this.emit("startChange", false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主时钟状态控制
|
* 主时钟状态控制
|
||||||
*/
|
*/
|
||||||
@ -216,160 +108,6 @@ class Actuator extends Emitter<IActuatorEvent> {
|
|||||||
|
|
||||||
public tickerType: 1 | 2 = 2;
|
public tickerType: 1 | 2 = 2;
|
||||||
|
|
||||||
private playTickerTimer?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 设置播放进度
|
|
||||||
*/
|
|
||||||
public setPlayProcess(id: number) {
|
|
||||||
if (this.playClip && id >= 0 && id < this.playClip.frames.length) {
|
|
||||||
|
|
||||||
// 跳转值这帧
|
|
||||||
this.playFrameId = id;
|
|
||||||
this.playFrame = this.playClip.frames[this.playFrameId];
|
|
||||||
this.emit("record", this.playFrame.duration);
|
|
||||||
|
|
||||||
if (this.mod !== ActuatorModel.Play) {
|
|
||||||
this.playClip.play(this.playFrame);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 离线渲染参数
|
|
||||||
*/
|
|
||||||
public offlineAllFrame: number = 0;
|
|
||||||
public offlineCurrentFrame: number = 0;
|
|
||||||
private offlineRenderTickTimer?: number;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 关闭离线渲染
|
|
||||||
*/
|
|
||||||
public endOfflineRender() {
|
|
||||||
|
|
||||||
// 清除 timer
|
|
||||||
clearTimeout(this.offlineRenderTickTimer);
|
|
||||||
|
|
||||||
this.recordClip && (this.recordClip.isRecording = false);
|
|
||||||
this.recordClip = undefined;
|
|
||||||
|
|
||||||
// 设置状态
|
|
||||||
this.mod = ActuatorModel.View;
|
|
||||||
|
|
||||||
// 激发结束事件
|
|
||||||
this.start(false);
|
|
||||||
this.emit("record", 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 离线渲染 tick
|
|
||||||
*/
|
|
||||||
private offlineRenderTick(dt: number) {
|
|
||||||
|
|
||||||
if (this.mod !== ActuatorModel.Offline) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.offlineCurrentFrame >= this.offlineAllFrame) {
|
|
||||||
return this.endOfflineRender();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新模型
|
|
||||||
this.model.update(dt);
|
|
||||||
|
|
||||||
// 录制
|
|
||||||
this.recordClip?.record(dt);
|
|
||||||
|
|
||||||
// 限制更新频率
|
|
||||||
if (this.offlineCurrentFrame % 10 === 0) {
|
|
||||||
this.emit("offline", dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
this.offlineCurrentFrame++
|
|
||||||
|
|
||||||
if (this.offlineCurrentFrame <= this.offlineAllFrame) {
|
|
||||||
|
|
||||||
// 下一个 tick
|
|
||||||
this.offlineRenderTickTimer = setTimeout(() => this.offlineRenderTick(dt)) as any;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.endOfflineRender();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 离线渲染
|
|
||||||
*/
|
|
||||||
public offlineRender(clip: Clip, time: number, fps: number) {
|
|
||||||
|
|
||||||
// 记录录制片段
|
|
||||||
this.recordClip = clip;
|
|
||||||
clip.isRecording = true;
|
|
||||||
|
|
||||||
// 如果仿真正在进行,停止仿真
|
|
||||||
if (this.start()) this.start(false);
|
|
||||||
|
|
||||||
// 如果正在录制,阻止
|
|
||||||
if (this.mod === ActuatorModel.Record || this.mod === ActuatorModel.Offline) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果正在播放,暂停播放
|
|
||||||
if (this.mod === ActuatorModel.Play) {
|
|
||||||
this.pausePlay();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置状态
|
|
||||||
this.mod = ActuatorModel.Offline;
|
|
||||||
|
|
||||||
// 计算帧数
|
|
||||||
this.offlineCurrentFrame = 0;
|
|
||||||
this.offlineAllFrame = Math.round(time * fps) - 1;
|
|
||||||
let dt = time / this.offlineAllFrame;
|
|
||||||
|
|
||||||
// 第一帧渲染
|
|
||||||
clip.record(0);
|
|
||||||
|
|
||||||
// 开启时钟
|
|
||||||
this.offlineRenderTick(dt);
|
|
||||||
|
|
||||||
this.emit("record", dt);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 播放时钟
|
|
||||||
*/
|
|
||||||
private playTicker() {
|
|
||||||
|
|
||||||
if (this.playClip && this.playFrame && this.mod === ActuatorModel.Play) {
|
|
||||||
|
|
||||||
// 播放当前帧
|
|
||||||
this.playClip.play(this.playFrame);
|
|
||||||
|
|
||||||
// 没有完成播放,继续播放
|
|
||||||
if (!this.isPlayEnd()) {
|
|
||||||
|
|
||||||
// 跳转值下一帧
|
|
||||||
this.playFrameId ++;
|
|
||||||
this.playFrame = this.playClip.frames[this.playFrameId];
|
|
||||||
this.emit("record", this.playFrame.duration);
|
|
||||||
|
|
||||||
// 清除计时器,保证时钟唯一性
|
|
||||||
clearTimeout(this.playTickerTimer);
|
|
||||||
|
|
||||||
// 延时
|
|
||||||
this.playTickerTimer = setTimeout(() => {
|
|
||||||
this.playTicker();
|
|
||||||
}, this.playFrame.duration * 1000) as any;
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this.pausePlay();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
this.pausePlay();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private ticker(t: number) {
|
private ticker(t: number) {
|
||||||
if (this.startFlag && t !== 0) {
|
if (this.startFlag && t !== 0) {
|
||||||
if (this.lastTime === 0) {
|
if (this.lastTime === 0) {
|
||||||
|
@ -15,7 +15,6 @@ interface IDrawCommand {
|
|||||||
interface IFrame {
|
interface IFrame {
|
||||||
commands: IDrawCommand[];
|
commands: IDrawCommand[];
|
||||||
duration: number;
|
duration: number;
|
||||||
process: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -82,41 +81,17 @@ class Clip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const dt = this.frames.length <= 0 ? 0 : t;
|
|
||||||
this.time += dt;
|
|
||||||
|
|
||||||
const frame: IFrame = {
|
const frame: IFrame = {
|
||||||
commands: commands,
|
commands: commands,
|
||||||
duration: dt,
|
duration: t
|
||||||
process: this.time
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
this.time += t;
|
||||||
this.frames.push(frame);
|
this.frames.push(frame);
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 播放一帧
|
|
||||||
*/
|
|
||||||
public play(frame: IFrame) {
|
|
||||||
|
|
||||||
// 清除全部渲染状态
|
|
||||||
this.model.renderer.clean();
|
|
||||||
|
|
||||||
// 执行全部渲染指令
|
|
||||||
for (let i = 0; i < frame.commands.length; i++) {
|
|
||||||
const command: IDrawCommand = frame.commands[i];
|
|
||||||
|
|
||||||
if (command.type === "cube") {
|
|
||||||
this.model.renderer.cube(command.id, command.position, command.radius, command.parameter);
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (frame.commands[i].type === "points") {
|
|
||||||
this.model.renderer.points(command.id, command.data, command.parameter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public equal(clip?: Clip) {
|
public equal(clip?: Clip) {
|
||||||
return clip === this || clip?.id === this.id;
|
return clip === this || clip?.id === this.id;
|
||||||
}
|
}
|
||||||
@ -127,4 +102,4 @@ class Clip {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export { Clip, IFrame };
|
export { Clip };
|
@ -371,7 +371,7 @@ class Model extends Emitter<ModelEvent> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (deletedClip) {
|
if (deletedClip) {
|
||||||
this.clipPool.splice(index, 1);
|
this.behaviorPool.splice(index, 1);
|
||||||
console.log(`Model: Delete clip ${deletedClip.name ?? deletedClip.id}`);
|
console.log(`Model: Delete clip ${deletedClip.name ?? deletedClip.id}`);
|
||||||
this.emit("clipChange", this.clipPool);
|
this.emit("clipChange", this.clipPool);
|
||||||
}
|
}
|
||||||
|
@ -1,90 +1,38 @@
|
|||||||
import { Component, ReactNode } from "react";
|
import { Component, ReactNode } from "react";
|
||||||
import { ClipList } from "@Component/ClipList/ClipList";
|
import { ClipList } from "@Component/ClipList/ClipList";
|
||||||
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
import { useStatusWithEvent, IMixinStatusProps } from "@Context/Status";
|
||||||
import { BackgroundLevel, FontLevel, Theme } from "@Component/Theme/Theme";
|
import { Theme } from "@Component/Theme/Theme";
|
||||||
import { Message } from "@Input/Message/Message";
|
import { Message } from "@Input/Message/Message";
|
||||||
import { Clip } from "@Model/Clip";
|
import { Clip } from "@Model/Clip";
|
||||||
import { ActuatorModel } from "@Model/Actuator";
|
import { ActuatorModel } from "@Model/Actuator";
|
||||||
import { ConfirmPopup } from "@Component/ConfirmPopup/ConfirmPopup";
|
|
||||||
import { OfflineRender } from "@Component/OfflineRender/OfflineRender"
|
|
||||||
import "./ClipPlayer.scss";
|
import "./ClipPlayer.scss";
|
||||||
|
|
||||||
@useStatusWithEvent("clipChange", "focusClipChange", "actuatorStartChange")
|
@useStatusWithEvent("clipChange", "focusClipChange", "actuatorStartChange")
|
||||||
class ClipPlayer extends Component<IMixinStatusProps> {
|
class ClipPlayer extends Component<IMixinStatusProps> {
|
||||||
|
|
||||||
private isInnerClick: boolean = false;
|
|
||||||
|
|
||||||
private renderMessage(): ReactNode {
|
private renderMessage(): ReactNode {
|
||||||
return <Message i18nKey="Panel.Info.Clip.List.Error.Nodata"/>;
|
return <Message i18nKey="Panel.Info.Clip.List.Error.Nodata"/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
private isClipListDisable() {
|
|
||||||
return !this.props.status?.focusClip &&
|
|
||||||
(
|
|
||||||
this.props.status?.actuator.mod === ActuatorModel.Record ||
|
|
||||||
this.props.status?.actuator.mod === ActuatorModel.Offline
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
private renderClipList(clipList: Clip[]): ReactNode {
|
private renderClipList(clipList: Clip[]): ReactNode {
|
||||||
|
|
||||||
|
const disable =
|
||||||
|
!this.props.status?.focusClip &&
|
||||||
|
(
|
||||||
|
this.props.status?.actuator.mod === ActuatorModel.Record ||
|
||||||
|
this.props.status?.actuator.mod === ActuatorModel.Offline
|
||||||
|
);
|
||||||
|
|
||||||
return <ClipList
|
return <ClipList
|
||||||
focus={this.props.status?.focusClip}
|
|
||||||
clips={clipList}
|
clips={clipList}
|
||||||
disable={this.isClipListDisable()}
|
disable={disable}
|
||||||
delete={(clip) => {
|
|
||||||
this.isInnerClick = true;
|
|
||||||
const status = this.props.status;
|
|
||||||
if (status) {
|
|
||||||
status.popup.showPopup(ConfirmPopup, {
|
|
||||||
infoI18n: "Popup.Delete.Clip.Confirm",
|
|
||||||
titleI18N: "Popup.Action.Objects.Confirm.Title",
|
|
||||||
yesI18n: "Popup.Action.Objects.Confirm.Delete",
|
|
||||||
red: "yes",
|
|
||||||
yes: () => {
|
|
||||||
status.setClipObject();
|
|
||||||
this.props.status?.actuator.endPlay();
|
|
||||||
status.model.deleteClip(clip.id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
add={() => {
|
|
||||||
this.isInnerClick = true;
|
|
||||||
this.props.status?.popup.showPopup(OfflineRender, {});
|
|
||||||
}}
|
|
||||||
click={(clip) => {
|
|
||||||
this.isInnerClick = true;
|
|
||||||
this.props.status?.setClipObject(clip);
|
|
||||||
this.props.status?.actuator.startPlay(clip);
|
|
||||||
}}
|
|
||||||
/>;
|
/>;
|
||||||
}
|
}
|
||||||
|
|
||||||
public render(): ReactNode {
|
public render(): ReactNode {
|
||||||
const clipList = this.props.status?.model.clipPool ?? [];
|
const clipList = this.props.status?.model.clipPool ?? [];
|
||||||
|
|
||||||
return <Theme
|
return <Theme className="Clip-player-clip-list-root">
|
||||||
className="Clip-player-clip-list-root"
|
|
||||||
fontLevel={FontLevel.normal}
|
|
||||||
backgroundLevel={BackgroundLevel.Level4}
|
|
||||||
onClick={()=>{
|
|
||||||
|
|
||||||
// 拦截禁用状态的事件
|
|
||||||
if (this.isClipListDisable()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.isInnerClick) {
|
|
||||||
this.isInnerClick = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
else {
|
|
||||||
this.props.status?.setClipObject();
|
|
||||||
this.props.status?.actuator.endPlay();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
{ clipList.length > 0 ? null : this.renderMessage() }
|
{ clipList.length > 0 ? null : this.renderMessage() }
|
||||||
{ this.renderClipList(clipList) }
|
{ this.renderClipList(clipList) }
|
||||||
</Theme>;
|
</Theme>;
|
||||||
|
@ -9,12 +9,7 @@ class ClipRecorder extends Component<IMixinStatusProps> {
|
|||||||
|
|
||||||
let mod: "P" | "R" = this.props.status?.focusClip ? "P" : "R";
|
let mod: "P" | "R" = this.props.status?.focusClip ? "P" : "R";
|
||||||
let runner: boolean = false;
|
let runner: boolean = false;
|
||||||
let currentTime: number | undefined = 0;
|
let currentTime: number = 0;
|
||||||
let allTime: number | undefined = 0;
|
|
||||||
let name: string | undefined;
|
|
||||||
let currentFrame: number | undefined = 0;
|
|
||||||
let allFrame: number | undefined = 0;
|
|
||||||
let fps: number | undefined = 0;
|
|
||||||
|
|
||||||
// 是否开始录制
|
// 是否开始录制
|
||||||
if (mod === "R") {
|
if (mod === "R") {
|
||||||
@ -24,38 +19,18 @@ class ClipRecorder extends Component<IMixinStatusProps> {
|
|||||||
this.props.status?.actuator.mod === ActuatorModel.Offline;
|
this.props.status?.actuator.mod === ActuatorModel.Offline;
|
||||||
|
|
||||||
currentTime = this.props.status?.actuator.recordClip?.time ?? 0;
|
currentTime = this.props.status?.actuator.recordClip?.time ?? 0;
|
||||||
|
|
||||||
name = this.props.status?.actuator.recordClip?.name;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
else if (mod === "P") {
|
else if (mod === "P") {
|
||||||
|
|
||||||
// 是否正在播放
|
// 是否正在播放
|
||||||
runner = this.props.status?.actuator.mod === ActuatorModel.Play;
|
runner = this.props.status?.actuator.mod === ActuatorModel.Play;
|
||||||
name = this.props.status?.focusClip?.name;
|
|
||||||
allTime = this.props.status?.focusClip?.time;
|
|
||||||
allFrame = this.props.status?.focusClip?.frames.length;
|
|
||||||
currentFrame = this.props.status?.actuator.playFrameId;
|
|
||||||
currentTime = this.props.status?.actuator.playFrame?.process;
|
|
||||||
|
|
||||||
if (allFrame !== undefined) {
|
|
||||||
allFrame --;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (allTime !== undefined && allFrame !== undefined) {
|
|
||||||
fps = Math.round(allFrame / allTime);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return <Recorder
|
return <Recorder
|
||||||
name={name}
|
|
||||||
currentTime={currentTime}
|
currentTime={currentTime}
|
||||||
allTime={allTime}
|
|
||||||
currentFrame={currentFrame}
|
|
||||||
allFrame={allFrame}
|
|
||||||
mode={mod}
|
mode={mod}
|
||||||
running={runner}
|
running={runner}
|
||||||
fps={fps}
|
|
||||||
action={() => {
|
action={() => {
|
||||||
|
|
||||||
// 开启录制
|
// 开启录制
|
||||||
@ -76,25 +51,6 @@ class ClipRecorder extends Component<IMixinStatusProps> {
|
|||||||
this.props.status?.actuator.endRecord();
|
this.props.status?.actuator.endRecord();
|
||||||
console.log("ClipRecorder: Rec end...");
|
console.log("ClipRecorder: Rec end...");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 开始播放
|
|
||||||
if (mod === "P" && !runner) {
|
|
||||||
|
|
||||||
// 启动播放时钟
|
|
||||||
this.props.status?.actuator.playing();
|
|
||||||
console.log("ClipRecorder: Play start...");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 暂停播放
|
|
||||||
if (mod === "P" && runner) {
|
|
||||||
|
|
||||||
// 启动播放时钟
|
|
||||||
this.props.status?.actuator.pausePlay();
|
|
||||||
console.log("ClipRecorder: Pause play...");
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
valueChange={(value) => {
|
|
||||||
this.props.status?.actuator.setPlayProcess(value);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user