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/interface/intf_camera.h>
22 #include <scene/interface/intf_scene.h>
23 #include <scene/interface/intf_mesh.h>
24
25 #include "MeshJS.h"
26 #include "SceneJS.h"
GetInstanceImpl(uint32_t id)27 void* SubMeshJS::GetInstanceImpl(uint32_t id)
28 {
29 if (id == SubMeshJS::ID)
30 return this;
31 // no id will match
32 return nullptr;
33 }
DisposeNative(void * scn)34 void SubMeshJS::DisposeNative(void* scn)
35 {
36 if (disposed_) {
37 return;
38 }
39 disposed_ = true;
40 LOG_V("SubMeshJS::DisposeNative");
41 if (auto* sceneJS = static_cast<SceneJS*>(scn)) {
42 sceneJS->ReleaseStrongDispose(reinterpret_cast<uintptr_t>(&scene_));
43 }
44
45 aabbMin_.reset();
46 aabbMax_.reset();
47 parentMesh_.Reset();
48 scene_.Reset();
49 }
50
Finalize(napi_env env)51 void SubMeshJS::Finalize(napi_env env)
52 {
53 DisposeNative(scene_.GetObject().GetJsWrapper<SceneJS>());
54 BaseObject::Finalize(env);
55 }
56
Dispose(NapiApi::FunctionContext<> & ctx)57 napi_value SubMeshJS::Dispose(NapiApi::FunctionContext<>& ctx)
58 {
59 // Dispose of the native object. (makes the js object invalid)
60 if (TrueRootObject* instance = ctx.This().GetRoot()) {
61 // see if we have "scenejs" as ext (prefer one given as argument)
62 napi_status stat;
63 SceneJS* ptr { nullptr };
64 NapiApi::FunctionContext<NapiApi::Object> args(ctx);
65 if (args) {
66 if (NapiApi::Object obj = args.Arg<0>()) {
67 if (napi_value ext = obj.Get("SceneJS")) {
68 stat = napi_get_value_external(ctx.GetEnv(), ext, (void**)&ptr);
69 }
70 }
71 }
72 if (!ptr) {
73 ptr = scene_.GetObject().GetJsWrapper<SceneJS>();
74 }
75 UnsetNativeObject();
76 instance->DisposeNative(ptr);
77 }
78 return ctx.GetUndefined();
79 }
Init(napi_env env,napi_value exports)80 void SubMeshJS::Init(napi_env env, napi_value exports)
81 {
82 BASE_NS::vector<napi_property_descriptor> node_props;
83
84 using namespace NapiApi;
85 node_props.push_back(GetSetProperty<BASE_NS::string, SubMeshJS, &SubMeshJS::GetName, &SubMeshJS::SetName>("name"));
86 node_props.push_back(GetProperty<Object, SubMeshJS, &SubMeshJS::GetAABB>("aabb"));
87 node_props.push_back(
88 GetSetProperty<Object, SubMeshJS, &SubMeshJS::GetMaterial, &SubMeshJS::SetMaterial>("material"));
89
90 node_props.push_back(MakeTROMethod<FunctionContext<>, SubMeshJS, &SubMeshJS::Dispose>("destroy"));
91
92 napi_value func;
93 auto status = napi_define_class(env, "SubMesh", NAPI_AUTO_LENGTH, BaseObject::ctor<SubMeshJS>(), nullptr,
94 node_props.size(), node_props.data(), &func);
95
96 NapiApi::MyInstanceState* mis;
97 NapiApi::MyInstanceState::GetInstance(env, (void**)&mis);
98 if (mis) {
99 mis->StoreCtor("SubMesh", func);
100 }
101 }
102
SubMeshJS(napi_env e,napi_callback_info i)103 SubMeshJS::SubMeshJS(napi_env e, napi_callback_info i) : BaseObject(e, i)
104 {
105 LOG_V("SubMeshJS ++ ");
106 NapiApi::FunctionContext<NapiApi::Object, NapiApi::Object, uint32_t> fromJs(e, i);
107 if (!fromJs) {
108 // okay internal create. we will receive the object after.
109 return;
110 }
111 scene_ = fromJs.Arg<0>().valueOrDefault();
112 parentMesh_ = fromJs.Arg<1>().valueOrDefault();
113 indexInParent_ = fromJs.Arg<2>().valueOrDefault(); // 2: arg num
114 if (!scene_.GetObject().GetNative<SCENE_NS::IScene>()) {
115 LOG_F("INVALID SCENE!");
116 }
117 {
118 // add the dispose hook to scene. (so that the geometry node is disposed when scene is disposed)
119 NapiApi::Object meJs(fromJs.This());
120 NapiApi::Object scene = fromJs.Arg<0>();
121 if (const auto sceneJS = scene.GetJsWrapper<SceneJS>()) {
122 sceneJS->StrongDisposeHook(reinterpret_cast<uintptr_t>(&scene_), meJs);
123 }
124 }
125 }
~SubMeshJS()126 SubMeshJS::~SubMeshJS()
127 {
128 LOG_V("SubMeshJS --");
129 }
130
GetAABB(NapiApi::FunctionContext<> & ctx)131 napi_value SubMeshJS::GetAABB(NapiApi::FunctionContext<>& ctx)
132 {
133 auto node = ctx.This().GetNative<SCENE_NS::ISubMesh>();
134 if (!node) {
135 // return undefined.. as no actual node.
136 return ctx.GetUndefined();
137 }
138 BASE_NS::Math::Vec3 aabmin;
139 BASE_NS::Math::Vec3 aabmax;
140 aabmin = node->AABBMin()->GetValue();
141 aabmax = node->AABBMax()->GetValue();
142 NapiApi::Env env(ctx.Env());
143 NapiApi::Object res(env);
144
145 NapiApi::Object min(env);
146 min.Set("x", NapiApi::Value<float> { env, aabmin.x });
147 min.Set("y", NapiApi::Value<float> { env, aabmin.y });
148 min.Set("z", NapiApi::Value<float> { env, aabmin.z });
149 res.Set("aabbMin", min);
150
151 NapiApi::Object max(env);
152 max.Set("x", NapiApi::Value<float> { env, aabmax.x });
153 max.Set("y", NapiApi::Value<float> { env, aabmax.y });
154 max.Set("z", NapiApi::Value<float> { env, aabmax.z });
155 res.Set("aabbMax", max);
156 return res.ToNapiValue();
157 }
158
GetName(NapiApi::FunctionContext<> & ctx)159 napi_value SubMeshJS::GetName(NapiApi::FunctionContext<>& ctx)
160 {
161 BASE_NS::string name;
162 if (auto node = ctx.This().GetNative<META_NS::INamed>()) {
163 name = node->Name()->GetValue();
164 }
165 return ctx.GetString(name);
166 }
SetName(NapiApi::FunctionContext<BASE_NS::string> & ctx)167 void SubMeshJS::SetName(NapiApi::FunctionContext<BASE_NS::string>& ctx)
168 {
169 if (auto node = ctx.This().GetNative<META_NS::INamed>()) {
170 BASE_NS::string name = ctx.Arg<0>();
171 node->Name()->SetValue(name);
172 }
173 }
174
GetMaterial(NapiApi::FunctionContext<> & ctx)175 napi_value SubMeshJS::GetMaterial(NapiApi::FunctionContext<>& ctx)
176 {
177 auto sm = ctx.This().GetNative<SCENE_NS::ISubMesh>();
178 if (!sm) {
179 return ctx.GetUndefined();
180 }
181 META_NS::IObject::Ptr obj;
182 auto material = sm->Material()->GetValue();
183
184 NapiApi::Env env(ctx.Env());
185 NapiApi::Object argJS(env);
186 napi_value args[] = { scene_.GetValue(), argJS.ToNapiValue() };
187 if (!scene_.GetObject().GetNative<SCENE_NS::IScene>()) {
188 LOG_F("INVALID SCENE!");
189 }
190 return CreateFromNativeInstance(env, material, PtrType::STRONG, args).ToNapiValue();
191 }
192
SetMaterial(NapiApi::FunctionContext<NapiApi::Object> & ctx)193 void SubMeshJS::SetMaterial(NapiApi::FunctionContext<NapiApi::Object>& ctx)
194 {
195 auto sm = ctx.This().GetNative<SCENE_NS::ISubMesh>();
196 if (!sm) {
197 return;
198 }
199 NapiApi::Object obj = ctx.Arg<0>();
200 auto new_material = obj.GetNative<SCENE_NS::IMaterial>();
201 if (new_material) {
202 auto cur = sm->Material()->GetValue();
203 if (cur != new_material) {
204 sm->Material()->SetValue(new_material);
205 }
206 }
207 }
208