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/material_uid.h>
16
17#include <meta/ext/concrete_base_object.h>
18
19#include "bind_templates.inl"
20#include "node_impl.h"
21
22namespace {
23class GraphicsStateImpl : public META_NS::ObjectFwd<GraphicsStateImpl, SCENE_NS::ClassId::GraphicsState,
24                              META_NS::ClassId::Object, SCENE_NS::IGraphicsState, ISceneHolderRef> {
25    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IGraphicsState, BASE_NS::string, Uri, "")
26    META_IMPLEMENT_INTERFACE_PROPERTY(SCENE_NS::IGraphicsState, BASE_NS::string, Variant, "")
27
28    bool Build(const IMetadata::Ptr& data) override
29    {
30        return true;
31    }
32
33    RENDER_NS::RenderHandleReference GetRenderHandleReference(RENDER_NS::IShaderManager& shaderManager) override
34    {
35        if (RENDER_NS::RenderHandleUtil::IsValid(renderHandleReference_.GetHandle())) {
36            return renderHandleReference_;
37        }
38
39        auto uri = GetValue(META_ACCESS_PROPERTY(Uri));
40        auto variant = GetValue(META_ACCESS_PROPERTY(Variant));
41
42        renderHandleReference_ = shaderManager.GetGraphicsStateHandle(uri, variant);
43        if (!renderHandleReference_) {
44            // presumably we should resolve the state from shader instead trying to create a default our self
45            // the problem is, we don't actually know to which shader we are attached to
46            // basically the shader should have set its default during the material component set-up, though
47            shaderManager.CreateGraphicsState({ uri, {} }, { variant, {} });
48            renderHandleReference_ = shaderManager.GetGraphicsStateHandle(uri, variant);
49        }
50
51        return renderHandleReference_;
52    }
53
54    void SetGraphicsState(const RENDER_NS::GraphicsState& state, SCENE_NS::IMaterial::Ptr mat) override
55    {
56        if (auto sh = SceneHolder()) {
57            sh->QueueApplicationTask(META_NS::MakeCallback<META_NS::ITaskQueueTask>(
58                                         [st = state, sh = sh_, material = BASE_NS::weak_ptr(mat), type = ix_]() {
59                                             if (auto sceneHolder = sh.lock()) {
60                                                 if (auto mat = interface_cast<SCENE_NS::IEcsObject>(material.lock())) {
61                                                     sceneHolder->SetGraphicsState(
62                                                         mat->GetEntity(), (SceneHolder::ShaderType)type, st);
63                                                 }
64                                             }
65                                             return false;
66                                         }),
67                false);
68        }
69    }
70
71    SCENE_NS::IShaderGraphicsState::Ptr GetGraphicsState(SCENE_NS::IMaterial::Ptr mat) override
72    {
73        auto ret =
74            META_NS::GetObjectRegistry().Create<SCENE_NS::IShaderGraphicsState>(SCENE_NS::ClassId::GraphicsState);
75        if (auto sh = SceneHolder()) {
76            sh->QueueApplicationTask(
77                META_NS::MakeCallback<META_NS::ITaskQueueTask>([sh = sh_, material = BASE_NS::weak_ptr(mat), type = ix_,
78                                                               ret_w = BASE_NS::weak_ptr(ret)]() {
79                    if (auto sceneHolder = sh.lock()) {
80                        if (auto mat = interface_cast<SCENE_NS::IEcsObject>(material.lock())) {
81                            if (auto ret = ret_w.lock()) {
82                                sceneHolder->GetGraphicsState(mat->GetEntity(), (SceneHolder::ShaderType)type, ret);
83                                if (auto typedRet =
84                                        interface_cast<SCENE_NS::IPendingRequestData<RENDER_NS::GraphicsState>>(ret)) {
85                                    typedRet->MarkReady();
86                                }
87                            }
88                        }
89                    }
90                    return false;
91                }),
92                false);
93        }
94
95        return ret;
96    }
97
98    void SetSceneHolder(const SceneHolder::WeakPtr& sh) override
99    {
100        sh_ = sh;
101    }
102
103    SceneHolder::Ptr SceneHolder() override
104    {
105        return sh_.lock();
106    }
107
108    void SetIndex(size_t ix) override
109    {
110        ix_ = ix;
111    }
112
113private:
114    RENDER_NS::RenderHandleReference renderHandleReference_;
115    SceneHolder::WeakPtr sh_;
116    size_t ix_ { 0 };
117};
118} // namespace
119
120SCENE_BEGIN_NAMESPACE()
121void RegisterGraphicsStateImpl()
122{
123    META_NS::GetObjectRegistry().RegisterObjectType<GraphicsStateImpl>();
124}
125void UnregisterGraphicsStateImpl()
126{
127    META_NS::GetObjectRegistry().UnregisterObjectType<GraphicsStateImpl>();
128}
129SCENE_END_NAMESPACE()