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 "MeshJS.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* MeshJS::GetInstanceImpl(uint32_t id)
26 {
27     if (id == MeshJS::ID) {
28         return this;
29     }
30     return SceneResourceImpl::GetInstanceImpl(id);
31 }
DisposeNative()32 void MeshJS::DisposeNative()
33 {
34     // do nothing for now..
35     LOG_F("MeshJS::DisposeNative");
36     scene_.Reset();
37 }
Init(napi_env env,napi_value exports)38 void MeshJS::Init(napi_env env, napi_value exports)
39 {
40     BASE_NS::vector<napi_property_descriptor> node_props;
41     SceneResourceImpl::GetPropertyDescs(node_props);
42 
43     using namespace NapiApi;
44     node_props.push_back(GetProperty<Object, MeshJS, &MeshJS::GetSubmesh>("subMeshes"));
45     node_props.push_back(GetProperty<Object, MeshJS, &MeshJS::GetAABB>("aabb"));
46     node_props.push_back(
47         GetSetProperty<Object, MeshJS, &MeshJS::GetMaterialOverride, &MeshJS::SetMaterialOverride>("materialOverride"));
48 
49     napi_value func;
50     auto status = napi_define_class(env, "Mesh", NAPI_AUTO_LENGTH, BaseObject::ctor<MeshJS>(), nullptr,
51         node_props.size(), node_props.data(), &func);
52 
53     NapiApi::MyInstanceState* mis;
54     napi_get_instance_data(env, (void**)&mis);
55     mis->StoreCtor("Mesh", func);
56 }
57 
MeshJS(napi_env e,napi_callback_info i)58 MeshJS::MeshJS(napi_env e, napi_callback_info i) : BaseObject<MeshJS>(e, i), SceneResourceImpl(SceneResourceImpl::MESH)
59 {
60     NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object> fromJs(e, i);
61     if (!fromJs) {
62         // okay internal create. we will receive the object after.
63         return;
64     }
65     NapiApi::Object scene = fromJs.Arg<0>();
66     scene_ = scene;
67     if (!GetNativeMeta<SCENE_NS::IScene>(scene_.GetObject())) {
68         CORE_LOG_F("INVALID SCENE!");
69     }
70 }
~MeshJS()71 MeshJS::~MeshJS()
72 {
73     LOG_F("MeshJS -- ");
74 }
75 
GetSubmesh(NapiApi::FunctionContext<> & ctx)76 napi_value MeshJS::GetSubmesh(NapiApi::FunctionContext<>& ctx)
77 {
78     auto node = interface_pointer_cast<SCENE_NS::IMesh>(GetThisNativeObject(ctx));
79     if (!node) {
80         // return undefined.. as no actual node.
81         napi_value undef;
82         napi_get_undefined(ctx, &undef);
83         return undef;
84     }
85 
86     BASE_NS::vector<SCENE_NS::ISubMesh::Ptr> subs;
87     ExecSyncTask([node, &subs]() {
88         subs = node->SubMeshes()->GetValue();
89         return META_NS::IAny::Ptr {};
90     });
91 
92     napi_value tmp;
93     auto status = napi_create_array_with_length(ctx, subs.size(), &tmp);
94     size_t i = 0;
95     for (const auto& node : subs) {
96         NapiApi::Object argJS(ctx);
97         napi_value args[] = { scene_.GetValue(), argJS };
98 
99         napi_value val = CreateFromNativeInstance(
100             ctx, interface_pointer_cast<META_NS::IObject>(node), false, BASE_NS::countof(args), args);
101         status = napi_set_element(ctx, tmp, i++, val);
102     }
103 
104     return tmp;
105 }
106 
GetAABB(NapiApi::FunctionContext<> & ctx)107 napi_value MeshJS::GetAABB(NapiApi::FunctionContext<>& ctx)
108 {
109     napi_value undef;
110     napi_get_undefined(ctx, &undef);
111     auto node = interface_pointer_cast<SCENE_NS::IMesh>(GetThisNativeObject(ctx));
112     if (!node) {
113         // return undefined.. as no actual node.
114         return undef;
115     }
116     BASE_NS::Math::Vec3 aabmin;
117     BASE_NS::Math::Vec3 aabmax;
118     ExecSyncTask([node, &aabmin, &aabmax]() {
119         aabmin = node->AABBMin()->GetValue();
120         aabmax = node->AABBMax()->GetValue();
121         return META_NS::IAny::Ptr {};
122     });
123     NapiApi::Object res(ctx);
124 
125     NapiApi::Object min(ctx);
126     min.Set("x", NapiApi::Value<float> { ctx, aabmin.x });
127     min.Set("y", NapiApi::Value<float> { ctx, aabmin.y });
128     min.Set("z", NapiApi::Value<float> { ctx, aabmin.z });
129     res.Set("aabbMin", min);
130 
131     NapiApi::Object max(ctx);
132     max.Set("x", NapiApi::Value<float> { ctx, aabmax.x });
133     max.Set("y", NapiApi::Value<float> { ctx, aabmax.y });
134     max.Set("z", NapiApi::Value<float> { ctx, aabmax.z });
135     res.Set("aabbMax", max);
136     return res;
137 }
138 
GetMaterialOverride(NapiApi::FunctionContext<> & ctx)139 napi_value MeshJS::GetMaterialOverride(NapiApi::FunctionContext<>& ctx)
140 {
141     napi_value undef;
142     napi_get_undefined(ctx, &undef);
143     auto sm = interface_pointer_cast<SCENE_NS::IMesh>(GetThisNativeObject(ctx));
144     if (!sm) {
145         // return undefined.. as submesh bound.
146         return undef;
147     }
148     META_NS::IObject::Ptr obj;
149     ExecSyncTask([sm, &obj]() {
150         auto material = sm->MaterialOverride()->GetValue();
151         obj = interface_pointer_cast<META_NS::IObject>(material);
152         return META_NS::IAny::Ptr {};
153     });
154 
155     if (obj == nullptr) {
156         return ctx.GetUndefined();
157     }
158     if (auto cached = FetchJsObj(obj)) {
159         // always return the same js object.
160         return cached;
161     }
162     napi_value args[] = { ctx.This() };
163     return CreateFromNativeInstance(ctx, obj, false /*these are owned by the scene*/, BASE_NS::countof(args), args);
164 }
165 
SetMaterialOverride(NapiApi::FunctionContext<NapiApi::Object> & ctx)166 void MeshJS::SetMaterialOverride(NapiApi::FunctionContext<NapiApi::Object>& ctx)
167 {
168     auto sm = interface_pointer_cast<SCENE_NS::IMesh>(GetThisNativeObject(ctx));
169     if (!sm) {
170         // return undefined.. as no actual node.
171         return;
172     }
173     NapiApi::Object obj = ctx.Arg<0>();
174     auto new_material = GetNativeMeta<SCENE_NS::IMaterial>(obj);
175     ExecSyncTask([sm, &new_material]() {
176         sm->MaterialOverride()->SetValue(new_material);
177         return META_NS::IAny::Ptr {};
178     });
179 }
180