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 #include <scene_plugin/api/camera_uid.h>
16 #include <scene_plugin/api/postprocess_uid.h>
17 
18 #include <meta/ext/concrete_base_object.h>
19 
20 #include "bind_templates.inl"
21 #include "intf_postprocess_private.h"
22 #include "node_impl.h"
23 #include "task_utils.h"
24 
25 using SCENE_NS::MakeTask;
26 
27 namespace {
28 class CameraImpl
29     : public META_NS::ConcreteBaseMetaObjectFwd<CameraImpl, NodeImpl, SCENE_NS::ClassId::Camera, SCENE_NS::ICamera> {
30     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, FoV, 60.f * BASE_NS::Math::DEG2RAD)
31     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, AspectRatio, -1.f)
32     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, NearPlane, 0.3f)
33     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, FarPlane, 1000.f)
34     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, XMagnification, 0.f)
35     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, YMagnification, 0.f)
36     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, XOffset, 1.f)
37     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, YOffset, 1.f)
38     META_IMPLEMENT_INTERFACE_PROPERTY(
39         SCENE_NS::ICamera, uint8_t, Projection, SCENE_NS::ICamera::SCENE_CAM_PROJECTION_PERSPECTIVE)
40     META_IMPLEMENT_INTERFACE_PROPERTY(
41         SCENE_NS::ICamera, uint8_t, Culling, SCENE_NS::ICamera::SCENE_CAM_CULLING_VIEW_FRUSTUM)
42     META_IMPLEMENT_INTERFACE_PROPERTY(
43         SCENE_NS::ICamera, uint8_t, RenderingPipeline, SCENE_NS::ICamera::SCENE_CAM_PIPELINE_FORWARD)
44     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, uint32_t, SceneFlags, 0)
45     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, uint32_t, PipelineFlags, (1 << 3))
46     META_IMPLEMENT_INTERFACE_PROPERTY(
47         SCENE_NS::ICamera, BASE_NS::Math::Vec4, Viewport, BASE_NS::Math::Vec4(0.f, 0.f, 1.f, 1.f))
48     META_IMPLEMENT_INTERFACE_PROPERTY(
49         SCENE_NS::ICamera, BASE_NS::Math::Vec4, Scissor, BASE_NS::Math::Vec4(0.f, 0.f, 1.f, 1.f))
50     META_IMPLEMENT_INTERFACE_PROPERTY(
51         SCENE_NS::ICamera, BASE_NS::Math::UVec2, RenderTargetSize, BASE_NS::Math::UVec2(0, 0))
52     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, SCENE_NS::Color, ClearColor, SCENE_NS::Colors::TRANSPARENT)
53     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, float, ClearDepth, 1.f)
54     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, BASE_NS::string, RenderNodeGraphFile, {})
55     META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::ICamera, SCENE_NS::IPostProcess::Ptr, PostProcess, {})
56 
57     static constexpr BASE_NS::string_view CAMERA_COMPONENT_NAME = "CameraComponent";
58     static constexpr size_t CAMERA_COMPONENT_NAME_LEN = CAMERA_COMPONENT_NAME.size() + 1;
59     static constexpr BASE_NS::string_view CAMERA_FOV = "CameraComponent.yFov";
60     static constexpr BASE_NS::string_view CAMERA_ASPECT = "CameraComponent.aspect";
61     static constexpr BASE_NS::string_view CAMERA_ZNEAR = "CameraComponent.zNear";
62     static constexpr BASE_NS::string_view CAMERA_ZFAR = "CameraComponent.zFar";
63     static constexpr BASE_NS::string_view CAMERA_XMAG = "CameraComponent.xMag";
64     static constexpr BASE_NS::string_view CAMERA_YMAG = "CameraComponent.yMag";
65     static constexpr BASE_NS::string_view CAMERA_XOFFSET = "CameraComponent.xOffset";
66     static constexpr BASE_NS::string_view CAMERA_YOFFSET = "CameraComponent.yOffset";
67     static constexpr BASE_NS::string_view CAMERA_PROJECTION = "CameraComponent.projection";
68     static constexpr BASE_NS::string_view CAMERA_CULLING = "CameraComponent.culling";
69     static constexpr BASE_NS::string_view CAMERA_RENDERINGPIPELINE = "CameraComponent.renderingPipeline";
70     static constexpr BASE_NS::string_view CAMERA_SCENEFLAGS = "CameraComponent.sceneFlags";
71     static constexpr BASE_NS::string_view CAMERA_PIPELINEFLAGS = "CameraComponent.pipelineFlags";
72     static constexpr BASE_NS::string_view CAMERA_SCISSOR = "CameraComponent.scissor";
73     static constexpr BASE_NS::string_view CAMERA_VIEWPORT = "CameraComponent.viewport";
74     static constexpr BASE_NS::string_view CAMERA_CLEARCOLORVALUE = "CameraComponent.clearColorValue";
75     static constexpr BASE_NS::string_view CAMERA_CLEARDEPTHVALUE = "CameraComponent.clearDepthValue";
76     static constexpr BASE_NS::string_view CAMERA_LAYERMASK = "CameraComponent.layerMask";
77     static constexpr BASE_NS::string_view CAMERA_RENDERRESOLUTION = "CameraComponent.renderResolution";
78     static constexpr BASE_NS::string_view CAMERA_POSTPROCESS = "CameraComponent.postProcess";
79 
Build(const IMetadata::Ptr & data)80     bool Build(const IMetadata::Ptr& data) override
81     {
82         bool ret = false;
83         if (ret = NodeImpl::Build(data); ret) {
84             PropertyNameMask()[CAMERA_COMPONENT_NAME] = { CAMERA_FOV.substr(CAMERA_COMPONENT_NAME_LEN),
85                 CAMERA_ASPECT.substr(CAMERA_COMPONENT_NAME_LEN), CAMERA_ZNEAR.substr(CAMERA_COMPONENT_NAME_LEN),
86                 CAMERA_ZFAR.substr(CAMERA_COMPONENT_NAME_LEN), CAMERA_XMAG.substr(CAMERA_COMPONENT_NAME_LEN),
87                 CAMERA_YMAG.substr(CAMERA_COMPONENT_NAME_LEN), CAMERA_XOFFSET.substr(CAMERA_COMPONENT_NAME_LEN),
88                 CAMERA_YOFFSET.substr(CAMERA_COMPONENT_NAME_LEN), CAMERA_PROJECTION.substr(CAMERA_COMPONENT_NAME_LEN),
89                 CAMERA_CULLING.substr(CAMERA_COMPONENT_NAME_LEN),
90                 CAMERA_RENDERINGPIPELINE.substr(CAMERA_COMPONENT_NAME_LEN),
91                 CAMERA_SCENEFLAGS.substr(CAMERA_COMPONENT_NAME_LEN),
92                 CAMERA_PIPELINEFLAGS.substr(CAMERA_COMPONENT_NAME_LEN),
93                 CAMERA_SCISSOR.substr(CAMERA_COMPONENT_NAME_LEN), CAMERA_VIEWPORT.substr(CAMERA_COMPONENT_NAME_LEN),
94                 CAMERA_CLEARCOLORVALUE.substr(CAMERA_COMPONENT_NAME_LEN),
95                 CAMERA_CLEARDEPTHVALUE.substr(CAMERA_COMPONENT_NAME_LEN),
96                 CAMERA_LAYERMASK.substr(CAMERA_COMPONENT_NAME_LEN),
97                 CAMERA_POSTPROCESS.substr(CAMERA_COMPONENT_NAME_LEN),
98                 CAMERA_RENDERRESOLUTION.substr(CAMERA_COMPONENT_NAME_LEN) };
99         }
100         return ret;
101     }
102 
CompleteInitialization(const BASE_NS::string & path)103     bool CompleteInitialization(const BASE_NS::string& path) override
104     {
105         if (!NodeImpl::CompleteInitialization(path)) {
106             return false;
107         }
108 
109         auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_);
110         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(FoV), meta, CAMERA_FOV);
111         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(AspectRatio), meta, CAMERA_ASPECT);
112         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(NearPlane), meta, CAMERA_ZNEAR);
113         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(FarPlane), meta, CAMERA_ZFAR);
114         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(XMagnification), meta, CAMERA_XMAG);
115         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(YMagnification), meta, CAMERA_YMAG);
116         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(XOffset), meta, CAMERA_XOFFSET);
117         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(YOffset), meta, CAMERA_YOFFSET);
118         BindChanges<uint8_t>(propHandler_, META_ACCESS_PROPERTY(Projection), meta, CAMERA_PROJECTION);
119         BindChanges<uint8_t>(propHandler_, META_ACCESS_PROPERTY(Culling), meta, CAMERA_CULLING);
120         BindChanges<uint8_t>(propHandler_, META_ACCESS_PROPERTY(RenderingPipeline), meta, CAMERA_RENDERINGPIPELINE);
121         BindChanges<uint32_t>(propHandler_, META_ACCESS_PROPERTY(SceneFlags), meta, CAMERA_SCENEFLAGS);
122         BindChanges<uint32_t>(propHandler_, META_ACCESS_PROPERTY(PipelineFlags), meta, CAMERA_PIPELINEFLAGS);
123         BindChanges<BASE_NS::Math::Vec4>(propHandler_, META_ACCESS_PROPERTY(Scissor), meta, CAMERA_SCISSOR);
124         BindChanges<BASE_NS::Math::Vec4>(propHandler_, META_ACCESS_PROPERTY(Viewport), meta, CAMERA_VIEWPORT);
125         ConvertBindChanges<SCENE_NS::Color, BASE_NS::Math::Vec4>(
126             propHandler_, META_ACCESS_PROPERTY(ClearColor), meta, CAMERA_CLEARCOLORVALUE);
127         BindChanges<float>(propHandler_, META_ACCESS_PROPERTY(ClearDepth), meta, CAMERA_CLEARDEPTHVALUE);
128 
129         // override INode default handling for LayerMask
130         BindChanges<uint64_t>(propHandler_, NodeImpl::META_ACCESS_PROPERTY(LayerMask), meta, CAMERA_LAYERMASK);
131 
132         if (auto scene = GetScene()) {
133             propHandler_.NewHandler(nullptr, nullptr)
134                 .Subscribe(META_ACCESS_PROPERTY(RenderTargetSize),
135                     META_NS::MakeCallback<META_NS::IOnChanged>(
136                         [this](const auto& scene) {
137                             if (auto ecsObject = EcsObject(); scene && ecsObject) {
138                                 auto renderSize = META_NS::GetValue(RenderTargetSize());
139                                 if (renderSize.x != 0 && renderSize.y != 0) {
140                                     SceneHolder()->SetRenderSize(renderSize.x, renderSize.y, ecsObject->GetEntity().id);
141                                 }
142                             }
143                         },
144                         scene));
145         } else {
146             // Engine side does not automatically resize camera resources even the size changes
147             BindChanges<BASE_NS::Math::UVec2>(
148                 propHandler_, META_ACCESS_PROPERTY(RenderTargetSize), meta, CAMERA_RENDERRESOLUTION);
149         }
150 
151         if (auto postProcess = meta->GetPropertyByName(CAMERA_POSTPROCESS)) {
152             // To quickly test / verify post-process bindings
153             // callback to carry out when toolkit side changes
154             auto metaCallback = [this](META_NS::IProperty::Ptr postProcessEntity,
155                                     SCENE_NS::IPostProcess::Ptr postProcessBridge) {
156                 auto typed = META_NS::Property<CORE_NS::Entity>(postProcessEntity);
157                 auto entity = META_NS::GetValue(typed);
158                 auto sh = SceneHolder();
159                 auto ecs = sh->GetEcs();
160                 if (!CORE_NS::EntityUtil::IsValid(entity)) {
161                     // engine does not have existing entity, create new one
162                     entity = sh->CreatePostProcess();
163                     META_NS::SetValue(typed, entity);
164                 }
165                 // values from toolkit dominate initialization
166                 interface_cast<IPostProcessPrivate>(postProcessBridge)->SetEntity(entity, sh, false);
167             };
168 
169             // callback to carry out if the engine side drives the change
170             auto engineCallback = [this](META_NS::IProperty::Ptr postProcessEntity) {
171                 auto entity = META_NS::GetValue(META_NS::Property<CORE_NS::Entity>(postProcessEntity));
172                 auto sh = SceneHolder();
173                 auto ecs = sh->GetEcs();
174                 if (!CORE_NS::EntityUtil::IsValid(entity)) {
175                     META_NS::SetValue(PostProcess(), SCENE_NS::IPostProcess::Ptr {});
176                 } else {
177                     auto ppo = META_NS::GetObjectRegistry().Create<IPostProcessPrivate>(SCENE_NS::ClassId::PostProcess);
178                     // values from ecs dominate initialization
179                     ppo->SetEntity(entity, sh, true);
180                     META_NS::SetValue(PostProcess(), interface_pointer_cast<SCENE_NS::IPostProcess>(ppo));
181                 }
182             };
183 
184             if (auto bridge = META_NS::GetValue(PostProcess())) {
185                 metaCallback(postProcess, bridge);
186             } else {
187                 engineCallback(postProcess);
188             }
189 
190             // setup subscription for toolkit changes
191             PostProcess()->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this, metaCallback]() {
192                 if (auto bridge = META_NS::GetValue(PostProcess())) {
193                     if (auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_)) {
194                         if (auto postProcess = meta->GetPropertyByName(CAMERA_POSTPROCESS)) {
195                             metaCallback(postProcess, bridge);
196                         }
197                     }
198                 } else {
199                     if (auto meta = interface_pointer_cast<META_NS::IMetadata>(ecsObject_)) {
200                         if (auto postProcess = meta->GetPropertyByName(CAMERA_POSTPROCESS)) {
201                             if (auto typed = META_NS::Property<CORE_NS::Entity>(postProcess)) {
202                                 META_NS::SetValue(typed, CORE_NS::Entity());
203                             }
204                         }
205                     }
206                 }
207             }),
208                 reinterpret_cast<uint64_t>(this));
209 
210             // setup subscription to ecs changes
211             postProcess->OnChanged()->AddHandler(META_NS::MakeCallback<META_NS::IOnChanged>([this, engineCallback]() {
212                 if (auto meta = this->GetSelf<META_NS::IMetadata>()) {
213                     if (auto postProcess = meta->GetPropertyByName(CAMERA_POSTPROCESS)) {
214                         engineCallback(postProcess);
215                     }
216                 }
217             }),
218                 reinterpret_cast<uint64_t>(this));
219             ConvertBindChanges<SCENE_NS::IPostProcess::Ptr, CORE_NS::Entity, EntityConverter<SCENE_NS::IPostProcess>>(
220                 propHandler_, PostProcess(), meta, "CameraComponent.postProcess", ONE_WAY_TO_ECS);
221         }
222 
223         auto updateCustom = [this]() {
224             auto pipeline = RenderingPipeline()->GetValue();
225             if (pipeline == SCENE_NS::ICamera::SceneCameraPipeline::SCENE_CAM_PIPELINE_FORWARD) {
226                 auto ecs0 = interface_cast<SCENE_NS::IEcsObject>(GetSelf());
227                 auto ecs = ecs0->GetEcs();
228                 auto ent = ecs0->GetEntity();
229                 if (auto cameraManager = CORE_NS::GetManager<CORE3D_NS::ICameraComponentManager>(*ecs)) {
230                     if (cameraManager->HasComponent(ent)) {
231                         auto data = cameraManager->Get(ent);
232                         data.colorTargetCustomization.clear();
233                         data.colorTargetCustomization.push_back({ BASE_NS::BASE_FORMAT_R16G16B16A16_SFLOAT, {} });
234                         cameraManager->Set(ent, data);
235                     }
236                 }
237             };
238         };
239         updateCustom();
240         RenderingPipeline()->OnChanged()->AddHandler(
241             META_NS::MakeCallback<META_NS::IOnChanged>(updateCustom), reinterpret_cast<uint64_t>(this));
242         return true;
243     }
244 
Destroy()245     void Destroy() override {}
246 
247     BASE_NS::vector<SCENE_NS::ICamera::Ptr> multiviewCameras_;
248 
249     // ToDo: Should someday listen to flags (or even entity changes from engine in case multiview is set up there)
AddMultiviewCamera(ICamera::Ptr camera)250     void AddMultiviewCamera(ICamera::Ptr camera) override
251     {
252         if (camera) {
253             // add render bit
254             auto flags = META_NS::GetValue(camera->PipelineFlags()) | CORE3D_NS::CameraComponent::MULTI_VIEW_ONLY_BIT;
255             camera->PipelineFlags()->SetValue(flags);
256             // store to array and ecs
257             if (auto sh = SceneHolder()) {
258                 sh->QueueEngineTask(MakeTask(
259                                         [source = interface_cast<SCENE_NS::IEcsObject>(camera)->GetEntity(),
260                                             target = GetSelf<SCENE_NS::IEcsObject>()->GetEntity()](auto sh) {
261                                             sh->SetMultiviewCamera(target, source);
262                                             return false;
263                                         },
264                                         sh),
265                     false);
266             }
267             // hold strong ref (allow adding multiple times)
268             multiviewCameras_.push_back(camera);
269         }
270     }
271 
RemoveMultiviewCamera(const ICamera::Ptr & camera)272     void RemoveMultiviewCamera(const ICamera::Ptr& camera) override
273     {
274         if (!camera) {
275             return;
276         }
277         size_t count = 0;
278         // release refs
279         for (size_t ii = 0; ii < multiviewCameras_.size();) {
280             if (multiviewCameras_[ii] == camera) // assuming shared ptr compares the object it points
281             {
282                 if (++count == 1) {
283                     multiviewCameras_.erase(multiviewCameras_.cbegin() + ii);
284                 } else {
285                     break;
286                 }
287             } else {
288                 ii++;
289             }
290         }
291 
292         if (count == 1) {
293             // remove render-bit
294             auto flags = META_NS::GetValue(camera->PipelineFlags()) & ~CORE3D_NS::CameraComponent::MULTI_VIEW_ONLY_BIT;
295             camera->PipelineFlags()->SetValue(flags);
296 
297             // tell ecs
298             if (auto sh = SceneHolder()) {
299                 sh->QueueEngineTask(MakeTask(
300                                         [source = interface_cast<SCENE_NS::IEcsObject>(camera)->GetEntity(),
301                                             target = GetSelf<SCENE_NS::IEcsObject>()->GetEntity()](auto sh) {
302                                             sh->RemoveMultiviewCamera(target, source);
303                                             return false;
304                                         },
305                                         sh),
306                     false);
307             }
308         }
309     }
ScreenToWorld(BASE_NS::Math::Vec3 screenCoordinate) const310     SCENE_NS::IPickingResult::Ptr ScreenToWorld(BASE_NS::Math::Vec3 screenCoordinate) const override
311     {
312         auto ret = objectRegistry_->Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request);
313         if (ret && SceneHolder()) {
314             SceneHolder()->QueueEngineTask(
315                 META_NS::MakeCallback<META_NS::ITaskQueueTask>(
316                     [screenCoordinate, weakRet = BASE_NS::weak_ptr(ret), weakSh = sceneHolder_,
317                         weakSelf = BASE_NS::weak_ptr(ecsObject_)]() {
318                         if (auto sh = weakSh.lock()) {
319                             if (auto ret = weakRet.lock()) {
320                                 if (auto self = weakSelf.lock()) {
321                                     if (sh->ScreenToWorld(ret, self->GetEntity(), screenCoordinate)) {
322                                         sh->QueueApplicationTask(
323                                             META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() {
324                                                 if (auto writable = interface_pointer_cast<
325                                                         SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(weakRet)) {
326                                                     writable->MarkReady();
327                                                 }
328                                                 return false;
329                                             }),
330                                             false);
331                                     }
332                                 }
333                             }
334                         }
335                         return false;
336                     }),
337                 false);
338             return ret;
339         }
340         return SCENE_NS::IPickingResult::Ptr();
341     }
342 
WorldToScreen(BASE_NS::Math::Vec3 worldCoordinate) const343     SCENE_NS::IPickingResult::Ptr WorldToScreen(BASE_NS::Math::Vec3 worldCoordinate) const override
344     {
345         auto ret = objectRegistry_->Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request);
346         if (ret && SceneHolder()) {
347             SceneHolder()->QueueEngineTask(
348                 META_NS::MakeCallback<META_NS::ITaskQueueTask>(
349                     [worldCoordinate, weakRet = BASE_NS::weak_ptr(ret), weakSh = sceneHolder_,
350                         weakSelf = BASE_NS::weak_ptr(ecsObject_)]() {
351                         if (auto sh = weakSh.lock()) {
352                             if (auto ret = weakRet.lock()) {
353                                 if (auto self = weakSelf.lock()) {
354                                     if (sh->WorldToScreen(ret, self->GetEntity(), worldCoordinate)) {
355                                         sh->QueueApplicationTask(
356                                             META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet]() {
357                                                 if (auto writable = interface_pointer_cast<
358                                                         SCENE_NS::IPendingRequestData<BASE_NS::Math::Vec3>>(weakRet)) {
359                                                     writable->MarkReady();
360                                                 }
361                                                 return false;
362                                             }),
363                                             false);
364                                     }
365                                 }
366                             }
367                         }
368                         return false;
369                     }),
370                 false);
371             return ret;
372         }
373         return SCENE_NS::IPickingResult::Ptr();
374     }
375 
RayCastFromCamera(const BASE_NS::Math::Vec2 & screenPos) const376     SCENE_NS::IRayCastResult::Ptr RayCastFromCamera(const BASE_NS::Math::Vec2& screenPos) const override
377     {
378         auto ret =
379             META_NS::GetObjectRegistry().Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest);
380         if (ret && SceneHolder()) {
381             SceneHolder()->QueueEngineTask(
382                 META_NS::MakeCallback<META_NS::ITaskQueueTask>(
383                     [pos = screenPos, weakRet = BASE_NS::weak_ptr(ret), weakSh = sceneHolder_,
384                         weakSelf = BASE_NS::weak_ptr(ecsObject_), weakScene = BASE_NS::weak_ptr(GetScene())]() {
385                         if (auto sh = weakSh.lock()) {
386                             if (auto ret = weakRet.lock()) {
387                                 if (auto self = weakSelf.lock()) {
388                                     if (sh->RayCastFromCamera(ret, self->GetEntity(), pos)) {
389                                         sh->QueueApplicationTask(
390                                             META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, weakScene]() {
391                                                 if (auto writable = interface_pointer_cast<
392                                                         SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>(
393                                                         weakRet)) {
394                                                     if (auto scene = weakScene.lock()) {
395                                                         // resolve proxy nodes
396                                                         for (size_t ii = writable->MetaData().size(); ii > 0;) {
397                                                             --ii;
398                                                             writable->MutableData().at(ii).node =
399                                                                 scene->GetNode(writable->MetaData().at(ii));
400                                                         }
401                                                         writable->MarkReady();
402                                                     }
403                                                 }
404                                                 return false;
405                                             }),
406                                             false);
407                                     }
408                                 }
409                             }
410                         }
411                         return false;
412                     }),
413                 false);
414             return ret;
415         }
416         return SCENE_NS::IRayCastResult::Ptr();
417     }
418 
RayCastFromCamera(const BASE_NS::Math::Vec2 & screenPos,uint64_t layerMask) const419     SCENE_NS::IRayCastResult::Ptr RayCastFromCamera(
420         const BASE_NS::Math::Vec2& screenPos, uint64_t layerMask) const override
421     {
422         auto ret = objectRegistry_->Create<SCENE_NS::IRayCastResult>(SCENE_NS::ClassId::PendingDistanceRequest);
423         if (ret && SceneHolder()) {
424             SceneHolder()->QueueEngineTask(
425                 META_NS::MakeCallback<META_NS::ITaskQueueTask>(
426                     [pos = screenPos, weakRet = BASE_NS::weak_ptr(ret), weakSh = sceneHolder_, layerMask,
427                         weakSelf = BASE_NS::weak_ptr(ecsObject_), weakScene = BASE_NS::weak_ptr(GetScene())]() {
428                         if (auto sh = weakSh.lock()) {
429                             if (auto ret = weakRet.lock()) {
430                                 if (auto self = weakSelf.lock()) {
431                                     if (sh->RayCastFromCamera(ret, self->GetEntity(), pos, layerMask)) {
432                                         sh->QueueApplicationTask(
433                                             META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, weakScene]() {
434                                                 if (auto writable = interface_pointer_cast<
435                                                         SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>(
436                                                         weakRet)) {
437                                                     if (auto scene = weakScene.lock()) {
438                                                         // resolve proxy nodes
439                                                         for (size_t ii = writable->MetaData().size(); ii > 0;) {
440                                                             --ii;
441                                                             writable->MutableData().at(ii).node =
442                                                                 scene->GetNode(writable->MetaData().at(ii));
443                                                         }
444                                                         writable->MarkReady();
445                                                     }
446                                                 }
447                                                 return false;
448                                             }),
449                                             false);
450                                     }
451                                 }
452                             }
453                         }
454                         return false;
455                     }),
456                 false);
457             return ret;
458         }
459         return SCENE_NS::IRayCastResult::Ptr();
460     }
461 
RayFromCamera(const BASE_NS::Math::Vec2 & screenPos) const462     SCENE_NS::IPickingResult::Ptr RayFromCamera(const BASE_NS::Math::Vec2& screenPos) const override
463     {
464         auto ret = objectRegistry_->Create<SCENE_NS::IPickingResult>(SCENE_NS::ClassId::PendingVec3Request);
465         if (ret && SceneHolder()) {
466             SceneHolder()->QueueEngineTask(
467                 META_NS::MakeCallback<META_NS::ITaskQueueTask>(
468                     [pos = screenPos, weakRet = BASE_NS::weak_ptr(ret), weakSh = sceneHolder_,
469                         weakSelf = BASE_NS::weak_ptr(ecsObject_), weakScene = BASE_NS::weak_ptr(GetScene())]() {
470                         if (auto sh = weakSh.lock()) {
471                             if (auto ret = weakRet.lock()) {
472                                 if (auto self = weakSelf.lock()) {
473                                     if (sh->RayFromCamera(ret, self->GetEntity(), pos)) {
474                                         sh->QueueApplicationTask(
475                                             META_NS::MakeCallback<META_NS::ITaskQueueTask>([weakRet, weakScene]() {
476                                                 if (auto writable = interface_pointer_cast<
477                                                         SCENE_NS::IPendingRequestData<SCENE_NS::NodeDistance>>(
478                                                         weakRet)) {
479                                                     if (auto scene = weakScene.lock()) {
480                                                         // resolve proxy nodes
481                                                         for (size_t ii = writable->MetaData().size(); ii > 0;) {
482                                                             --ii;
483                                                             writable->MutableData().at(ii).node =
484                                                                 scene->GetNode(writable->MetaData().at(ii));
485                                                         }
486                                                         writable->MarkReady();
487                                                     }
488                                                 }
489                                                 return false;
490                                             }),
491                                             false);
492                                     }
493                                 }
494                             }
495                         }
496                         return false;
497                     }),
498                 false);
499             return ret;
500         }
501         return SCENE_NS::IPickingResult::Ptr();
502     }
503 
SetDefaultRenderTargetSize(uint64_t width,uint64_t height)504     void SetDefaultRenderTargetSize(uint64_t width, uint64_t height) override
505     {
506         RenderTargetSize()->SetDefaultValue(BASE_NS::Math::UVec2(width, height));
507     }
508 };
509 
510 } // namespace
511 
SCENE_BEGIN_NAMESPACE()512 SCENE_BEGIN_NAMESPACE()
513 
514 void RegisterCameraImpl()
515 {
516     auto& registry = META_NS::GetObjectRegistry();
517     registry.RegisterObjectType<CameraImpl>();
518 }
519 
UnregisterCameraImpl()520 void UnregisterCameraImpl()
521 {
522     auto& registry = META_NS::GetObjectRegistry();
523     registry.UnregisterObjectType<CameraImpl>();
524 }
525 
526 SCENE_END_NAMESPACE()
527