• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2025 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 "geometry_definition/CustomJS.h"
17 
18 #include <ColorProxy.h>
19 #include <Vec2Proxy.h>
20 #include <Vec3Proxy.h>
21 #include <napi_api.h>
22 #include <scene/interface/intf_create_mesh.h>
23 
24 namespace GeometryDefinition {
25 
CustomJS()26 CustomJS::CustomJS() : GeometryDefinition() {}
27 
Init(napi_env env,napi_value exports)28 void CustomJS::Init(napi_env env, napi_value exports)
29 {
30     auto ctor = [](napi_env env, napi_callback_info info) -> napi_value {
31         napi_value self;
32         napi_get_cb_info(env, info, nullptr, nullptr, &self, nullptr);
33         auto selfObj = NapiApi::Object { env, self };
34         for (auto&& propertyName : { "vertices", "indices", "normals", "uvs", "colors" }) {
35             napi_value array;
36             napi_create_array(env, &array);
37             const auto arrayObj = NapiApi::Object(env, array);
38             selfObj.Set(propertyName, arrayObj);
39         }
40         return self;
41     };
42 
43     auto getType = [](napi_env e, napi_callback_info) { return NapiApi::Env { e }.GetNumber(GeometryType::CUSTOM); };
44     napi_value topology;
45     napi_create_uint32(env, PrimitiveTopology::TRIANGLE_LIST, &topology);
46     napi_value undefined;
47     napi_get_undefined(env, &undefined);
48     const auto props = BASE_NS::vector<napi_property_descriptor> {
49         // clang-format off
50         { "geometryType", nullptr, nullptr, getType, nullptr, nullptr,   napi_default_jsproperty, nullptr },
51         { "topology",     nullptr, nullptr, nullptr, nullptr, topology,  napi_default_jsproperty, nullptr },
52         { "vertices",     nullptr, nullptr, nullptr, nullptr, undefined, napi_default_jsproperty, nullptr },
53         { "indices",      nullptr, nullptr, nullptr, nullptr, undefined, napi_default_jsproperty, nullptr },
54         { "normals",      nullptr, nullptr, nullptr, nullptr, undefined, napi_default_jsproperty, nullptr },
55         { "uvs",          nullptr, nullptr, nullptr, nullptr, undefined, napi_default_jsproperty, nullptr },
56         { "colors",       nullptr, nullptr, nullptr, nullptr, undefined, napi_default_jsproperty, nullptr },
57         // clang-format on
58     };
59     DefineClass(env, exports, "CustomGeometry", props, ctor);
60 }
61 
RegisterEnums(NapiApi::Object exports)62 void CustomJS::RegisterEnums(NapiApi::Object exports)
63 {
64     napi_value v;
65     NapiApi::Object PrimitiveTopology(exports.GetEnv());
66 
67 #define DECL_ENUM(enu, x)                                           \
68     {                                                               \
69         napi_create_uint32(enu.GetEnv(), PrimitiveTopology::x, &v); \
70         enu.Set(#x, v);                                             \
71     }
72     DECL_ENUM(PrimitiveTopology, TRIANGLE_LIST);
73     DECL_ENUM(PrimitiveTopology, TRIANGLE_STRIP);
74 #undef DECL_ENUM
75 
76     exports.Set("PrimitiveTopology", PrimitiveTopology);
77 }
78 
FromJs(NapiApi::Object jsDefinition)79 GeometryDefinition* CustomJS::FromJs(NapiApi::Object jsDefinition)
80 {
81     auto newObj = new CustomJS();
82     if (newObj->SetTopology(jsDefinition)
83         // clang-format off
84         && ArrayToNative(jsDefinition, "vertices", newObj->vertices_)
85         && ArrayToNative(jsDefinition, "indices",  newObj->indices_)
86         && ArrayToNative(jsDefinition, "normals",  newObj->normals_)
87         && ArrayToNative(jsDefinition, "uvs",      newObj->uvs_)
88         && ArrayToNative(jsDefinition, "colors",   newObj->colors_)
89         // clang-format on
90     ) {
91         return newObj;
92     } else {
93         delete newObj;
94         LOG_E("Unable to create CustomJS: Invalid JS object given");
95     }
96     return {};
97 }
98 
CreateMesh(const SCENE_NS::ICreateMesh::Ptr & creator,const SCENE_NS::MeshConfig & config) const99 SCENE_NS::IMesh::Ptr CustomJS::CreateMesh(
100     const SCENE_NS::ICreateMesh::Ptr& creator, const SCENE_NS::MeshConfig& config) const
101 {
102     const auto meshData = SCENE_NS::CustomMeshData { GetTopology(), vertices_, indices_, normals_, uvs_, colors_ };
103     return creator->Create(config, meshData).GetResult();
104 }
105 
GetTopology() const106 SCENE_NS::PrimitiveTopology CustomJS::GetTopology() const
107 {
108     if (topology_ == PrimitiveTopology::TRIANGLE_LIST) {
109         return SCENE_NS::PrimitiveTopology::TRIANGLE_LIST;
110     } else {
111         return SCENE_NS::PrimitiveTopology::TRIANGLE_STRIP;
112     }
113 }
114 
SetTopology(NapiApi::Object & jsDefinition)115 bool CustomJS::SetTopology(NapiApi::Object& jsDefinition)
116 {
117     if (auto value = jsDefinition.Get<uint32_t>("topology"); value.IsValid()) {
118         uint32_t newTopology = value;
119         if (newTopology <= PrimitiveTopology::TRIANGLE_STRIP) {
120             topology_ = static_cast<PrimitiveTopology>(newTopology);
121             return true;
122         }
123     }
124     LOG_E("Invalid primitive topology given to CustomGeometry");
125     return false;
126 }
127 
128 template<typename ItemType>
ArrayToNative(NapiApi::Object & obj,const BASE_NS::string & arrayName,BASE_NS::vector<ItemType> & target)129 bool CustomJS::ArrayToNative(NapiApi::Object& obj, const BASE_NS::string& arrayName, BASE_NS::vector<ItemType>& target)
130 {
131     NapiApi::Array jsArray = obj.Get<NapiApi::Array>(arrayName);
132     auto newItems = BASE_NS::vector<ItemType> {};
133     const auto length = jsArray.Count();
134     newItems.reserve(length);
135     for (auto i = 0; i < length; i++) {
136         const auto jsItem = jsArray.Get_value(i);
137         if (!jsItem) {
138             LOG_E("Invalid array given to CustomGeometry");
139             return false;
140         }
141         auto conversionOk { false };
142         newItems.emplace_back(ToNative<ItemType>(obj.GetEnv(), jsItem, conversionOk));
143         if (!conversionOk) {
144             LOG_E("Invalid array given to CustomGeometry");
145             return false;
146         }
147     }
148     target.swap(newItems);
149     return true;
150 }
151 
152 template<>
ToNative(napi_env env,napi_value jsItem,bool & conversionOk)153 uint32_t CustomJS::ToNative(napi_env env, napi_value jsItem, bool& conversionOk)
154 {
155     auto tmpSigned = int64_t {};
156     conversionOk = (napi_get_value_int64(env, jsItem, &tmpSigned) == napi_ok);
157     conversionOk &= 0 <= tmpSigned && tmpSigned <= UINT32_MAX;
158     return static_cast<uint32_t>(tmpSigned);
159 }
160 
161 template<>
ToNative(napi_env env,napi_value jsItem,bool & conversionOk)162 BASE_NS::Math::Vec2 CustomJS::ToNative(napi_env env, napi_value jsItem, bool& conversionOk)
163 {
164     return Vec2Proxy::ToNative(NapiApi::Object { env, jsItem }, conversionOk);
165 }
166 
167 template<>
ToNative(napi_env env,napi_value jsItem,bool & conversionOk)168 BASE_NS::Math::Vec3 CustomJS::ToNative(napi_env env, napi_value jsItem, bool& conversionOk)
169 {
170     return Vec3Proxy::ToNative(NapiApi::Object { env, jsItem }, conversionOk);
171 }
172 
173 template<>
ToNative(napi_env env,napi_value jsItem,bool & conversionOk)174 BASE_NS::Color CustomJS::ToNative(napi_env env, napi_value jsItem, bool& conversionOk)
175 {
176     return ColorProxy::ToNative(NapiApi::Object { env, jsItem }, conversionOk);
177 }
178 
179 } // namespace GeometryDefinition
180