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 "SubMeshJS.h"
17 
18 #include <meta/api/make_callback.h>
19 #include <meta/interface/intf_task_queue.h>
20 #include <meta/interface/intf_task_queue_registry.h>
21 #include <scene_plugin/api/camera_uid.h>
22 #include <scene_plugin/interface/intf_camera.h>
23 #include <scene_plugin/interface/intf_scene.h>
24 
GetInstanceImpl(uint32_t id)25 void* SubMeshJS::GetInstanceImpl(uint32_t id)
26 {
27     if (id == SubMeshJS::ID) {
28         return this;
29     }
30     // not a node.
31     return nullptr;
32 }
DisposeNative()33 void SubMeshJS::DisposeNative()
34 {
35     // do nothing for now..
36     LOG_F("SubMeshJS::DisposeNative");
37     aabbMin_.reset();
38     aabbMax_.reset();
39     scene_.Reset();
40 }
Init(napi_env env,napi_value exports)41 void SubMeshJS::Init(napi_env env, napi_value exports)
42 {
43     BASE_NS::vector<napi_property_descriptor> node_props;
44 
45     using namespace NapiApi;
46     node_props.push_back(GetSetProperty<BASE_NS::string, SubMeshJS, &SubMeshJS::GetName, &SubMeshJS::SetName>("name"));
47     node_props.push_back(GetProperty<Object, SubMeshJS, &SubMeshJS::GetAABB>("aabb"));
48     node_props.push_back(
49         GetSetProperty<Object, SubMeshJS, &SubMeshJS::GetMaterial, &SubMeshJS::SetMaterial>("material"));
50 
51     napi_value func;
52     auto status = napi_define_class(env, "SubMesh", NAPI_AUTO_LENGTH, BaseObject::ctor<SubMeshJS>(), nullptr,
53         node_props.size(), node_props.data(), &func);
54 
55     NapiApi::MyInstanceState* mis;
56     napi_get_instance_data(env, (void**)&mis);
57     mis->StoreCtor("SubMesh", func);
58 }
59 
SubMeshJS(napi_env e,napi_callback_info i)60 SubMeshJS::SubMeshJS(napi_env e, napi_callback_info i) : BaseObject<SubMeshJS>(e, i)
61 {
62     LOG_F("SubMeshJS ++ ");
63     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
64     if (!fromJs) {
65         // okay internal create. we will receive the object after.
66         return;
67     }
68     NapiApi::Object scene = fromJs.Arg<0>();
69     scene_ = scene;
70     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
71         CORE_LOG_F("INVALID SCENE!");
72     }
73 }
~SubMeshJS()74 SubMeshJS::~SubMeshJS()
75 {
76     LOG_F("SubMeshJS -- ");
77 }
78 
GetAABB(NapiApi::FunctionContext<> & ctx)79 napi_value SubMeshJS::GetAABB(NapiApi::FunctionContext<>& ctx)
80 {
81     napi_value undef;
82     napi_get_undefined(ctx, &undef);
83     auto node = interface_pointer_cast<SCENE_NS::ISubMesh>(GetThisNativeObject(ctx));
84     if (!node) {
85         // return undefined.. as no actual node.
86         return undef;
87     }
88     BASE_NS::Math::Vec3 aabmin;
89     BASE_NS::Math::Vec3 aabmax;
90     ExecSyncTask([node, &aabmin, &aabmax]() {
91         aabmin = node->AABBMin()->GetValue();
92         aabmax = node->AABBMax()->GetValue();
93         return META_NS::IAny::Ptr {};
94     });
95     NapiApi::Object res(ctx);
96 
97     NapiApi::Object min(ctx);
98     min.Set("x", NapiApi::Value<float> { ctx, aabmin.x });
99     min.Set("y", NapiApi::Value<float> { ctx, aabmin.y });
100     min.Set("z", NapiApi::Value<float> { ctx, aabmin.z });
101     res.Set("aabbMin", min);
102 
103     NapiApi::Object max(ctx);
104     max.Set("x", NapiApi::Value<float> { ctx, aabmax.x });
105     max.Set("y", NapiApi::Value<float> { ctx, aabmax.y });
106     max.Set("z", NapiApi::Value<float> { ctx, aabmax.z });
107     res.Set("aabbMax", max);
108     return res;
109 }
110 
GetName(NapiApi::FunctionContext<> & ctx)111 napi_value SubMeshJS::GetName(NapiApi::FunctionContext<>& ctx)
112 {
113     BASE_NS::string name;
114     if (auto node = interface_pointer_cast<SCENE_NS::ISubMesh>(GetThisNativeObject(ctx))) {
115         ExecSyncTask([node, &name]() {
116             name = node->Name()->GetValue();
117             return META_NS::IAny::Ptr {};
118         });
119     }
120     napi_value value;
121     napi_status status = napi_create_string_utf8(ctx, name.c_str(), name.length(), &value);
122     return value;
123 }
SetName(NapiApi::FunctionContext<BASE_NS::string> & ctx)124 void SubMeshJS::SetName(NapiApi::FunctionContext<BASE_NS::string>& ctx)
125 {
126     if (auto node = interface_pointer_cast<SCENE_NS::ISubMesh>(GetThisNativeObject(ctx))) {
127         BASE_NS::string name = ctx.Arg<0>();
128         ExecSyncTask([node, name]() {
129             node->Name()->SetValue(name);
130             return META_NS::IAny::Ptr {};
131         });
132     }
133 }
134 
GetMaterial(NapiApi::FunctionContext<> & ctx)135 napi_value SubMeshJS::GetMaterial(NapiApi::FunctionContext<>& ctx)
136 {
137     napi_value undef;
138     napi_get_undefined(ctx, &undef);
139     auto sm = interface_pointer_cast<SCENE_NS::ISubMesh>(GetThisNativeObject(ctx));
140     if (!sm) {
141         // return undefined..
142         return undef;
143     }
144     META_NS::IObject::Ptr obj;
145     ExecSyncTask([sm, &obj]() {
146         auto material = sm->Material()->GetValue();
147         obj = interface_pointer_cast<META_NS::IObject>(material);
148         return META_NS::IAny::Ptr {};
149     });
150 
151     if (auto cached = FetchJsObj(obj)) {
152         // always return the same js object.
153         return cached;
154     }
155 
156     // No jswrapper for this material , so create it.
157     NapiApi::Object argJS(ctx);
158     napi_value args[] = { scene_.GetValue(), argJS };
159     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
160         CORE_LOG_F("INVALID SCENE!");
161     }
162     auto argc = BASE_NS::countof(args);
163     auto argv = args;
164     return CreateFromNativeInstance(ctx, obj, false /*these are owned by the scene*/, argc, argv);
165 }
166 
SetMaterial(NapiApi::FunctionContext<NapiApi::Object> & ctx)167 void SubMeshJS::SetMaterial(NapiApi::FunctionContext<NapiApi::Object>& ctx)
168 {
169     napi_value undef;
170     napi_get_undefined(ctx, &undef);
171     auto sm = interface_pointer_cast<SCENE_NS::ISubMesh>(GetThisNativeObject(ctx));
172     if (!sm) {
173         // return undefined.. as no actual node.
174         return;
175     }
176     NapiApi::Object obj = ctx.Arg<0>();
177     auto new_material = GetNativeMeta<SCENE_NS::IMaterial>(obj);
178     if (new_material) {
179         ExecSyncTask([sm, &new_material]() {
180             auto cur = sm->Material()->GetValue();
181             if (cur != new_material) {
182                 sm->Material()->SetValue(new_material);
183             }
184             return META_NS::IAny::Ptr {};
185         });
186     }
187 
188     return;
189 }
190