1 /*
2 * Copyright (c) 2022 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
16 #include "core/components/scene_viewer/render_scene_viewer.h"
17
18 #include "base/log/ace_trace.h"
19 #include "core/event/ace_event_helper.h"
20 #include "graphics_manager.h"
21 #include "graphics_task.h"
22
23 namespace OHOS::Ace {
24
RenderSceneViewer(uint32_t key)25 RenderSceneViewer::RenderSceneViewer(uint32_t key) : RenderNode(true), sceneViewerAdapter_(key), key_(key)
26 {
27 Initialize();
28 }
29
~RenderSceneViewer()30 RenderSceneViewer::~RenderSceneViewer()
31 {
32 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
33 auto delegate = weak.Upgrade();
34 if (delegate) {
35 delegate->sceneViewerAdapter_.DeInitEngine();
36 OHOS::Render3D::GraphicsManager::GetInstance().UnRegister(delegate->GetKey());
37 }
38 });
39
40 auto context = context_.Upgrade();
41 if (context) {
42 context->UnregisterSurfaceChangedCallback(surfaceChangeCallbackId_);
43 }
44 }
45
Initialize()46 void RenderSceneViewer::Initialize()
47 {
48 auto wp = AceType::WeakClaim(this);
49 touchHandler_ = AceType::MakeRefPtr<SceneViewerTouchHandler>();
50 touchHandler_->SetEventCallback([wp](const OHOS::Render3D::SceneViewerTouchEvent& event) {
51 auto sv = wp.Upgrade();
52 if (sv) {
53 sv->HandleEvent(event);
54 }
55 });
56 }
57
HandleEvent(const OHOS::Render3D::SceneViewerTouchEvent & event)58 void RenderSceneViewer::HandleEvent(const OHOS::Render3D::SceneViewerTouchEvent& event)
59 {
60 ACE_SCOPED_TRACE("RenderSceneViewer::HandleEvent()");
61 switch (event.GetEventType()) {
62 case OHOS::Ace::TouchType::DOWN:
63 isClicked_ = true;
64 touchCount_++;
65 break;
66 case OHOS::Ace::TouchType::UP:
67 touchCount_--;
68 break;
69 case OHOS::Ace::TouchType::MOVE:
70 break;
71 case OHOS::Ace::TouchType::CANCEL:
72 touchCount_--;
73 break;
74 default:
75 LOGW("Unknown touch type.");
76 break;
77 }
78
79 if (!isHandleCameraMove_) {
80 if (isClicked_ && touchCount_ == 0) {
81 PerformClick();
82 }
83 isClicked_ = touchCount_ > 0;
84 return;
85 }
86
87 // Convert to LUME stuff.
88 auto context = GetContext().Upgrade();
89 if (context) {
90 #if MULTI_ECS_UPDATE_AT_ONCE
91 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), event] {
92 #else
93 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this), event] {
94 #endif
95 auto delegate = weak.Upgrade();
96 if (delegate) {
97 delegate->sceneViewerAdapter_.OnTouchEvent(event);
98 }
99 });
100 } else {
101 LOGE("ACE-3D RenderSceneViewer::HandleEvent() GetContext failed.");
102 }
103 SetNeedRender(false);
104 MarkNeedRender();
105 }
106
107 void RenderSceneViewer::RenderWithContext(RenderContext& context, const Offset& offset) {
108
109 ACE_SCOPED_TRACE("RenderSceneViewer::RenderWithContext()");
110
111 auto pipelineContext = GetContext().Upgrade();
112 if (!pipelineContext) {
113 LOGE("ACE-3D RenderSceneViewer::RenderWithContext() GetContext failed.");
114 return;
115 }
116 if (!pipelineContext->IsSurfaceReady()) {
117 // Surface not ready yet, reschedule render.
118 LOGE("ACE-3D RenderSceneViewer::RenderWithContext() Surface not ready yet.");
119 MarkNeedRender();
120 return;
121 }
122 if (!inited_) {
123 inited_ = true;
124 EGLContext eglContext = GetRenderContext();
125
126 // texture create must in sync manner
127 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([&eglContext, weak = WeakClaim(this)] {
128 auto delegate = weak.Upgrade();
129 if (!delegate) {
130 LOGE("delegate is null");
131 return;
132 }
133
134 auto& gfxManager = OHOS::Render3D::GraphicsManager::GetInstance();
135 gfxManager.Register(delegate->GetKey());
136
137 delegate->eglContext_ = gfxManager.CreateOffScreenContext(eglContext);
138 delegate->textureInfo_ = delegate->CreateRenderTarget(delegate->sceneSize_.Width(),
139 delegate->sceneSize_.Height());
140 });
141
142 PrepareTextureLayer(textureInfo_);
143
144 #if MULTI_ECS_UPDATE_AT_ONCE
145 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([&eglContext, weak = WeakClaim(this)] {
146 #else
147 // OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([&eglContext, this] {
148 // init engine in async manner sometimes crash on screen rotation
149 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([&eglContext, weak = WeakClaim(this)] {
150 #endif
151 auto delegate = weak.Upgrade();
152 if (!delegate) {
153 LOGE("delegate is null");
154 return;
155 }
156
157 auto& gfxManager = OHOS::Render3D::GraphicsManager::GetInstance();
158 auto &&engine = gfxManager.GetEngine(OHOS::Render3D::EngineFactory::EngineType::LUME, eglContext);
159 delegate->sceneViewerAdapter_.SetEngine(std::move(engine));
160 });
161 }
162
163 if (needsSceneSetup_) {
164 // Make sure needs scene setup is on, or introduce another flag
165 if (!customRenders_.empty()) {
166 PassCustomRenders(customRenders_);
167 }
168
169 if (!shapes_.empty()) {
170 PassGeometries(shapes_);
171 }
172
173 #if MULTI_ECS_UPDATE_AT_ONCE
174 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
175 #else
176 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this)] {
177 #endif
178 auto delegate = weak.Upgrade();
179 if (!delegate) {
180 LOGE("delegate is null");
181 return;
182 }
183
184 delegate->sceneViewerAdapter_.SetUpCameraTransform(
185 delegate->cameraPosition_, delegate->cameraLookAtVec_,
186 delegate->cameraUpVec_, delegate->cameraRotation_);
187 delegate->sceneViewerAdapter_.SetUpCameraViewProjection(
188 delegate->zNear_, delegate->zFar_, delegate->fovDegrees_);
189
190 auto bg_type = delegate->isTransparent_ ? OHOS::Render3D::SceneViewerBackgroundType::TRANSPARENT :
191 OHOS::Render3D::SceneViewerBackgroundType::CUBE_MAP;
192
193 // Pass the lights to backend if any.
194 if (!delegate->lights_.empty()) {
195 delegate->sceneViewerAdapter_.AddLights(delegate->lights_);
196 }
197
198 delegate->sceneViewerAdapter_.SetUpSceneViewer(delegate->textureInfo_, delegate->glTFSrc_,
199 delegate->backgroundSrc_, bg_type);
200 });
201 needsSceneSetup_ = false;
202 SetNeedRender(true);
203 }
204
205 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
206 auto delegate = weak.Upgrade();
207 if (delegate) {
208 delegate->animating_ = delegate->sceneViewerAdapter_.IsAnimating();
209 delegate->handlesNotReady_ = delegate->sceneViewerAdapter_.HandlesNotReady();
210 }
211 });
212
213 RenderNode::RenderWithContext(context, offset);
214
215 if (animating_ || handlesNotReady_) {
216 SetNeedRender(true);
217 }
218 }
219
220 void RenderSceneViewer::Paint(RenderContext& context, const Offset& offset)
221 {
222 ACE_FUNCTION_TRACE();
223
224 auto pipeline_context = GetContext().Upgrade();
225 if (pipeline_context) {
226 // auto &&ftr = OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([this] {
227 // If open MULTI_ECS_UPDATE_AT_ONCE macro SetGSVsyncCallback is called on current thread
228 // that means all the 3D engine task should be in syncorinize manner.
229 #if MULTI_ECS_UPDATE_AT_ONCE
230 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
231 #else
232 renderFinished_ = OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this)] {
233 #endif
234 auto delegate = weak.Upgrade();
235 if (delegate) {
236 delegate->sceneViewerAdapter_.DrawFrame();
237 }
238 });
239 } else {
240 LOGE("ACE-3D RenderSceneViewer::Paint() GetContext failed.");
241 }
242
243 // Texture layer position is (0,0) w.r.t to RenderNode.
244 PaintTextureLayer(context, Offset(0.0, 0.0));
245 RenderNode::Paint(context, offset);
246
247 if ((animating_ || handlesNotReady_) && pipeline_context) {
248 SetNeedRender(true);
249 pipeline_context->AddDirtyRenderNode(AceType::Claim(this), false);
250 }
251 }
252
253 void RenderSceneViewer::Update(const RefPtr<Component>& component)
254 {
255 ACE_SCOPED_TRACE("RenderSceneViewer::Update()");
256 RefPtr<SceneViewerComponent> svComponent = AceType::DynamicCast<SceneViewerComponent>(component);
257 if (!svComponent) {
258 LOGE("ACE-3D RenderSceneViewer::Update() svComponent is null!");
259 return;
260 }
261
262 bool src_updated = (!glTFSrc_.empty() && glTFSrc_ != svComponent->GetGltfSrc());
263 bool background_updated = (backgroundSrc_ != svComponent->GetBackgroundSrc());
264
265 if (src_updated || background_updated) {
266 auto pipeline_context = GetContext().Upgrade();
267 if (pipeline_context) {
268 #if MULTI_ECS_UPDATE_AT_ONCE
269 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
270 #else
271 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this)] {
272 #endif
273 auto delegate = weak.Upgrade();
274 if (delegate) {
275 delegate->sceneViewerAdapter_.UnLoadModel();
276 }
277 });
278 } else {
279 LOGE("ACE-3D RenderSceneViewer::Update() GetContext failed.");
280 }
281 }
282
283 // Update camera properties if changed.
284 if (IsCameraPropertyChanged(svComponent)) {
285 // Position is Animatable currently.
286 cameraPosition_.SetVec(svComponent->GetCameraPositionVec());
287 cameraPosition_.SetDistance(svComponent->GetCameraPosDistance());
288 cameraPosition_.SetIsAngular(svComponent->GetIsCameraPosInAngles());
289 cameraLookAtVec_ = svComponent->GetCameraLookAtVec();
290 cameraUpVec_ = svComponent->GetCameraUpVec();
291 cameraRotation_ = svComponent->GetCameraRotation();
292 zNear_ = svComponent->GetZNear();
293 zFar_ = svComponent->GetZFar();
294 fovDegrees_ = svComponent->GetFovDegrees();
295 PerformCameraUpdate();
296 }
297 needsSceneSetup_ |= (src_updated || background_updated);
298
299 if (!svComponent->GetLights().empty()) {
300 HandleLightsUpdate(svComponent);
301 }
302
303 if (!svComponent->GetGLTFAnimations().empty()) {
304 UpdateGLTFAnimations(svComponent->GetGLTFAnimations());
305 }
306
307 glTFSrc_ = svComponent->GetGltfSrc();
308 backgroundSrc_ = svComponent->GetBackgroundSrc();
309 MarkNeedLayout();
310
311 onClick_ = AceAsyncEvent<void()>::Create(svComponent->GetClickedEventId(), context_);
312 isHandleCameraMove_ = svComponent->IsHandleCameraMove();
313 isTransparent_= svComponent->IsTransparent();
314
315 if (!svComponent->GetGeometries().empty()) {
316 shapes_ = svComponent->GetGeometries();
317 needsSceneSetup_ = true;
318 }
319
320 if (!svComponent->GetCustomRenders().empty()) {
321 customRenders_ = svComponent->GetCustomRenders();
322 needsSceneSetup_ = true;
323 }
324 }
325
326 void RenderSceneViewer::PerformLayout()
327 {
328 ACE_SCOPED_TRACE("RenderSceneViewer::PerformLayout()");
329 double w = GetLayoutParam().GetMaxSize().Width();
330 double h = GetLayoutParam().GetMaxSize().Height();
331 sceneSize_ = Size(w, h);
332 SetLayoutSize(Size(w, h));
333 }
334
335 void RenderSceneViewer::OnPaintFinish() {}
336
337 void RenderSceneViewer::OnSurfaceChanged()
338 {
339 ACE_SCOPED_TRACE("RenderSceneViewer::OnSurfaceChanged key: %d", GetKey());
340 if (inited_) {
341 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
342 auto delegate = weak.Upgrade();
343 if (delegate) {
344 delegate->sceneViewerAdapter_.DeInitEngine();
345 OHOS::Render3D::GraphicsManager::GetInstance().UnRegister(delegate->GetKey());
346 }
347 });
348 inited_ = false;
349 SetNeedRender(false);
350 MarkNeedRender();
351 needsSceneSetup_ = true;
352 }
353 }
354
355 void RenderSceneViewer::ClearRenderObject() {
356 RenderNode::ClearRenderObject();
357 }
358
359 uint32_t RenderSceneViewer::GetKey() {
360 return key_;
361 }
362
363 Size RenderSceneViewer::GetSize() {
364 return sceneSize_;
365 }
366
367 void RenderSceneViewer::OnTouchTestHit(
368 const Offset& coordinateOffset, const TouchRestrict& touchRestrict, TouchTestResult& result) {
369 ACE_SCOPED_TRACE("RenderSceneViewer::OnTouchTestHit()");
370 touchHandler_->SetCoordinateOffset(coordinateOffset);
371 result.emplace_back(touchHandler_);
372 }
373
374 void RenderSceneViewer::PerformClick()
375 {
376 if (onClick_) {
377 onClick_();
378 }
379 }
380
381 void RenderSceneViewer::PerformCameraUpdate()
382 {
383 UpdateCameraOnly();
384 }
385
386 void RenderSceneViewer::UpdateCameraOnly()
387 {
388 ACE_SCOPED_TRACE("RenderSceneViewer::UpdateCameraOnly()");
389 auto pipeline_context = GetContext().Upgrade();
390 if (pipeline_context) {
391 #if MULTI_ECS_UPDATE_AT_ONCE
392 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
393 #else
394 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this)] {
395 #endif
396 auto delegate = weak.Upgrade();
397 if (delegate) {
398 delegate->sceneViewerAdapter_.SetUpCameraTransform(delegate->cameraPosition_,
399 delegate->cameraLookAtVec_, delegate->cameraUpVec_, delegate->cameraRotation_);
400 delegate->sceneViewerAdapter_.SetUpCameraViewProjection(
401 delegate->zNear_, delegate->zFar_, delegate->fovDegrees_);
402 }
403 });
404 MarkNeedLayout();
405 } else {
406 LOGE("ACE-3D RenderSceneViewer::UpdateCameraOnly() GetContext failed.");
407 }
408 }
409
410 void RenderSceneViewer::PerformLightUpdate()
411 {
412 UpdateLightOnly();
413 }
414
415 void RenderSceneViewer::UpdateLightOnly()
416 {
417 ACE_SCOPED_TRACE("RenderSceneViewer::UpdateLightOnly()");
418 auto pipeline_context = GetContext().Upgrade();
419 if (pipeline_context) {
420 #if MULTI_ECS_UPDATE_AT_ONCE
421 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this)] {
422 #else
423 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this)] {
424 #endif
425 auto delegate = weak.Upgrade();
426 if (delegate) {
427 delegate->sceneViewerAdapter_.AddLights(delegate->lights_);
428 delegate->sceneViewerAdapter_.CreateLight();
429 }
430 });
431 MarkNeedLayout();
432 } else {
433 LOGE("ACE-3D RenderSceneViewer::UpdateLightOnly() GetContext failed.");
434 }
435 }
436
437 // Save the geometry if engine not start up
438 void RenderSceneViewer::PassGeometries(const std::vector<RefPtr<OHOS::Render3D::SVGeometry>>& geometries)
439 {
440 auto pipeline_context = GetContext().Upgrade();
441 if (pipeline_context) {
442 #if MULTI_ECS_UPDATE_AT_ONCE
443 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &geometries] {
444 #else
445 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this), &geometries] {
446 #endif
447 auto delegate = weak.Upgrade();
448 if (delegate) {
449 delegate->sceneViewerAdapter_.UpdateGeometries(geometries);
450 }
451 });
452 } else {
453 LOGE("ACE-3D RenderSceneViewer::PassGeometries() GetContext failed.");
454 }
455 }
456
457 // Save the gltf animation if engine not start up
458 void RenderSceneViewer::UpdateGLTFAnimations(const std::vector<RefPtr<OHOS::Render3D::GLTFAnimation>>& gltfAnimations)
459 {
460 ACE_SCOPED_TRACE("RenderSceneViewer::UpdateGLTFAnimations()");
461 auto pipeline_context = GetContext().Upgrade();
462 if (!pipeline_context) {
463 LOGE("RenderSceneViewer::UpdateGLTFAnimations() GetContext failed.");
464 return;
465 }
466
467 #if MULTI_ECS_UPDATE_AT_ONCE
468 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), gltfAnimations] {
469 #else
470 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this), gltfAnimations] {
471 #endif
472 auto delegate = weak.Upgrade();
473 if (delegate) {
474 delegate->sceneViewerAdapter_.UpdateGLTFAnimations(gltfAnimations);
475 delegate->animating_ = delegate->sceneViewerAdapter_.IsAnimating();
476 }
477 });
478 }
479
480 bool RenderSceneViewer::IsCameraPropertyChanged(const RefPtr<SceneViewerComponent>& svComponent)
481 {
482 if (!svComponent) {
483 LOGE("ACE-3D RenderSceneViewer::IsCameraPropertyChanged() svComponent is null!");
484 return false;
485 }
486
487 if (cameraPosition_.GetVec() != svComponent->GetCameraPositionVec()
488 || cameraPosition_.GetDistance() != svComponent->GetCameraPosDistance()
489 || !NearEqual(zNear_, svComponent->GetZNear())
490 || !NearEqual(zFar_, svComponent->GetZFar())
491 || !NearEqual(fovDegrees_, svComponent->GetFovDegrees())
492 || cameraLookAtVec_ != svComponent->GetCameraLookAtVec()
493 || cameraUpVec_ != svComponent->GetCameraUpVec()
494 || cameraRotation_ != svComponent->GetCameraRotation()) {
495 return true;
496 }
497 return false;
498 }
499
500 void RenderSceneViewer::HandleLightsUpdate(const RefPtr<SceneViewerComponent>& svComponent)
501 {
502 if (!svComponent) {
503 LOGE("ACE-3D RenderSceneViewer::HandleLightsUpdate() svComponent is null!");
504 return;
505 }
506
507 // First time update. Attach the animation callbacks.
508 if (lights_.empty()) {
509 lights_ = svComponent->GetLights();
510 for (auto& light : lights_) {
511 light->SetContextAndCallback(
512 context_,
513 std::bind(&RenderSceneViewer::PerformLightUpdate, this));
514 }
515 PerformLightUpdate();
516 return;
517 }
518
519 if (!IsLightPropertyChanged(svComponent)) {
520 return;
521 }
522
523 std::vector<OHOS::Ace::RefPtr<OHOS::Render3D::SVLight>> newLights = svComponent->GetLights();
524
525 int index = 0;
526 for (auto& light : lights_) {
527 light->SetLightType(newLights.at(index)->GetLightType());
528 light->SetIntensity(newLights.at(index)->GetLightIntensity());
529 light->SetColor(newLights.at(index)->GetLightColor());
530 light->SetLightShadow(newLights.at(index)->GetLightShadow());
531 light->SetPosition(newLights.at(index)->GetPosition());
532 light->SetRotation(newLights.at(index)->GetRotation());
533 index++;
534 }
535 PerformLightUpdate();
536 }
537
538 bool RenderSceneViewer::IsLightPropertyChanged(const RefPtr<SceneViewerComponent>& svComponent)
539 {
540 if (!svComponent) {
541 LOGE("ACE-3D RenderSceneViewer::IsLightPropertyChanged() svComponent is null!");
542 return false;
543 }
544
545 std::vector<OHOS::Ace::RefPtr<OHOS::Render3D::SVLight>> newLights = svComponent->GetLights();
546 int index = 0;
547 for (auto& light : lights_) {
548 if (light->GetLightType() != newLights.at(index)->GetLightType()
549 || light->GetLightIntensity() != newLights.at(index)->GetLightIntensity()
550 || light->GetLightColor() != newLights.at(index)->GetLightColor()
551 || light->GetLightShadow() != newLights.at(index)->GetLightShadow()
552 || light->GetPosition().GetVec() != newLights.at(index)->GetPosition().GetVec()
553 || light->GetPosition().GetDistance() != newLights.at(index)->GetPosition().GetDistance()
554 || light->GetRotation() != newLights.at(index)->GetRotation()) {
555 return true;
556 }
557 index++;
558 }
559 return false;
560 }
561
562 // Save the custom renders if engine not start up
563 void RenderSceneViewer::PassCustomRenders(
564 const std::vector<RefPtr<OHOS::Render3D::SVCustomRenderDescriptor>>& customRenders)
565 {
566 auto pipeline_context = GetContext().Upgrade();
567 if (pipeline_context) {
568 #if MULTI_ECS_UPDATE_AT_ONCE
569 OHOS::Render3D::GraphicsTask::GetInstance().PushSyncMessage([weak = WeakClaim(this), &customRenders] {
570 #else
571 OHOS::Render3D::GraphicsTask::GetInstance().PushAsyncMessage([weak = WeakClaim(this), &customRenders] {
572 #endif
573 auto delegate = weak.Upgrade();
574 if (delegate) {
575 delegate->sceneViewerAdapter_.AddCustomRenders(customRenders);
576 }
577 });
578 } else {
579 LOGE("ACE-3D RenderSceneViewer::PassCustomRenders() GetContext failed.");
580 }
581 }
582
583 } // namespace OHOS::Ace
584