diff --git a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx index 126c0d680a..4c61defb6c 100644 --- a/app/pages/PageEnigma/comps/Timeline/Timeline.tsx +++ b/app/pages/PageEnigma/comps/Timeline/Timeline.tsx @@ -17,8 +17,11 @@ import { timelineHeight, } from "~/pages/PageEnigma/store"; import { useQueueHandler } from "~/pages/PageEnigma/comps/Timeline/utils/useQueueHandler"; +import { EngineContext } from "../../contexts/EngineContext"; export const Timeline = () => { + const editorEngine = useContext(EngineContext); + const { characters, objects, diff --git a/app/pages/PageEnigma/contexts/EngineProvider.tsx b/app/pages/PageEnigma/contexts/EngineProvider.tsx index 899de9ff72..fdaa9982ef 100644 --- a/app/pages/PageEnigma/contexts/EngineProvider.tsx +++ b/app/pages/PageEnigma/contexts/EngineProvider.tsx @@ -4,7 +4,7 @@ import Editor from "~/pages/PageEnigma/js/editor"; import { EngineContext } from "./EngineContext"; import { AppUiContext } from "./AppUiContext"; - +import { TrackContext } from "./TrackContext/TrackContext"; interface Props { children: ReactNode; @@ -13,6 +13,8 @@ interface Props { export const EngineProvider = ({ children }: Props) => { const [editor, setEditor] = useState(null); const [appUiState, dispatchAppUiState] = useContext(AppUiContext); + // To talk to react land. + const trackContext = useContext(TrackContext) useEffect(() => { //componentDidMount diff --git a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx index 2559041981..413b947e99 100644 --- a/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx +++ b/app/pages/PageEnigma/contexts/TrackContext/TrackProvider.tsx @@ -76,8 +76,26 @@ export const TrackProvider = ({ children }: Props) => { { id: "ani-id1", offset: 0, - length: 124, - name: "ani 11", + length: 25, + name: "Sit", + }, + { + id: "ani-id2", + offset: 0, + length: 25, + name: "Idle", + }, + { + id: "ani-id3", + offset: 0, + length: 25, + name: "Stand", + }, + { + id: "ani-id4", + offset: 0, + length: 25, + name: "Walk", }, ]); setAudioClips([]); diff --git a/app/pages/PageEnigma/js/api_manager.ts b/app/pages/PageEnigma/js/api_manager.ts index ab3fa0a2ff..6a10773369 100644 --- a/app/pages/PageEnigma/js/api_manager.ts +++ b/app/pages/PageEnigma/js/api_manager.ts @@ -8,6 +8,21 @@ import { TimelineDataState } from "./timeline"; * Storyteller Studio API Manager * The source of truth of all these media items is the database in the cloud */ +class MediaFile { + public_bucket_path: string; + media_type: string; + media_token: string; + + constructor( + public_bucket_path: string, + media_type: string, + media_token: string, + ) { + this.media_token = media_token; + this.public_bucket_path = public_bucket_path; + this.media_type = media_type; + } +} /** * This is designed to surface user customer facing messages as errors. @@ -61,7 +76,8 @@ class APIManager { file, scene_glb_media_file_token, ); - const result_scene_glb_media_file_token = upload_glb_response["media_file_token"]; + const result_scene_glb_media_file_token = + upload_glb_response["media_file_token"]; // now write the scene const save_scene_timeline_response = await this.saveSceneAndTimeLineState( @@ -74,12 +90,16 @@ class APIManager { const result_scene_media_file_token = save_scene_timeline_response["media_file_token"]; - const data = { "scene_glb_media_file_token":result_scene_glb_media_file_token, - "scene_media_file_token": result_scene_media_file_token }; + const data = { + scene_glb_media_file_token: result_scene_glb_media_file_token, + scene_media_file_token: result_scene_media_file_token, + }; return new APIManagerResponseSuccess("Scene Saved", data); } - public async loadSceneState(scene_media_file_token: string | null): Promise { + public async loadSceneState( + scene_media_file_token: string | null, + ): Promise { const api_base_url = "https://api.fakeyou.com"; const url = `${api_base_url}/v1/media_files/file/${scene_media_file_token}`; const response = await fetch(url); @@ -104,19 +124,28 @@ class APIManager { console.log(`loadSceneState: ${JSON.stringify(json_result)}`); - const scene_glb_media_file_token: string = json_result["scene_glb_media_file_token"]; - - const media_bucket_path = await this.getMediaFile(scene_glb_media_file_token); - console.log(`GLB ${media_bucket_path}`) + const scene_glb_media_file_token: string = + json_result["scene_glb_media_file_token"]; + + const media_bucket_path = await this.getMediaFile( + scene_glb_media_file_token, + ); + console.log(`GLB ${media_bucket_path}`); let glbLoader = new GLTFLoader(); // promisify this - const loadGlb = (bucket_path: string): Promise => { + const loadGlb = ( + bucket_path: string, + ): Promise => { return new Promise((resolve, reject) => { glbLoader.load(bucket_path, (glb) => { if (glb) { const scene: THREE.Scene = glb.scene; - const data = { "scene_glb_media_file_token": scene_glb_media_file_token , "scene_media_file_token":scene_media_file_token, "scene": scene }; - console.log(`Data: ${data}`) + const data = { + scene_glb_media_file_token: scene_glb_media_file_token, + scene_media_file_token: scene_media_file_token, + scene: scene, + }; + console.log(`Data: ${data}`); resolve(new APIManagerResponseSuccess("Success Loaded", data)); } else { throw new APIManagerResponseError("Failed to Load GLB Scene"); @@ -205,12 +234,14 @@ class APIManager { const url = `${this.baseUrl}/v1/media_files/write/scene_file`; let uuid = uuidv4(); - console.log(`Saving Scene scene_media_file_token:${scene_media_file_token} | scene_glb_media_file_token:${scene_glb_media_file_token}`) + console.log( + `Saving Scene scene_media_file_token:${scene_media_file_token} | scene_glb_media_file_token:${scene_glb_media_file_token}`, + ); // turn json into a blob const scene_schema = { - 'scene_glb_media_file_token': scene_glb_media_file_token, - 'scene_name': scene_file_name, - 'timeline': { 'objects': [] }, + scene_glb_media_file_token: scene_glb_media_file_token, + scene_name: scene_file_name, + timeline: { objects: [] }, }; const json = JSON.stringify(scene_schema); const blob = new Blob([json], { type: "application/json" }); @@ -282,10 +313,25 @@ class APIManager { } } - public async batchGetMedia(media_tokens: []): Promise { - return ""; + public async getMediaBatch(media_tokens: string[]): Promise { + const tokens = media_tokens; + const url = new URL(`${this.baseUrl}/v1/media_files/batch`); + tokens.forEach((token) => url.searchParams.append("tokens", token)); + const result = await fetch(url) + .then((response) => response.json()) + .then((data) => { + const result = data["media_files"].map((element) => { + return new MediaFile( + element["public_bucket_path"], + element["media_type"], + element["token"], + ); + }); + return result; + }) + .catch((error) => console.error("Error:", error)); + return result; } - } export default APIManager; diff --git a/app/pages/PageEnigma/js/editor.ts b/app/pages/PageEnigma/js/editor.ts index 0fbdbb1072..1ac8c61f0d 100644 --- a/app/pages/PageEnigma/js/editor.ts +++ b/app/pages/PageEnigma/js/editor.ts @@ -1,6 +1,6 @@ import * as THREE from "three"; import { OrbitControls } from "three/addons/controls/OrbitControls.js"; -import { FreeCam } from "./free_cam" +import { FreeCam } from "./free_cam"; import { TransformControls } from "three/addons/controls/TransformControls.js"; import Scene from "./scene.js"; import APIManager from "./api_manager.js"; @@ -20,10 +20,9 @@ import { ClipUI } from "../datastructures/clips/clip_offset.js"; import { LipSyncEngine } from "./lip_sync_engine.js"; import { AnimationEngine } from "./animation_engine.js"; -import { PointerLockControls } from 'three/addons/controls/PointerLockControls.js'; +import { PointerLockControls } from "three/addons/controls/PointerLockControls.js"; import { APPUI_ACTION_TYPES } from "../reducers"; - class EditorState { // { // action: "ShowLoadingIndicator" @@ -174,7 +173,7 @@ class Editor { this.current_frame = 0; - // Dispatcher + // Dispatcher this.dispatchAppUiState = null; // Scene State @@ -182,19 +181,17 @@ class Editor { this.current_scene_glb_media_token = null; } - initialize(config:any) { + initialize(config: any) { //setup reactland Callbacks - this.dispatchAppUiState = config.dispatchAppUiState + this.dispatchAppUiState = config.dispatchAppUiState; - // Show Loader - this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER - }); + // this is called by the parent for some reason + // this.dispatchAppUiState({ + // type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER + // }); if (this.can_initialize == false) { - console.log( - "Editor Already Initialized", - ); + console.log("Editor Already Initialized"); return; } this.can_initialize = false; @@ -225,8 +222,14 @@ class Editor { this._configure_post_pro(); // Controls and movement. - this.lockControls = new PointerLockControls(this.camera, this.renderer.domElement); - this.cameraViewControls = new FreeCam(this.camera, this.renderer.domElement); + this.lockControls = new PointerLockControls( + this.camera, + this.renderer.domElement, + ); + this.cameraViewControls = new FreeCam( + this.camera, + this.renderer.domElement, + ); this.cameraViewControls.movementSpeed = 1; this.cameraViewControls.domElement = this.renderer.domElement; this.cameraViewControls.rollSpeed = Math.PI / 24; @@ -234,7 +237,10 @@ class Editor { this.cameraViewControls.dragToLook = true; this.cameraViewControls.enabled = false; - this.orbitControls = new OrbitControls(this.camera, this.renderer.domElement); + this.orbitControls = new OrbitControls( + this.camera, + this.renderer.domElement, + ); this.control = new TransformControls(this.camera, this.renderer.domElement); // OnClick and MouseMove events. @@ -255,28 +261,49 @@ class Editor { this.current_scene_media_token = null; this.current_scene_glb_media_token = null; + this.renderer.domElement.addEventListener( + "mousedown", + this.onMouseDown.bind(this), + false, + ); + this.renderer.domElement.addEventListener( + "mouseup", + this.onMouseUp.bind(this), + false, + ); + this.renderer.domElement.addEventListener( + "onContextMenu", + this.onContextMenu.bind(this), + false, + ); - this.renderer.domElement.addEventListener("mousedown", this.onMouseDown.bind(this), false); - this.renderer.domElement.addEventListener("mouseup", this.onMouseUp.bind(this), false); - this.renderer.domElement.addEventListener("onContextMenu", this.onContextMenu.bind(this), false); - this.cam_obj = this.activeScene.get_object_by_name("::CAM::"); - if(this.cam_obj) - { - this.add_transform_clip_base("Camera Object", this.cam_obj, 0, 150) + if (this.cam_obj) { + this.add_transform_clip_base("Camera Object", this.cam_obj, 0, 150); } - // hide loader this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADER + type: APPUI_ACTION_TYPES.UPDATE_EDITOR_LOADINGBAR, + payload: { + showEditorLoadingBar: { + progress: 100, + }, + }, }); + this.dispatchAppUiState({ + type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADINGBAR, + }); } // Token comes in from the front end to load the scene from the site. + public async testBatchRequest() { + const result = await this.api_manager.getMediaBatch(["m_8fmp9hrvsqcryzka1fra597kg42s50","m_z4jzbst3xfh64h0qn4bqh4afenfps9"]); + console.log(result); + } public async loadScene(scene_media_token: string) { this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER + type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER, }); if (scene_media_token != null) { @@ -287,19 +314,24 @@ class Editor { this.current_scene_media_token, ); - console.log(load_scene_state_response) - if(load_scene_state_response.data == null) { - console.log("load_scene_state_response Missing Data") - return; } + console.log(load_scene_state_response); + if (load_scene_state_response.data == null) { + console.log("load_scene_state_response Missing Data"); + return; + } - const loaded_scene = load_scene_state_response.data["scene"] + const loaded_scene = load_scene_state_response.data["scene"]; // Load these so you can rewrite the scene glb using it's token. - this.current_scene_media_token = load_scene_state_response.data["scene_media_file_token"] - this.current_scene_glb_media_token = load_scene_state_response.data["scene_glb_media_file_token"] + this.current_scene_media_token = + load_scene_state_response.data["scene_media_file_token"]; + this.current_scene_glb_media_token = + load_scene_state_response.data["scene_glb_media_file_token"]; + + console.log( + `loadScene => SceneMediaToken:${this.current_scene_media_token} SceneGLBMediaToken:${this.current_scene_glb_media_token}`, + ); - console.log(`loadScene => SceneMediaToken:${this.current_scene_media_token} SceneGLBMediaToken:${this.current_scene_glb_media_token}`); - this.activeScene.scene.children = loaded_scene.children; this.activeScene.scene.children.forEach((child: THREE.Object3D) => { @@ -316,53 +348,59 @@ class Editor { }); this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADER + type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADER, }); } - - public async saveScene(name: string) { // remove controls when saving scene. this.removeTransformControls(); this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER + type: APPUI_ACTION_TYPES.SHOW_EDITOR_LOADER, }); - console.log(`saveScene => SceneMediaToken:${this.current_scene_media_token} SceneGLBMediaToken:${this.current_scene_glb_media_token}`); - + console.log( + `saveScene => SceneMediaToken:${this.current_scene_media_token} SceneGLBMediaToken:${this.current_scene_glb_media_token}`, + ); + const result = await this.api_manager.saveSceneState( this.activeScene.scene, name, this.current_scene_glb_media_token, this.current_scene_media_token, - new TimelineDataState() - ) + new TimelineDataState(), + ); - if(result.data == null) { return; } - - const scene_media_token = result.data["scene_media_file_token"] - if (scene_media_token != null) { - this.current_scene_media_token = scene_media_token + if (result.data == null) { + return; } - const scene_glb_media_token = result.data["scene_glb_media_file_token"] + + const scene_media_token = result.data["scene_media_file_token"]; + if (scene_media_token != null) { + this.current_scene_media_token = scene_media_token; + } + const scene_glb_media_token = result.data["scene_glb_media_file_token"]; if (scene_glb_media_token != null) { - this.current_scene_glb_media_token = scene_glb_media_token - } + this.current_scene_glb_media_token = scene_glb_media_token; + } this.dispatchAppUiState({ - type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADER + type: APPUI_ACTION_TYPES.HIDE_EDITOR_LOADER, }); } /** - * This cleans up the transform controls - * During saving it + * This cleans up the transform controls + * During saving it * Doesn't retain those controls. - * @returns + * @returns */ private removeTransformControls() { - if (this.control == undefined) { return }; - if (this.outlinePass == undefined) { return }; + if (this.control == undefined) { + return; + } + if (this.outlinePass == undefined) { + return; + } this.last_selected = this.selected; this.control.detach(); this.activeScene.scene.remove(this.control); @@ -422,29 +460,41 @@ class Editor { switchCameraView() { this.camera_person_mode = !this.camera_person_mode; if (this.cam_obj) { - if(this.camera_person_mode) { + if (this.camera_person_mode) { this.last_cam_pos.copy(this.camera.position); this.last_cam_rot.copy(this.camera.rotation); this.camera.position.copy(this.cam_obj.position); this.camera.rotation.copy(this.cam_obj.rotation); - if(this.orbitControls) { this.orbitControls.enabled = false; } - if(this.lockControls) { this.activeScene.scene.add(this.lockControls.getObject()); } - if(this.cameraViewControls) { this.cameraViewControls.enabled = true; } + if (this.orbitControls) { + this.orbitControls.enabled = false; + } + if (this.lockControls) { + this.activeScene.scene.add(this.lockControls.getObject()); + } + if (this.cameraViewControls) { + this.cameraViewControls.enabled = true; + } - if(this.activeScene.hot_items){ - this.activeScene.hot_items.forEach(element => { + if (this.activeScene.hot_items) { + this.activeScene.hot_items.forEach((element) => { element.visible = false; }); } } else { this.camera.position.copy(this.last_cam_pos); this.camera.rotation.copy(this.last_cam_rot); - if(this.orbitControls) { this.orbitControls.enabled = true; } - if(this.lockControls) { this.activeScene.scene.remove(this.lockControls.getObject()); } - if(this.cameraViewControls) { this.cameraViewControls.enabled = false; } - if(this.activeScene.hot_items){ - this.activeScene.hot_items.forEach(element => { + if (this.orbitControls) { + this.orbitControls.enabled = true; + } + if (this.lockControls) { + this.activeScene.scene.remove(this.lockControls.getObject()); + } + if (this.cameraViewControls) { + this.cameraViewControls.enabled = false; + } + if (this.activeScene.hot_items) { + this.activeScene.hot_items.forEach((element) => { element.visible = true; }); } @@ -452,9 +502,22 @@ class Editor { } } - async add_transform_clip_base(name: string = "New Clip", object: THREE.Object3D, start_offset:number, end_offset:number) { + async add_transform_clip_base( + name: string = "New Clip", + object: THREE.Object3D, + start_offset: number, + end_offset: number, + ) { this.timeline.addPlayableClip( - new ClipUI(1.0, "transform", "clip2", object.uuid, object.uuid, start_offset, end_offset), + new ClipUI( + 1.0, + "transform", + "clip2", + object.uuid, + object.uuid, + start_offset, + end_offset, + ), ); this.transform_engine.loadObject(object.uuid, end_offset); } @@ -572,8 +635,8 @@ class Editor { this.composer.addPass(this.smaaPass); this.composer.addPass(this.bokehPass); - this.outputPass = new OutputPass() - this.composer.addPass(this.outputPass) + this.outputPass = new OutputPass(); + this.composer.addPass(this.outputPass); } create_parim(name: string) { @@ -628,9 +691,16 @@ class Editor { } take_timeline_cam_clip() { - if(this.cam_obj == null) { return; } - if(!this.camera_person_mode) { return; } - this.transform_engine.addFrame(this.cam_obj, this.transform_engine.clips[this.cam_obj.uuid].length); + if (this.cam_obj == null) { + return; + } + if (!this.camera_person_mode) { + return; + } + this.transform_engine.addFrame( + this.cam_obj, + this.transform_engine.clips[this.cam_obj.uuid].length, + ); console.log("Camera frame taken."); this.activeScene.createPoint(this.cam_obj.position, false); } @@ -649,7 +719,7 @@ class Editor { let delta_time = this.clock.getDelta(); if (this.cameraViewControls && this.camera_person_mode) { - this.cameraViewControls.update(5 * delta_time) + this.cameraViewControls.update(5 * delta_time); if (this.cam_obj) { if (this.timeline.isPlaying == false) { this.cam_obj.position.copy(this.camera.position); @@ -671,7 +741,7 @@ class Editor { start_playback() { this.timeline.isPlaying = true; - if(!this.camera_person_mode) { + if (!this.camera_person_mode) { this.switchCameraView(); } } diff --git a/app/pages/PageEnigma/reducers/appUiReducer/values.tsx b/app/pages/PageEnigma/reducers/appUiReducer/values.tsx index 25aa12acab..b62b819a6f 100644 --- a/app/pages/PageEnigma/reducers/appUiReducer/values.tsx +++ b/app/pages/PageEnigma/reducers/appUiReducer/values.tsx @@ -4,11 +4,12 @@ export const initialStateValues : State = { timelineHeight: 260, viewMode: VIEW_MODES.EDITOR, showEditorLoader: { - isShowing:true, - message: 'loading Editor Engine 🦊' + isShowing:false, + message: 'Loading Editor Engine 🦊' }, showEditorLoadingBar: { - isShowing:false, - progress:0, + isShowing:true, + progress:5, + message: 'Loading Editor Engine 🦊' } } \ No newline at end of file