1/* 2 * Copyright (c) 2024 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import scene3d from '@ohos.graphics.scene' 17import router from '@ohos.router'; 18import animator, { AnimatorResult } from '@ohos.animator'; 19import Logger from '../util/Logger'; 20 21@Entry 22@Component 23struct sceneAnimation { 24 scene: scene3d.Scene | null = null; 25 @State sceneOpt: SceneOptions | null = null; 26 cam: scene3d.Camera | null = null; 27 @State progressValue: number = 0; 28 29 @State animationEnabled: Boolean = false; 30 @State animationDuration: number = 0; 31 @State animationIsRunning: Boolean = false; 32 @State animationCallbackInvoked: string = 'no invoked callback' 33 34 backAnimator: AnimatorResult | undefined = undefined; 35 36 onPageShow(): void { 37 this.init(); 38 } 39 40 onPageHide(): void { 41 if (this.scene) { 42 this.scene.destroy(); 43 } 44 45 this.cam = null; 46 this.scene = null; 47 } 48 49 init(): void { 50 this.backAnimator = animator.create({ 51 duration: 2000, // duration 52 easing: "ease", 53 delay: 0, 54 fill: "none", 55 direction: "normal", 56 iterations: -1, // endless loop 57 begin: 100, // begin 58 end: 200 // end 59 }) 60 this.backAnimator.onframe = value => { 61 if (this.scene?.animations[0]) { 62 this.animationEnabled = this.scene.animations[0].enabled; 63 this.animationDuration = this.scene.animations[0].duration; 64 this.animationIsRunning = this.scene.animations[0].running; 65 this.progressValue = this.scene.animations[0].progress; 66 } 67 } 68 if (this.scene === null) { 69 scene3d.Scene.load($rawfile("gltf/BrainStem/glTF/BrainStem.glb")) 70 .then(async (result: scene3d.Scene) => { 71 this.scene = result; 72 this.sceneOpt = { scene: this.scene, modelType: ModelType.SURFACE } as SceneOptions; 73 let rf = this.scene.getResourceFactory(); 74 this.cam = await rf.createCamera({ "name": "Camera1" }); 75 this.cam.enabled = true; 76 this.cam.position.z = 5; 77 78 let env = await rf.createEnvironment({ "name": "Env" }); 79 this.scene.environment.backgroundType = scene3d.EnvironmentBackgroundType.BACKGROUND_IMAGE; 80 this.scene.environment.environmentImage = await rf.createImage({ name: "envImg1", uri: $rawfile("gltf/DamagedHelmet/glTF/Default_normal.jpg") }); 81 }) 82 .catch((reason: string) => { 83 Logger.error("init error", reason); 84 }); 85 } 86 } 87 88 build() { 89 Row() { 90 Column() { 91 Column() { 92 if (this.sceneOpt) { 93 Component3D(this.sceneOpt) 94 .renderWidth('60%') 95 .renderHeight('60%') 96 .onAppear(()=>{ 97 if (!this.scene || !this.scene.animations[0]) { 98 return; 99 } 100 let count = this.scene.animations.length; 101 102 let anim: scene3d.Animation = this.scene.animations[0]; 103 anim.onStarted(()=>{ 104 this.animationCallbackInvoked = 'animation on start' 105 }); 106 anim.onFinished(() => { 107 this.animationCallbackInvoked = 'animation on finish' 108 }); 109 this.backAnimator?.play(); 110 }) 111 } 112 else { 113 Text("loading 1..."); 114 } 115 } 116 .height('30%') 117 118 Row() { 119 Text ("progress: " + (this.progressValue * 100).toFixed(2) + '%') 120 } 121 Text("Duration: " + this.animationDuration.toFixed(2) + "S"); 122 Text("Running: " + this.animationIsRunning); 123 Text("enabled: " + this.animationEnabled); 124 125 Text("animation invoked callback:" + this.animationCallbackInvoked); 126 127 Button('enable animation').onClick(() => { 128 if (!this.scene || !this.scene.animations[0]) { 129 return; 130 } 131 132 this.scene.animations[0].enabled = !this.scene.animations[0].enabled; 133 }).id('enable_animation'); 134 135 Button('start').onClick(async () => { 136 if (!this.scene || !this.scene.animations[0]) { 137 return; 138 } 139 let anim: scene3d.Animation = this.scene.animations[0]; 140 anim.start(); 141 }).id('start_animation'); 142 143 Button('pause').onClick(async () => { 144 if (!this.scene || !this.scene.animations[0]) { 145 return; 146 } 147 let anim: scene3d.Animation = this.scene.animations[0]; 148 anim.pause(); 149 }).id('pause_animation'); 150 151 Button('stop').onClick(async () => { 152 if (!this.scene || !this.scene.animations[0]) { 153 return; 154 } 155 let anim: scene3d.Animation = this.scene.animations[0]; 156 anim.stop(); 157 }).id('stop_animation'); 158 159 Button('finish').onClick(async () => { 160 if (!this.scene || !this.scene.animations[0]) { 161 return; 162 } 163 let anim: scene3d.Animation = this.scene.animations[0]; 164 anim.finish(); 165 }).id('finish_animation'); 166 167 Button('restart').onClick(async () => { 168 if (!this.scene || !this.scene.animations[0]) { 169 return; 170 } 171 let anim: scene3d.Animation = this.scene.animations[0]; 172 anim.restart(); 173 }).id('restart_animation'); 174 175 Button('seek to 30% progress').onClick(async () => { 176 if (!this.scene || !this.scene.animations[0]) { 177 return; 178 } 179 let anim: scene3d.Animation = this.scene.animations[0]; 180 // seek to 30% 181 anim.seek(0.3); 182 }).id('seek_animation'); 183 184 Button('back').onClick(() => { 185 router.back() 186 }).id('back_animation') 187 } 188 .width('100%') 189 } 190 .height('100%') 191 } 192}