• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 #include "ShaderJS.h"
17 
18 #include <meta/api/util.h>
19 #include <scene/ext/intf_internal_scene.h>
20 #include <scene/interface/intf_mesh.h>
21 #include <scene/interface/intf_scene.h>
22 
23 #include "SceneJS.h"
24 #include "Vec2Proxy.h"
25 #include "Vec3Proxy.h"
26 #include "Vec4Proxy.h"
27 
28 using IntfPtr = META_NS::SharedPtrIInterface;
29 using IntfWeakPtr = META_NS::WeakPtrIInterface;
30 
Init(napi_env env,napi_value exports)31 void ShaderJS::Init(napi_env env, napi_value exports)
32 {
33     using namespace NapiApi;
34     BASE_NS::vector<napi_property_descriptor> node_props;
35 
36     SceneResourceImpl::GetPropertyDescs(node_props);
37 
38     napi_value func;
39     auto status = napi_define_class(env, "Shader", NAPI_AUTO_LENGTH, BaseObject::ctor<ShaderJS>(), nullptr,
40         node_props.size(), node_props.data(), &func);
41 
42     NapiApi::MyInstanceState* mis;
43     GetInstanceData(env, reinterpret_cast<void**>(&mis));
44     mis->StoreCtor("Shader", func);
45 }
46 
ShaderJS(napi_env e,napi_callback_info i)47 ShaderJS::ShaderJS(napi_env e, napi_callback_info i)
48     : BaseObject<ShaderJS>(e, i), SceneResourceImpl(SceneResourceImpl::SHADER)
49 {
50     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
51     NapiApi::Object meJs(fromJs.This());
52 
53     NapiApi::Object scene = fromJs.Arg<0>(); // access to owning scene...
54     NapiApi::Object args = fromJs.Arg<1>();  // other args
55     scene_ = { scene };
56     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
57         LOG_F("INVALID SCENE!");
58     }
59 
60     auto* tro = scene.Native<TrueRootObject>();
61     if (tro) {
62         auto* sceneJS = ((SceneJS*)tro->GetInstanceImpl(SceneJS::ID));
63         if (sceneJS) {
64             sceneJS->DisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
65         }
66     }
67 
68     // check if we got the NativeObject as parameter. (meta object created when bound to material..)
69     auto metaobj = GetNativeObjectParam<META_NS::IMetadata>(args);
70 
71     StoreJsObj(interface_pointer_cast<META_NS::IObject>(metaobj), meJs);
72 
73     // check if it's a SCENE_NS::IShader (can only be set on instances created createShader, these are the "template"
74     // shaders.)
75     auto shader = interface_pointer_cast<SCENE_NS::IShader>(metaobj);
76     if (shader) {
77         // we should not be bound to a material then.. this is a place holder object.
78         SetNativeObject(interface_pointer_cast<META_NS::IObject>(shader), true);
79     } else {
80         // should be bound to a material..
81         // so the shader should be stored as a parameter..
82         SetNativeObject(interface_pointer_cast<META_NS::IObject>(metaobj), true);
83         shader = interface_pointer_cast<SCENE_NS::IShader>(metaobj->GetProperty<IntfPtr>("shader")->GetValue());
84     }
85 
86     NapiApi::Object material = args.Get<NapiApi::Object>("Material"); // see if we SHOULD be bound to a material.
87     if (material) {
88         BindToMaterial(meJs, material);
89     }
90 
91     BASE_NS::string name;
92     if (auto prm = args.Get<BASE_NS::string>("name"); prm.IsDefined()) {
93         name = prm;
94     } else {
95         if (auto named = interface_cast<META_NS::IObject>(metaobj)) {
96             name = named->GetName();
97         }
98     }
99     meJs.Set("name", name);
100 }
101 
BindToMaterial(NapiApi::Object meJs,NapiApi::Object material)102 void ShaderJS::BindToMaterial(NapiApi::Object meJs, NapiApi::Object material)
103 {
104     // unbind existing inputs.
105     UnbindInputs();
106 
107     // inputs are actually owned (and used) by the material.
108     // create the input object
109     NapiApi::Object inputs(meJs.GetEnv());
110 
111     napi_env e = inputs.GetEnv();
112     auto* tro = material.Native<TrueRootObject>();
113     if (!tro) {
114         LOG_F("tro is null");
115         return;
116     }
117     auto mat = interface_pointer_cast<SCENE_NS::IMaterial>(tro->GetNativeObject());
118     if (!mat) {
119         LOG_F("mat is null");
120         return;
121     }
122 
123     BASE_NS::vector<napi_property_descriptor> inputProps;
124 
125     META_NS::IMetadata::Ptr customProperties;
126     BASE_NS::vector<SCENE_NS::ITexture::Ptr> Textures = mat->Textures()->GetValue();
127     customProperties = mat->GetCustomProperties();
128 
129     if (!Textures.empty()) {
130         int index = 0;
131         for (auto t : Textures) {
132             BASE_NS::string name;
133             auto nn = interface_cast<META_NS::IObject>(t);
134             if (nn) {
135                 name = nn->GetName();
136             } else {
137                 name = "TextureInfo_" + BASE_NS::to_string(index);
138             }
139             BASE_NS::shared_ptr<PropertyProxy> proxt;
140             // factor
141             if (proxt = BASE_NS::shared_ptr { new Vec4Proxy(e, t->Factor()) }) {
142                 auto n = (name.empty() ? BASE_NS::string_view("") : name + BASE_NS::string_view("_")) +
143                          t->Factor()->GetName();
144 
145                 const auto& res = proxies_.insert_or_assign(n, proxt);
146                 inputProps.push_back(CreateProxyDesc(res.first->first.c_str(), BASE_NS::move(proxt)));
147             }
148 
149             if (proxt = BASE_NS::shared_ptr { new BitmapProxy(scene_.GetObject(), inputs, t->Image()) }) {
150                 auto n = (name.empty() ? BASE_NS::string_view("") : name + BASE_NS::string_view("_")) +
151                          t->Image()->GetName();
152                 const auto& res = proxies_.insert_or_assign(n, proxt);
153                 inputProps.push_back(CreateProxyDesc(res.first->first.c_str(), BASE_NS::move(proxt)));
154             }
155             index++;
156         }
157     }
158     // default stuff
159     {
160         auto proxt = BASE_NS::shared_ptr { new TypeProxy<float>(inputs, mat->AlphaCutoff()) };
161         if (proxt) {
162             auto res = proxies_.insert_or_assign(mat->AlphaCutoff()->GetName(), proxt);
163             inputProps.push_back(CreateProxyDesc(res.first->first.c_str(), BASE_NS::move(proxt)));
164         }
165     }
166     if (customProperties) {
167         BASE_NS::shared_ptr<CORE_NS::IInterface> intsc;
168         if (auto scene = GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
169             if (auto ints = scene->GetInternalScene()) {
170                 intsc = interface_pointer_cast<CORE_NS::IInterface>(ints);
171             }
172         }
173         if (intsc) {
174             for (auto t : customProperties->GetProperties()) {
175                 BASE_NS::shared_ptr<PropertyProxy> proxt = PropertyToProxy(scene_.GetObject(), inputs, t);
176                 if (proxt) {
177                     proxt->SetExtra(intsc);
178                     auto res = proxies_.insert_or_assign(t->GetName(), proxt);
179                     inputProps.push_back(CreateProxyDesc(res.first->first.c_str(), BASE_NS::move(proxt)));
180                 }
181             }
182         }
183     }
184     if (!inputProps.empty()) {
185         napi_define_properties(e, inputs.ToNapiValue(), inputProps.size(), inputProps.data());
186     }
187 
188     inputs_ = NapiApi::StrongRef(inputs);
189     meJs.Set("inputs", inputs_.GetValue());
190 }
191 
~ShaderJS()192 ShaderJS::~ShaderJS()
193 {
194     DisposeNative(nullptr);
195 }
196 
GetInstanceImpl(uint32_t id)197 void* ShaderJS::GetInstanceImpl(uint32_t id)
198 {
199     if (id == ShaderJS::ID)
200         return this;
201     return SceneResourceImpl::GetInstanceImpl(id);
202 }
UnbindInputs()203 void ShaderJS::UnbindInputs()
204 {
205     /// destroy the input object.
206     if (!inputs_.IsEmpty()) {
207         NapiApi::Object inp = inputs_.GetObject();
208         while (!proxies_.empty()) {
209             auto it = proxies_.begin();
210             // removes hooks for meta property & jsproperty.
211             inp.DeleteProperty(it->first);
212             // destroy the proxy.
213             proxies_.erase(it);
214         }
215     }
216     inputs_.Reset();
217 }
DisposeNative(void * in)218 void ShaderJS::DisposeNative(void* in)
219 {
220     if (!disposed_) {
221         disposed_ = true;
222 
223         UnbindInputs();
224 
225         // release native object.
226         SetNativeObject(nullptr, false);
227         SetNativeObject(nullptr, true);
228         NapiApi::Object obj = scene_.GetObject();
229         if (obj) {
230             auto* tro = obj.Native<TrueRootObject>();
231             if (tro) {
232                 SceneJS* sceneJS = static_cast<SceneJS*>(tro->GetInstanceImpl(SceneJS::ID));
233                 if (sceneJS) {
234                     sceneJS->ReleaseDispose(reinterpret_cast<uintptr_t>(&scene_));
235                 }
236             }
237         }
238 
239         scene_.Reset();
240     }
241 }
Finalize(napi_env env)242 void ShaderJS::Finalize(napi_env env)
243 {
244     DisposeNative(nullptr);
245     BaseObject<ShaderJS>::Finalize(env);
246 }
247