diff --git a/app/contexts/EngineProvider.tsx b/app/contexts/EngineProvider.tsx index 7c708816c4..0f3b833631 100644 --- a/app/contexts/EngineProvider.tsx +++ b/app/contexts/EngineProvider.tsx @@ -6,7 +6,6 @@ import { import { EngineContext } from "./EngineContext"; import Editor from "~/pages/PageEnigma/js/editor"; - interface Props{ children:ReactNode; } @@ -14,7 +13,6 @@ interface Props{ export const EngineProvider = ({ children }: Props)=>{ const editorRef = useRef(null); - useEffect(() => { //componentDidMount if (editorRef.current !== null ) { diff --git a/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx b/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx index 91fc1f3f04..77bee33df9 100644 --- a/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx +++ b/app/pages/PageEnigma/comps/ControlsTopButtons/ControlsTopButtons.tsx @@ -27,7 +27,9 @@ export const ControlsTopButtons = () => { document.getElementById("load-upload")?.click(); }; const handleButtonRender = () => { - editorEngine?.togglePlayback(); + console.log("Saving GLB to server for reference") + editorEngine._upload_for_testing() + //editorEngine?.togglePlayback(); }; const handleButtonPlay = () => {}; diff --git a/app/pages/PageEnigma/js/api_manager.ts b/app/pages/PageEnigma/js/api_manager.ts index 82125b5a8a..6672e6ccce 100644 --- a/app/pages/PageEnigma/js/api_manager.ts +++ b/app/pages/PageEnigma/js/api_manager.ts @@ -1,21 +1,39 @@ -import { v4 as uuidv4 } from 'uuid'; - -import { Scene } from '../datastructures/scene/scene_object'; +import { v4 as uuidv4 } from 'uuid' +import { Scene } from '../datastructures/scene/scene_object' +import * as THREE from 'three' +import { GLTFExporter } from 'three/addons/exporters/GLTFExporter.js' +import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js' +import { TimelineCurrentReactState } from './timeline' // Basically the data will exist on the database -class MediaUploadManager { +class APIManager { baseUrl:String constructor() { - this.baseUrl = "https://api.fakeyou.com"; + this.baseUrl = "https://api.fakeyou.com" //this.baseUrl = "http://localhost:12345" } - async saveScene(scene:Scene):Promise { - // we want to upload the glb first then use the engine asset idea from there + + // Function to save or update the scene + async saveSceneState(scene:THREE.Scene, + timeLine:TimelineCurrentReactState, + scene_id:string | null =null):Promise { + if (scene_id == null) { + // create new scene. + let file = await this.gltfExport(scene) + let response = await this.uploadGLB(file) + console.log(response) + } else { + // update scene or overwrite glb scene. + } return "" } + async _saveSceneAndTimelineToJSONSpec() { + + } + async loadScene(scene_token:[]):Promise { return "" @@ -26,16 +44,24 @@ class MediaUploadManager { return "" } + async gltfExport(scene:THREE.Scene) { + let gltfExporter = new GLTFExporter() + let uuid = uuidv4() + // save the scene to keep ids positions etc + let result = await gltfExporter.parseAsync(scene) + const file = new File([JSON.stringify(result)], `${uuid}.glb`, {type: 'application/json'}) + return file + } // two core functions to upload things to the server and get id's async uploadMedia(blob:any, fileName:string):Promise { - const url = `${this.baseUrl}/v1/media_uploads/upload`; - let uuid = uuidv4(); - const formData = new FormData(); - formData.append('uuid_idempotency_token', uuid); - formData.append('file', blob, fileName); - formData.append('source', 'file'); - formData.append('type', 'video'); - formData.append('source', 'file'); + const url = `${this.baseUrl}/v1/media_uploads/upload` + let uuid = uuidv4() + const formData = new FormData() + formData.append('uuid_idempotency_token', uuid) + formData.append('file', blob, fileName) + formData.append('source', 'file') + formData.append('type', 'video') + formData.append('source', 'file') const response = await fetch(url, { method: 'POST', credentials: "include", @@ -43,24 +69,25 @@ class MediaUploadManager { "Accept": "application/json", }, body: formData, - }); + }) if (!response.ok) { - throw new Error('Failed to Send Data'); + throw new Error('Failed to Send Data') } - return response.json(); // or handle the response as appropriate + return response.json() // or handle the response as appropriate } + // to save to a file then upload the scene. async uploadGLB(file:File):Promise { - const url = `${this.baseUrl}/v1/media_files/upload/engine_asset`; - let uuid = uuidv4(); - const formData = new FormData(); - formData.append('uuid_idempotency_token', uuid); - formData.append('file', file); - formData.append('source','file'); - formData.append('media_file_subtype', 'scene_import'); - formData.append('media_file_class', 'scene'); + const url = `${this.baseUrl}/v1/media_files/upload/engine_asset` + let uuid = uuidv4() + const formData = new FormData() + formData.append('uuid_idempotency_token', uuid) + formData.append('file', file) + formData.append('source','file') + formData.append('media_file_subtype', 'scene_import') + formData.append('media_file_class', 'scene') const response = await fetch(url, { method: 'POST', credentials: "include", @@ -68,13 +95,13 @@ class MediaUploadManager { "Accept": "application/json", }, body: formData, - }); + }) if (!response.ok) { - throw new Error('Failed to Send Data'); + throw new Error('Failed to Send Data') } - return response.json(); // or handle the response as appropriate + return response.json() // or handle the response as appropriate } } -export default MediaUploadManager; +export default APIManager diff --git a/app/pages/PageEnigma/js/editor.js b/app/pages/PageEnigma/js/editor.js index 563367f0b4..77320ecc35 100644 --- a/app/pages/PageEnigma/js/editor.js +++ b/app/pages/PageEnigma/js/editor.js @@ -3,7 +3,7 @@ import { OrbitControls } from 'three/addons/controls/OrbitControls.js'; import { TransformControls } from 'three/addons/controls/TransformControls.js'; import Scene from './scene.js'; import SaveManager from './serialization.js'; -import MediaUploadManager from './api_manager.ts'; +import APIManager from './api_manager.ts'; import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js'; import { RenderPass } from 'three/addons/postprocessing/RenderPass.js'; import { OutlinePass } from 'three/addons/postprocessing/OutlinePass.js'; @@ -23,6 +23,7 @@ import { LipSync } from './lipsync.js'; import { LipSyncEngine } from "./lip_sync_engine.ts"; import { AnimationEngine} from "./animation_engine.ts"; import { faL } from '@fortawesome/pro-solid-svg-icons'; + if (typeof window !== 'undefined') { import('ccapture.js').then(module => { const CCapture = module.CCapture; @@ -79,7 +80,7 @@ class Editor { this.transform_interaction; this.rendering = false; // API. - this.api_manager = new MediaUploadManager(); + this.api_manager = new APIManager(); // Debug & Movement. this.stats = null; this.orbit = null; @@ -158,14 +159,33 @@ class Editor { this._test_demo() } + // uploading some objects for testing to get their media ids from my account. + async _upload_for_testing() { + // have to upload as a file first + + // This is the default scene. + // "m_189p8hj0eyypbg74kkhcpehwpjhnkz" scene with the fox. + let result = await this.api_manager.saveSceneState(this.activeScene.scene) + console.log(result) + } + async _test_demo() { + // note the database from the server is the source of truth for all the data. // Test code here let object = await this.activeScene.load_glb("./resources/models/fox/fox.glb") + + // load object into the engine for lip syncing this.lipsync_engine.load_object(object.uuid, "m_f1jxx4zwy4da2zn0cvdqhha7kqkj72"); + + // create the clip with the same id for a reference to the media this.timeline.addPlayableClip(new ClipUI(1.0, "lipsync", "clip1", "m_f1jxx4zwy4da2zn0cvdqhha7kqkj72", object.uuid, 150, 400)); + + // media id for this is up in the air but when a path is created you should be able to store and delete it this.timeline.addPlayableClip(new ClipUI(1.0, "transform", "clip2", object.uuid, object.uuid, 0, 150)); - this.animation_engine.load_object(object.uuid, "/resources/models/fox/fox_idle.glb", "clip3"); + + // media id for this as well it can be downloaded this.timeline.addPlayableClip(new ClipUI(1.0, "animation", "clip3", "/resources/models/fox/fox_idle.glb", object.uuid, 0, 400)); + this.animation_engine.load_object(object.uuid, "/resources/models/fox/fox_idle.glb", "clip3"); } // Configure post processing. @@ -287,9 +307,9 @@ class Editor { this.timeline.isPlaying = true; } - _save_to_cloud(blob) { - this.api_manager.uploadGLB(blob, "test.glb"); - } + // _save_to_cloud(blob) { + // this.api_manager.uploadGLB(blob, "test.glb"); + // } change_mode(type) { this.control.mode = type;