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
25using SCENE_NS::MakeTask;
26
27namespace {
28class 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
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
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
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)
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
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    }
310    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
343    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
376    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
419    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
462    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
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
512SCENE_BEGIN_NAMESPACE()
513
514void RegisterCameraImpl()
515{
516    auto& registry = META_NS::GetObjectRegistry();
517    registry.RegisterObjectType<CameraImpl>();
518}
519
520void UnregisterCameraImpl()
521{
522    auto& registry = META_NS::GetObjectRegistry();
523    registry.UnregisterObjectType<CameraImpl>();
524}
525
526SCENE_END_NAMESPACE()
527