• 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 <meta/api/make_callback.h>
17 #include <meta/interface/intf_task_queue.h>
18 #include <meta/interface/intf_task_queue_registry.h>
19 #include <scene/interface/intf_material.h>
20 
21 #include "MaterialJS.h"
22 #include "MaterialPropertyJS.h"
23 #include "SamplerJS.h"
24 
25 #include <optional>
26 
27 using IntfPtr = BASE_NS::shared_ptr<CORE_NS::IInterface>;
28 using IntfWeakPtr = BASE_NS::weak_ptr<CORE_NS::IInterface>;
29 using namespace SCENE_NS;
30 
Init(napi_env env,napi_value exports)31 void MaterialPropertyJS::Init(napi_env env, napi_value exports)
32 {
33     using namespace NapiApi;
34 
35     BASE_NS::vector<napi_property_descriptor> node_props;
36     node_props.push_back(
37         GetSetProperty<Object, MaterialPropertyJS, &MaterialPropertyJS::GetImage, &MaterialPropertyJS::SetImage>(
38             "image"));
39     node_props.push_back(
40         GetSetProperty<Object, MaterialPropertyJS, &MaterialPropertyJS::GetFactor, &MaterialPropertyJS::SetFactor>(
41             "factor"));
42     node_props.push_back(
43         GetSetProperty<Object, MaterialPropertyJS, &MaterialPropertyJS::GetSampler, &MaterialPropertyJS::SetSampler>(
44             "sampler"));
45     node_props.push_back(
46         MakeTROMethod<FunctionContext<>, MaterialPropertyJS, &MaterialPropertyJS::Dispose>("destroy"));
47 
48     napi_value func;
49     auto status = napi_define_class(env, "MaterialProperty", NAPI_AUTO_LENGTH, BaseObject::ctor<MaterialPropertyJS>(),
50         nullptr, node_props.size(), node_props.data(), &func);
51 
52     MyInstanceState* mis;
53     NapiApi::MyInstanceState::GetInstance(env, (void**)&mis);
54     if (mis) {
55         mis->StoreCtor("MaterialProperty", func);
56     }
57 }
MaterialPropertyJS(napi_env e,napi_callback_info i)58 MaterialPropertyJS::MaterialPropertyJS(napi_env e, napi_callback_info i) : BaseObject(e, i) {}
~MaterialPropertyJS()59 MaterialPropertyJS::~MaterialPropertyJS()
60 {
61     DisposeNative(nullptr);
62     if (!GetNativeObject()) {
63         return;
64     }
65 }
GetInstanceImpl(uint32_t id)66 void* MaterialPropertyJS::GetInstanceImpl(uint32_t id)
67 {
68     if (id == MaterialPropertyJS::ID)
69         return this;
70     return nullptr;
71 }
Dispose(NapiApi::FunctionContext<> & ctx)72 napi_value MaterialPropertyJS::Dispose(NapiApi::FunctionContext<>& ctx)
73 {
74     DisposeNative(nullptr);
75     return {};
76 }
Finalize(napi_env env)77 void MaterialPropertyJS::Finalize(napi_env env)
78 {
79     DisposeNative(nullptr);
80     BaseObject::Finalize(env);
81 }
DisposeNative(void *)82 void MaterialPropertyJS::DisposeNative(void*)
83 {
84     if (!disposed_) {
85         disposed_ = true;
86         sampler_.Reset();
87         factorProxy_.reset();
88         UnsetNativeObject();
89     }
90 }
GetImage(NapiApi::FunctionContext<> & ctx)91 napi_value MaterialPropertyJS::GetImage(NapiApi::FunctionContext<>& ctx)
92 {
93     auto texture = ctx.This().GetNative<SCENE_NS::ITexture>();
94     if (!texture) {
95         return ctx.GetUndefined();
96     }
97 
98     SCENE_NS::IBitmap::Ptr image = META_NS::GetValue(texture->Image());
99     napi_value args[] = { ctx.This().ToNapiValue() };
100     return CreateFromNativeInstance(ctx.GetEnv(), image, PtrType::STRONG, args).ToNapiValue();
101 }
SetImage(NapiApi::FunctionContext<NapiApi::Object> & ctx)102 void MaterialPropertyJS::SetImage(NapiApi::FunctionContext<NapiApi::Object>& ctx)
103 {
104     auto texture = ctx.This().GetNative<SCENE_NS::ITexture>();
105     if (!texture) {
106         return;
107     }
108 
109     NapiApi::Object imageJS = ctx.Arg<0>();
110     if (auto nat = imageJS.GetRoot()) {
111         SCENE_NS::IBitmap::Ptr image = interface_pointer_cast<SCENE_NS::IBitmap>(nat->GetNativeObject());
112         META_NS::SetValue(texture->Image(), image);
113     }
114 }
GetFactor(NapiApi::FunctionContext<> & ctx)115 napi_value MaterialPropertyJS::GetFactor(NapiApi::FunctionContext<> &ctx)
116 {
117     if (auto texture = ctx.This().GetNative<SCENE_NS::ITexture>()) {
118         if (!factorProxy_) {
119             factorProxy_ = BASE_NS::make_unique<Vec4Proxy>(ctx.Env(), texture->Factor());
120         }
121         return factorProxy_->Value();
122     }
123     return ctx.GetUndefined();
124 }
SetFactor(NapiApi::FunctionContext<NapiApi::Object> & ctx)125 void MaterialPropertyJS::SetFactor(NapiApi::FunctionContext<NapiApi::Object>& ctx)
126 {
127     auto texture = ctx.This().GetNative<SCENE_NS::ITexture>();
128     if (!texture) {
129         return;
130     }
131 
132     if (NapiApi::Object factorJS = ctx.Arg<0>()) {
133         auto x = factorJS.Get<float>("x");
134         auto y = factorJS.Get<float>("y");
135         auto z = factorJS.Get<float>("z");
136         auto w = factorJS.Get<float>("w");
137         META_NS::SetValue(texture->Factor(), { x, y, z, w });
138     }
139 }
GetSampler(NapiApi::FunctionContext<> & ctx)140 napi_value MaterialPropertyJS::GetSampler(NapiApi::FunctionContext<>& ctx)
141 {
142     if (auto existing = sampler_.GetObject()) {
143         return existing.ToNapiValue();
144     }
145 
146     if (auto texture = GetNativeObject<ITexture>()) {
147         if (auto sampler = META_NS::GetValue(texture->Sampler())) {
148             napi_value args[] = { ctx.This().ToNapiValue() };
149             auto object = CreateFromNativeInstance(ctx.GetEnv(), sampler, PtrType::STRONG, args);
150             sampler_ = NapiApi::StrongRef(object);
151             return object.ToNapiValue();
152         }
153     }
154     return ctx.GetUndefined();
155 }
156 
SetSampler(NapiApi::FunctionContext<NapiApi::Object> & ctx)157 void MaterialPropertyJS::SetSampler(NapiApi::FunctionContext<NapiApi::Object>& ctx)
158 {
159     auto texture = ctx.This().GetNative<SCENE_NS::ITexture>();
160     if (!texture) {
161         return;
162     }
163 
164     auto target = META_NS::GetValue(texture->Sampler());
165     NapiApi::Object source = ctx.Arg<0>();
166 
167     struct SamplerChangeSet {
168         std::optional<SCENE_NS::SamplerFilter> minFilter;
169         std::optional<SCENE_NS::SamplerFilter> magFilter;
170         std::optional<SCENE_NS::SamplerFilter> mipMapMode;
171         std::optional<SCENE_NS::SamplerAddressMode> addressModeU;
172         std::optional<SCENE_NS::SamplerAddressMode> addressModeV;
173         std::optional<SCENE_NS::SamplerAddressMode> addressModeW;
174 
175         bool HasChanges() const
176         {
177             return minFilter.has_value() || magFilter.has_value() || mipMapMode.has_value() ||
178                    addressModeU.has_value() || addressModeV.has_value() || addressModeW.has_value();
179         }
180     };
181 
182     SamplerChangeSet changes;
183     bool defined = source && source.IsDefined() && !source.IsNull();
184     if (defined) {
185         if (source.Has("magFilter")) {
186             changes.magFilter = SamplerJS::ConvertToFilter(source.Get<uint32_t>("magFilter"));
187         }
188         if (source.Has("minFilter")) {
189             changes.minFilter = SamplerJS::ConvertToFilter(source.Get<uint32_t>("minFilter"));
190         }
191         if (source.Has("mipMapMode")) {
192             changes.mipMapMode = SamplerJS::ConvertToFilter(source.Get<uint32_t>("mipMapMode"));
193         }
194         if (source.Has("addressModeU")) {
195             changes.addressModeU = SamplerJS::ConvertToAddressMode(source.Get<uint32_t>("addressModeU"));
196         }
197         if (source.Has("addressModeV")) {
198             changes.addressModeV = SamplerJS::ConvertToAddressMode(source.Get<uint32_t>("addressModeV"));
199         }
200         if (source.Has("addressModeW")) {
201             changes.addressModeW = SamplerJS::ConvertToAddressMode(source.Get<uint32_t>("addressModeW"));
202         }
203     }
204 
205     ExecSyncTask([&]() {
206         // Apply given object as a changeset on top of default sampler
207         if (auto resetable = interface_cast<META_NS::IResetableObject>(target)) {
208             resetable->ResetObject(); // First, reset to default state
209         }
210         // Then apply those properties that have been set in our input object
211         if (changes.HasChanges()) {
212             if (changes.magFilter) {
213                 META_NS::SetValue(target->MagFilter(), changes.magFilter.value());
214             }
215             if (changes.minFilter) {
216                 META_NS::SetValue(target->MinFilter(), changes.minFilter.value());
217             }
218             if (changes.mipMapMode) {
219                 META_NS::SetValue(target->MipMapMode(), changes.mipMapMode.value());
220             }
221             if (changes.addressModeU) {
222                 META_NS::SetValue(target->AddressModeU(), changes.addressModeU.value());
223             }
224             if (changes.addressModeV) {
225                 META_NS::SetValue(target->AddressModeV(), changes.addressModeV.value());
226             }
227             if (changes.addressModeW) {
228                 META_NS::SetValue(target->AddressModeW(), changes.addressModeW.value());
229             }
230         }
231         return META_NS::IAny::Ptr {};
232     });
233 }