occt-gltf-addon 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CMakeLists.txt +183 -0
- package/LICENSE +22 -0
- package/README.md +74 -0
- package/example.js +81 -0
- package/index.d.ts +71 -0
- package/index.js +52 -0
- package/package.json +71 -0
- package/scripts/install.js +79 -0
- package/src/addon.cpp +504 -0
- package/src/convert_worker.cpp +474 -0
- package/src/convert_worker.h +94 -0
- package/src/gltf_writer.cpp +367 -0
- package/src/gltf_writer.h +24 -0
- package/src/gltf_writer_scene.cpp +545 -0
- package/src/mesh_types.h +78 -0
- package/src/occt_convert.cpp +313 -0
- package/src/occt_convert.h +40 -0
- package/src/occt_convert_xde.cpp +760 -0
package/src/addon.cpp
ADDED
|
@@ -0,0 +1,504 @@
|
|
|
1
|
+
#include <napi.h>
|
|
2
|
+
|
|
3
|
+
#include "convert_worker.h"
|
|
4
|
+
|
|
5
|
+
#include <string>
|
|
6
|
+
#include <vector>
|
|
7
|
+
|
|
8
|
+
static Napi::Value ConvertSTEPToGLTF(const Napi::CallbackInfo& info)
|
|
9
|
+
{
|
|
10
|
+
Napi::Env env = info.Env();
|
|
11
|
+
|
|
12
|
+
if (info.Length() < 1 || !info[0].IsObject())
|
|
13
|
+
{
|
|
14
|
+
Napi::TypeError::New(env, "Expected options object").ThrowAsJavaScriptException();
|
|
15
|
+
return env.Null();
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
Napi::Object options = info[0].As<Napi::Object>();
|
|
19
|
+
|
|
20
|
+
if (!options.Has("inputPath") || !options.Get("inputPath").IsString())
|
|
21
|
+
{
|
|
22
|
+
Napi::TypeError::New(env, "options.inputPath must be a string").ThrowAsJavaScriptException();
|
|
23
|
+
return env.Null();
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
std::string inputPath = options.Get("inputPath").As<Napi::String>().Utf8Value();
|
|
27
|
+
|
|
28
|
+
int logLevel = 1; // 0=quiet, 1=info, 2=debug
|
|
29
|
+
if (options.Has("logLevel"))
|
|
30
|
+
{
|
|
31
|
+
const Napi::Value v = options.Get("logLevel");
|
|
32
|
+
if (v.IsNumber())
|
|
33
|
+
{
|
|
34
|
+
logLevel = v.As<Napi::Number>().Int32Value();
|
|
35
|
+
}
|
|
36
|
+
else if (v.IsString())
|
|
37
|
+
{
|
|
38
|
+
const std::string s = v.As<Napi::String>().Utf8Value();
|
|
39
|
+
if (s == "quiet") logLevel = 0;
|
|
40
|
+
else if (s == "info") logLevel = 1;
|
|
41
|
+
else if (s == "debug") logLevel = 2;
|
|
42
|
+
else
|
|
43
|
+
{
|
|
44
|
+
Napi::RangeError::New(env, "logLevel must be 0|1|2 or 'quiet'|'info'|'debug'")
|
|
45
|
+
.ThrowAsJavaScriptException();
|
|
46
|
+
return env.Null();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
else
|
|
50
|
+
{
|
|
51
|
+
Napi::TypeError::New(env, "logLevel must be a number or string").ThrowAsJavaScriptException();
|
|
52
|
+
return env.Null();
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (logLevel < 0 || logLevel > 2)
|
|
56
|
+
{
|
|
57
|
+
Napi::RangeError::New(env, "logLevel must be 0, 1, or 2").ThrowAsJavaScriptException();
|
|
58
|
+
return env.Null();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
ConvertWorker::TessellationOptions tess;
|
|
62
|
+
if (options.Has("tessellation") && options.Get("tessellation").IsObject())
|
|
63
|
+
{
|
|
64
|
+
Napi::Object t = options.Get("tessellation").As<Napi::Object>();
|
|
65
|
+
if (t.Has("linearDeflection") && t.Get("linearDeflection").IsNumber())
|
|
66
|
+
{
|
|
67
|
+
tess.linearDeflection = t.Get("linearDeflection").As<Napi::Number>().DoubleValue();
|
|
68
|
+
}
|
|
69
|
+
if (t.Has("angularDeflection") && t.Get("angularDeflection").IsNumber())
|
|
70
|
+
{
|
|
71
|
+
tess.angularDeflection = t.Get("angularDeflection").As<Napi::Number>().DoubleValue();
|
|
72
|
+
}
|
|
73
|
+
if (t.Has("smoothNormals") && t.Get("smoothNormals").IsBoolean())
|
|
74
|
+
{
|
|
75
|
+
tess.smoothNormals = t.Get("smoothNormals").As<Napi::Boolean>().Value();
|
|
76
|
+
}
|
|
77
|
+
if (t.Has("normalCreaseAngle") && t.Get("normalCreaseAngle").IsNumber())
|
|
78
|
+
{
|
|
79
|
+
tess.normalCreaseAngle = t.Get("normalCreaseAngle").As<Napi::Number>().DoubleValue();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (tess.linearDeflection <= 0.0)
|
|
84
|
+
{
|
|
85
|
+
Napi::RangeError::New(env, "tessellation.linearDeflection must be > 0").ThrowAsJavaScriptException();
|
|
86
|
+
return env.Null();
|
|
87
|
+
}
|
|
88
|
+
if (tess.angularDeflection <= 0.0)
|
|
89
|
+
{
|
|
90
|
+
Napi::RangeError::New(env, "tessellation.angularDeflection must be > 0").ThrowAsJavaScriptException();
|
|
91
|
+
return env.Null();
|
|
92
|
+
}
|
|
93
|
+
if (tess.normalCreaseAngle < 0.0)
|
|
94
|
+
{
|
|
95
|
+
Napi::RangeError::New(env, "tessellation.normalCreaseAngle must be >= 0").ThrowAsJavaScriptException();
|
|
96
|
+
return env.Null();
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
ConvertWorker::FilterOptions filter;
|
|
100
|
+
if (options.Has("filter") && options.Get("filter").IsObject())
|
|
101
|
+
{
|
|
102
|
+
Napi::Object f = options.Get("filter").As<Napi::Object>();
|
|
103
|
+
if (f.Has("minBBoxDiagonal") && f.Get("minBBoxDiagonal").IsNumber())
|
|
104
|
+
{
|
|
105
|
+
filter.minBBoxDiagonal = f.Get("minBBoxDiagonal").As<Napi::Number>().DoubleValue();
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
if (filter.minBBoxDiagonal < 0.0)
|
|
109
|
+
{
|
|
110
|
+
Napi::RangeError::New(env, "filter.minBBoxDiagonal must be >= 0").ThrowAsJavaScriptException();
|
|
111
|
+
return env.Null();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
ConvertWorker::OutputOptions output;
|
|
115
|
+
if (options.Has("output") && options.Get("output").IsObject())
|
|
116
|
+
{
|
|
117
|
+
Napi::Object o = options.Get("output").As<Napi::Object>();
|
|
118
|
+
if (o.Has("unit") && o.Get("unit").IsString())
|
|
119
|
+
{
|
|
120
|
+
const std::string unit = o.Get("unit").As<Napi::String>().Utf8Value();
|
|
121
|
+
if (unit == "m")
|
|
122
|
+
{
|
|
123
|
+
output.unitScale = 0.001; // mm -> m (OCCT default)
|
|
124
|
+
}
|
|
125
|
+
else if (unit == "cm")
|
|
126
|
+
{
|
|
127
|
+
output.unitScale = 0.1; // mm -> cm
|
|
128
|
+
}
|
|
129
|
+
else if (unit == "mm")
|
|
130
|
+
{
|
|
131
|
+
output.unitScale = 1.0; // keep mm
|
|
132
|
+
}
|
|
133
|
+
else
|
|
134
|
+
{
|
|
135
|
+
Napi::RangeError::New(env, "output.unit must be one of: 'm', 'cm', 'mm'")
|
|
136
|
+
.ThrowAsJavaScriptException();
|
|
137
|
+
return env.Null();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
if (o.Has("unitScale") && o.Get("unitScale").IsNumber())
|
|
141
|
+
{
|
|
142
|
+
output.unitScale = o.Get("unitScale").As<Napi::Number>().DoubleValue();
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (o.Has("bakeTransforms") && o.Get("bakeTransforms").IsBoolean())
|
|
146
|
+
{
|
|
147
|
+
output.bakeTransforms = o.Get("bakeTransforms").As<Napi::Boolean>().Value();
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
if (o.Has("centerXY") && o.Get("centerXY").IsBoolean())
|
|
151
|
+
{
|
|
152
|
+
const bool v = o.Get("centerXY").As<Napi::Boolean>().Value();
|
|
153
|
+
output.center = v ? ConvertWorker::OutputOptions::CenterMode::XY
|
|
154
|
+
: ConvertWorker::OutputOptions::CenterMode::None;
|
|
155
|
+
}
|
|
156
|
+
if (o.Has("centerXZ") && o.Get("centerXZ").IsBoolean())
|
|
157
|
+
{
|
|
158
|
+
const bool v = o.Get("centerXZ").As<Napi::Boolean>().Value();
|
|
159
|
+
output.center = v ? ConvertWorker::OutputOptions::CenterMode::XZ
|
|
160
|
+
: ConvertWorker::OutputOptions::CenterMode::None;
|
|
161
|
+
}
|
|
162
|
+
if (o.Has("centerYZ") && o.Get("centerYZ").IsBoolean())
|
|
163
|
+
{
|
|
164
|
+
const bool v = o.Get("centerYZ").As<Napi::Boolean>().Value();
|
|
165
|
+
output.center = v ? ConvertWorker::OutputOptions::CenterMode::YZ
|
|
166
|
+
: ConvertWorker::OutputOptions::CenterMode::None;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
if (o.Has("center") && o.Get("center").IsString())
|
|
170
|
+
{
|
|
171
|
+
const std::string center = o.Get("center").As<Napi::String>().Utf8Value();
|
|
172
|
+
if (center == "none")
|
|
173
|
+
{
|
|
174
|
+
output.center = ConvertWorker::OutputOptions::CenterMode::None;
|
|
175
|
+
}
|
|
176
|
+
else if (center == "xy")
|
|
177
|
+
{
|
|
178
|
+
output.center = ConvertWorker::OutputOptions::CenterMode::XY;
|
|
179
|
+
}
|
|
180
|
+
else if (center == "xz")
|
|
181
|
+
{
|
|
182
|
+
output.center = ConvertWorker::OutputOptions::CenterMode::XZ;
|
|
183
|
+
}
|
|
184
|
+
else if (center == "yz")
|
|
185
|
+
{
|
|
186
|
+
output.center = ConvertWorker::OutputOptions::CenterMode::YZ;
|
|
187
|
+
}
|
|
188
|
+
else
|
|
189
|
+
{
|
|
190
|
+
Napi::RangeError::New(env, "output.center must be one of: 'none', 'xy', 'xz', 'yz'")
|
|
191
|
+
.ThrowAsJavaScriptException();
|
|
192
|
+
return env.Null();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
if (o.Has("zUp") && o.Get("zUp").IsBoolean())
|
|
197
|
+
{
|
|
198
|
+
output.zUp = o.Get("zUp").As<Napi::Boolean>().Value();
|
|
199
|
+
}
|
|
200
|
+
if (o.Has("zup") && o.Get("zup").IsBoolean())
|
|
201
|
+
{
|
|
202
|
+
output.zUp = o.Get("zup").As<Napi::Boolean>().Value();
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
if (o.Has("draco"))
|
|
206
|
+
{
|
|
207
|
+
const Napi::Value dv = o.Get("draco");
|
|
208
|
+
if (dv.IsBoolean())
|
|
209
|
+
{
|
|
210
|
+
output.dracoEnabled = dv.As<Napi::Boolean>().Value();
|
|
211
|
+
}
|
|
212
|
+
else if (dv.IsObject())
|
|
213
|
+
{
|
|
214
|
+
Napi::Object d = dv.As<Napi::Object>();
|
|
215
|
+
if (d.Has("enabled") && d.Get("enabled").IsBoolean())
|
|
216
|
+
{
|
|
217
|
+
output.dracoEnabled = d.Get("enabled").As<Napi::Boolean>().Value();
|
|
218
|
+
}
|
|
219
|
+
else
|
|
220
|
+
{
|
|
221
|
+
output.dracoEnabled = true;
|
|
222
|
+
}
|
|
223
|
+
if (d.Has("compressionLevel") && d.Get("compressionLevel").IsNumber())
|
|
224
|
+
{
|
|
225
|
+
output.dracoCompressionLevel = d.Get("compressionLevel").As<Napi::Number>().Int32Value();
|
|
226
|
+
}
|
|
227
|
+
if (d.Has("quantizationBitsPosition") && d.Get("quantizationBitsPosition").IsNumber())
|
|
228
|
+
{
|
|
229
|
+
output.dracoQuantBitsPosition = d.Get("quantizationBitsPosition").As<Napi::Number>().Int32Value();
|
|
230
|
+
}
|
|
231
|
+
if (d.Has("quantizationBitsNormal") && d.Get("quantizationBitsNormal").IsNumber())
|
|
232
|
+
{
|
|
233
|
+
output.dracoQuantBitsNormal = d.Get("quantizationBitsNormal").As<Napi::Number>().Int32Value();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else
|
|
237
|
+
{
|
|
238
|
+
Napi::TypeError::New(env, "output.draco must be boolean or object").ThrowAsJavaScriptException();
|
|
239
|
+
return env.Null();
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
if (output.unitScale <= 0.0)
|
|
244
|
+
{
|
|
245
|
+
Napi::RangeError::New(env, "output.unitScale must be > 0").ThrowAsJavaScriptException();
|
|
246
|
+
return env.Null();
|
|
247
|
+
}
|
|
248
|
+
if (output.dracoCompressionLevel < 0 || output.dracoCompressionLevel > 10)
|
|
249
|
+
{
|
|
250
|
+
Napi::RangeError::New(env, "output.draco.compressionLevel must be in [0..10]").ThrowAsJavaScriptException();
|
|
251
|
+
return env.Null();
|
|
252
|
+
}
|
|
253
|
+
if (output.dracoQuantBitsPosition < 1 || output.dracoQuantBitsPosition > 30)
|
|
254
|
+
{
|
|
255
|
+
Napi::RangeError::New(env, "output.draco.quantizationBitsPosition must be in [1..30]")
|
|
256
|
+
.ThrowAsJavaScriptException();
|
|
257
|
+
return env.Null();
|
|
258
|
+
}
|
|
259
|
+
if (output.dracoQuantBitsNormal < 1 || output.dracoQuantBitsNormal > 30)
|
|
260
|
+
{
|
|
261
|
+
Napi::RangeError::New(env, "output.draco.quantizationBitsNormal must be in [1..30]")
|
|
262
|
+
.ThrowAsJavaScriptException();
|
|
263
|
+
return env.Null();
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// Build variants list (multi-output) or fallback to single outputPath.
|
|
267
|
+
std::vector<ConvertWorker::VariantOptions> variants;
|
|
268
|
+
if (options.Has("variants"))
|
|
269
|
+
{
|
|
270
|
+
if (!options.Get("variants").IsArray())
|
|
271
|
+
{
|
|
272
|
+
Napi::TypeError::New(env, "options.variants must be an array").ThrowAsJavaScriptException();
|
|
273
|
+
return env.Null();
|
|
274
|
+
}
|
|
275
|
+
Napi::Array arr = options.Get("variants").As<Napi::Array>();
|
|
276
|
+
const uint32_t n = arr.Length();
|
|
277
|
+
if (n == 0)
|
|
278
|
+
{
|
|
279
|
+
Napi::RangeError::New(env, "options.variants must be non-empty").ThrowAsJavaScriptException();
|
|
280
|
+
return env.Null();
|
|
281
|
+
}
|
|
282
|
+
variants.reserve(n);
|
|
283
|
+
for (uint32_t i = 0; i < n; ++i)
|
|
284
|
+
{
|
|
285
|
+
if (!arr.Get(i).IsObject())
|
|
286
|
+
{
|
|
287
|
+
Napi::TypeError::New(env, "variants[i] must be an object").ThrowAsJavaScriptException();
|
|
288
|
+
return env.Null();
|
|
289
|
+
}
|
|
290
|
+
Napi::Object v = arr.Get(i).As<Napi::Object>();
|
|
291
|
+
if (!v.Has("outputPath") || !v.Get("outputPath").IsString())
|
|
292
|
+
{
|
|
293
|
+
Napi::TypeError::New(env, "variants[i].outputPath must be a string").ThrowAsJavaScriptException();
|
|
294
|
+
return env.Null();
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
ConvertWorker::VariantOptions vo;
|
|
298
|
+
vo.outputPath = v.Get("outputPath").As<Napi::String>().Utf8Value();
|
|
299
|
+
vo.tess = tess;
|
|
300
|
+
vo.filter = filter;
|
|
301
|
+
vo.output = output;
|
|
302
|
+
|
|
303
|
+
if (v.Has("tessellation") && v.Get("tessellation").IsObject())
|
|
304
|
+
{
|
|
305
|
+
Napi::Object t = v.Get("tessellation").As<Napi::Object>();
|
|
306
|
+
if (t.Has("linearDeflection") && t.Get("linearDeflection").IsNumber())
|
|
307
|
+
{
|
|
308
|
+
vo.tess.linearDeflection = t.Get("linearDeflection").As<Napi::Number>().DoubleValue();
|
|
309
|
+
}
|
|
310
|
+
if (t.Has("angularDeflection") && t.Get("angularDeflection").IsNumber())
|
|
311
|
+
{
|
|
312
|
+
vo.tess.angularDeflection = t.Get("angularDeflection").As<Napi::Number>().DoubleValue();
|
|
313
|
+
}
|
|
314
|
+
if (t.Has("smoothNormals") && t.Get("smoothNormals").IsBoolean())
|
|
315
|
+
{
|
|
316
|
+
vo.tess.smoothNormals = t.Get("smoothNormals").As<Napi::Boolean>().Value();
|
|
317
|
+
}
|
|
318
|
+
if (t.Has("normalCreaseAngle") && t.Get("normalCreaseAngle").IsNumber())
|
|
319
|
+
{
|
|
320
|
+
vo.tess.normalCreaseAngle = t.Get("normalCreaseAngle").As<Napi::Number>().DoubleValue();
|
|
321
|
+
}
|
|
322
|
+
if (vo.tess.linearDeflection <= 0.0)
|
|
323
|
+
{
|
|
324
|
+
Napi::RangeError::New(env, "variants[i].tessellation.linearDeflection must be > 0")
|
|
325
|
+
.ThrowAsJavaScriptException();
|
|
326
|
+
return env.Null();
|
|
327
|
+
}
|
|
328
|
+
if (vo.tess.angularDeflection <= 0.0)
|
|
329
|
+
{
|
|
330
|
+
Napi::RangeError::New(env, "variants[i].tessellation.angularDeflection must be > 0")
|
|
331
|
+
.ThrowAsJavaScriptException();
|
|
332
|
+
return env.Null();
|
|
333
|
+
}
|
|
334
|
+
if (vo.tess.normalCreaseAngle < 0.0)
|
|
335
|
+
{
|
|
336
|
+
Napi::RangeError::New(env, "variants[i].tessellation.normalCreaseAngle must be >= 0")
|
|
337
|
+
.ThrowAsJavaScriptException();
|
|
338
|
+
return env.Null();
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
if (v.Has("filter") && v.Get("filter").IsObject())
|
|
343
|
+
{
|
|
344
|
+
Napi::Object f = v.Get("filter").As<Napi::Object>();
|
|
345
|
+
if (f.Has("minBBoxDiagonal") && f.Get("minBBoxDiagonal").IsNumber())
|
|
346
|
+
{
|
|
347
|
+
vo.filter.minBBoxDiagonal = f.Get("minBBoxDiagonal").As<Napi::Number>().DoubleValue();
|
|
348
|
+
}
|
|
349
|
+
if (vo.filter.minBBoxDiagonal < 0.0)
|
|
350
|
+
{
|
|
351
|
+
Napi::RangeError::New(env, "variants[i].filter.minBBoxDiagonal must be >= 0")
|
|
352
|
+
.ThrowAsJavaScriptException();
|
|
353
|
+
return env.Null();
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (v.Has("output") && v.Get("output").IsObject())
|
|
358
|
+
{
|
|
359
|
+
Napi::Object o = v.Get("output").As<Napi::Object>();
|
|
360
|
+
// Reuse the same parsing logic by applying overrides in the same order.
|
|
361
|
+
if (o.Has("unit") && o.Get("unit").IsString())
|
|
362
|
+
{
|
|
363
|
+
const std::string unit = o.Get("unit").As<Napi::String>().Utf8Value();
|
|
364
|
+
if (unit == "m") vo.output.unitScale = 0.001;
|
|
365
|
+
else if (unit == "cm") vo.output.unitScale = 0.1;
|
|
366
|
+
else if (unit == "mm") vo.output.unitScale = 1.0;
|
|
367
|
+
else
|
|
368
|
+
{
|
|
369
|
+
Napi::RangeError::New(env, "variants[i].output.unit must be one of: 'm', 'cm', 'mm'")
|
|
370
|
+
.ThrowAsJavaScriptException();
|
|
371
|
+
return env.Null();
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
if (o.Has("unitScale") && o.Get("unitScale").IsNumber())
|
|
375
|
+
{
|
|
376
|
+
vo.output.unitScale = o.Get("unitScale").As<Napi::Number>().DoubleValue();
|
|
377
|
+
}
|
|
378
|
+
if (vo.output.unitScale <= 0.0)
|
|
379
|
+
{
|
|
380
|
+
Napi::RangeError::New(env, "variants[i].output.unitScale must be > 0").ThrowAsJavaScriptException();
|
|
381
|
+
return env.Null();
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
if (o.Has("bakeTransforms") && o.Get("bakeTransforms").IsBoolean())
|
|
385
|
+
{
|
|
386
|
+
vo.output.bakeTransforms = o.Get("bakeTransforms").As<Napi::Boolean>().Value();
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
if (o.Has("center") && o.Get("center").IsString())
|
|
390
|
+
{
|
|
391
|
+
const std::string center = o.Get("center").As<Napi::String>().Utf8Value();
|
|
392
|
+
if (center == "none") vo.output.center = ConvertWorker::OutputOptions::CenterMode::None;
|
|
393
|
+
else if (center == "xy") vo.output.center = ConvertWorker::OutputOptions::CenterMode::XY;
|
|
394
|
+
else if (center == "xz") vo.output.center = ConvertWorker::OutputOptions::CenterMode::XZ;
|
|
395
|
+
else if (center == "yz") vo.output.center = ConvertWorker::OutputOptions::CenterMode::YZ;
|
|
396
|
+
else
|
|
397
|
+
{
|
|
398
|
+
Napi::RangeError::New(env, "variants[i].output.center must be one of: 'none', 'xy', 'xz', 'yz'")
|
|
399
|
+
.ThrowAsJavaScriptException();
|
|
400
|
+
return env.Null();
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
if (o.Has("zUp") && o.Get("zUp").IsBoolean())
|
|
405
|
+
{
|
|
406
|
+
vo.output.zUp = o.Get("zUp").As<Napi::Boolean>().Value();
|
|
407
|
+
}
|
|
408
|
+
if (o.Has("zup") && o.Get("zup").IsBoolean())
|
|
409
|
+
{
|
|
410
|
+
vo.output.zUp = o.Get("zup").As<Napi::Boolean>().Value();
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (o.Has("draco"))
|
|
414
|
+
{
|
|
415
|
+
const Napi::Value dv = o.Get("draco");
|
|
416
|
+
if (dv.IsBoolean())
|
|
417
|
+
{
|
|
418
|
+
vo.output.dracoEnabled = dv.As<Napi::Boolean>().Value();
|
|
419
|
+
}
|
|
420
|
+
else if (dv.IsObject())
|
|
421
|
+
{
|
|
422
|
+
Napi::Object d = dv.As<Napi::Object>();
|
|
423
|
+
if (d.Has("enabled") && d.Get("enabled").IsBoolean())
|
|
424
|
+
{
|
|
425
|
+
vo.output.dracoEnabled = d.Get("enabled").As<Napi::Boolean>().Value();
|
|
426
|
+
}
|
|
427
|
+
else
|
|
428
|
+
{
|
|
429
|
+
vo.output.dracoEnabled = true;
|
|
430
|
+
}
|
|
431
|
+
if (d.Has("compressionLevel") && d.Get("compressionLevel").IsNumber())
|
|
432
|
+
{
|
|
433
|
+
vo.output.dracoCompressionLevel = d.Get("compressionLevel").As<Napi::Number>().Int32Value();
|
|
434
|
+
}
|
|
435
|
+
if (d.Has("quantizationBitsPosition") && d.Get("quantizationBitsPosition").IsNumber())
|
|
436
|
+
{
|
|
437
|
+
vo.output.dracoQuantBitsPosition = d.Get("quantizationBitsPosition").As<Napi::Number>().Int32Value();
|
|
438
|
+
}
|
|
439
|
+
if (d.Has("quantizationBitsNormal") && d.Get("quantizationBitsNormal").IsNumber())
|
|
440
|
+
{
|
|
441
|
+
vo.output.dracoQuantBitsNormal = d.Get("quantizationBitsNormal").As<Napi::Number>().Int32Value();
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
else
|
|
445
|
+
{
|
|
446
|
+
Napi::TypeError::New(env, "variants[i].output.draco must be boolean or object")
|
|
447
|
+
.ThrowAsJavaScriptException();
|
|
448
|
+
return env.Null();
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
if (vo.output.dracoCompressionLevel < 0 || vo.output.dracoCompressionLevel > 10)
|
|
453
|
+
{
|
|
454
|
+
Napi::RangeError::New(env, "variants[i].output.draco.compressionLevel must be in [0..10]")
|
|
455
|
+
.ThrowAsJavaScriptException();
|
|
456
|
+
return env.Null();
|
|
457
|
+
}
|
|
458
|
+
if (vo.output.dracoQuantBitsPosition < 1 || vo.output.dracoQuantBitsPosition > 30)
|
|
459
|
+
{
|
|
460
|
+
Napi::RangeError::New(env, "variants[i].output.draco.quantizationBitsPosition must be in [1..30]")
|
|
461
|
+
.ThrowAsJavaScriptException();
|
|
462
|
+
return env.Null();
|
|
463
|
+
}
|
|
464
|
+
if (vo.output.dracoQuantBitsNormal < 1 || vo.output.dracoQuantBitsNormal > 30)
|
|
465
|
+
{
|
|
466
|
+
Napi::RangeError::New(env, "variants[i].output.draco.quantizationBitsNormal must be in [1..30]")
|
|
467
|
+
.ThrowAsJavaScriptException();
|
|
468
|
+
return env.Null();
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
variants.push_back(std::move(vo));
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
else
|
|
476
|
+
{
|
|
477
|
+
if (!options.Has("outputPath") || !options.Get("outputPath").IsString())
|
|
478
|
+
{
|
|
479
|
+
Napi::TypeError::New(env, "options.outputPath must be a string").ThrowAsJavaScriptException();
|
|
480
|
+
return env.Null();
|
|
481
|
+
}
|
|
482
|
+
ConvertWorker::VariantOptions vo;
|
|
483
|
+
vo.outputPath = options.Get("outputPath").As<Napi::String>().Utf8Value();
|
|
484
|
+
vo.tess = tess;
|
|
485
|
+
vo.filter = filter;
|
|
486
|
+
vo.output = output;
|
|
487
|
+
variants.push_back(std::move(vo));
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
Napi::Promise::Deferred deferred = Napi::Promise::Deferred::New(env);
|
|
491
|
+
auto* worker = new ConvertWorker(env, deferred, std::move(inputPath), logLevel, std::move(variants));
|
|
492
|
+
worker->Queue();
|
|
493
|
+
|
|
494
|
+
return deferred.Promise();
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
static Napi::Object Init(Napi::Env env, Napi::Object exports)
|
|
498
|
+
{
|
|
499
|
+
exports.Set("convertSTEPToGLTF", Napi::Function::New(env, ConvertSTEPToGLTF));
|
|
500
|
+
return exports;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
NODE_API_MODULE(occt_gltf_addon, Init)
|
|
504
|
+
|