1414
1515using namespace emscripten ;
1616
17- // Info structure for library version information
18- struct uvula_info_t
17+ // TypeScript type aliases for better type safety
18+ EMSCRIPTEN_DECLARE_VAL_TYPE (Float32Array);
19+ EMSCRIPTEN_DECLARE_VAL_TYPE (Uint32Array);
20+ EMSCRIPTEN_DECLARE_VAL_TYPE (Int32Array);
21+
22+ // Return type for unwrap function
23+ struct UnwrapResult
24+ {
25+ std::vector<float > uvCoordinates;
26+ uint32_t textureWidth;
27+ uint32_t textureHeight;
28+ };
29+
30+ // Return type for project function (array of polygons as flat arrays)
31+ struct ProjectResult
1932{
20- std::string uvula_version;
21- std::string git_hash;
33+ std::vector<std::vector<float >> polygons;
2234};
2335
2436// Parameter structure for project function
2537struct ProjectParams
2638{
27- std::vector< float > strokePolygon;
28- std::vector< float > meshVertices;
29- std::vector< uint32_t > meshIndices;
30- std::vector< float > meshUV;
31- std::vector< int > meshFacesConnectivity;
32- uint32_t textureWidth;
33- uint32_t textureHeight;
34- std::vector< float > cameraProjectionMatrix;
35- bool isCameraPerspective;
36- uint32_t viewportWidth;
37- uint32_t viewportHeight;
38- std::vector< float > cameraNormal;
39- uint32_t faceId;
39+ Float32Array strokePolygon = Float32Array{ emscripten::val::array ()}; // float[]
40+ Float32Array meshVertices = Float32Array{ emscripten::val::array ()}; // float[]
41+ Uint32Array meshIndices = Uint32Array{ emscripten::val::array ()}; // uint32_t[]
42+ Float32Array meshUV = Float32Array{ emscripten::val::array ()}; // float[]
43+ Int32Array meshFacesConnectivity = Int32Array{ emscripten::val::array ()}; // int32_t[]
44+ uint32_t textureWidth = 0 ;
45+ uint32_t textureHeight = 0 ;
46+ Float32Array cameraProjectionMatrix = Float32Array{ emscripten::val::array ()}; // float[16] - 4x4 matrix
47+ bool isCameraPerspective = false ;
48+ uint32_t viewportWidth = 0 ;
49+ uint32_t viewportHeight = 0 ;
50+ Float32Array cameraNormal = Float32Array{ emscripten::val::array ()}; // float[3] - normal vector
51+ uint32_t faceId = 0 ;
4052};
4153
42- uvula_info_t get_uvula_info ()
54+ std::string get_uvula_info ()
4355{
44- return { UVULA_VERSION, " " }; // Git hash can be added later if needed
56+ return { UVULA_VERSION };
4557}
4658
4759// Typed wrapper functions for better TypeScript generation
48- emscripten::val unwrapTyped (const std::vector< float >& vertices , const std::vector< uint32_t >& indices )
60+ UnwrapResult unwrapTyped (const Float32Array& vertices_js , const Uint32Array& indices_js )
4961{
50- // Convert flat arrays to Point3F and Face vectors
62+ // Convert JavaScript arrays to C++ vectors
5163 std::vector<Point3F> vertex_points;
5264 std::vector<Face> face_indices;
53-
65+
66+ // Get array lengths
67+ unsigned vertices_length = vertices_js[" length" ].as <unsigned >();
68+ unsigned indices_length = indices_js[" length" ].as <unsigned >();
69+
5470 // Convert vertices (expecting flat array of [x1, y1, z1, x2, y2, z2, ...])
55- vertex_points.reserve (vertices.size () / 3 );
56- for (size_t i = 0 ; i < vertices.size (); i += 3 ) {
57- vertex_points.emplace_back (vertices[i], vertices[i + 1 ], vertices[i + 2 ]);
71+ vertex_points.reserve (vertices_length / 3 );
72+ for (unsigned i = 0 ; i < vertices_length; i += 3 ) {
73+ float x = vertices_js[i].as <float >();
74+ float y = vertices_js[i + 1 ].as <float >();
75+ float z = vertices_js[i + 2 ].as <float >();
76+ vertex_points.emplace_back (x, y, z);
5877 }
5978
6079 // Convert indices (expecting flat array of [i1, i2, i3, i4, i5, i6, ...])
61- face_indices.reserve (indices.size () / 3 );
62- for (size_t i = 0 ; i < indices.size (); i += 3 ) {
63- face_indices.push_back ({indices[i], indices[i + 1 ], indices[i + 2 ]});
80+ face_indices.reserve (indices_length / 3 );
81+ for (unsigned i = 0 ; i < indices_length; i += 3 ) {
82+ uint32_t i1 = indices_js[i].as <uint32_t >();
83+ uint32_t i2 = indices_js[i + 1 ].as <uint32_t >();
84+ uint32_t i3 = indices_js[i + 2 ].as <uint32_t >();
85+ face_indices.push_back ({i1, i2, i3});
6486 }
6587
6688 // Prepare output
@@ -70,87 +92,107 @@ emscripten::val unwrapTyped(const std::vector<float>& vertices, const std::vecto
7092
7193 // Perform unwrapping
7294 bool success = smartUnwrap (vertex_points, face_indices, uv_coords, texture_width, texture_height);
73-
95+
7496 if (!success) {
7597 throw std::runtime_error (" Couldn't unwrap UVs!" );
7698 }
7799
78- // Convert result to JavaScript object
79- emscripten::val result = emscripten::val::object ();
100+ // Convert result to structured return type
80101 std::vector<float > uv_array;
81102 uv_array.reserve (uv_coords.size () * 2 );
82-
103+
83104 for (const auto & coord : uv_coords) {
84105 uv_array.push_back (coord.x );
85106 uv_array.push_back (coord.y );
86107 }
87-
88- result. set ( " uvCoordinates " , emscripten::val::array (uv_array));
89- result. set ( " textureWidth " , texture_width);
90- result. set ( " textureHeight " , texture_height);
91-
92- return result ;
108+
109+ return UnwrapResult{
110+ . uvCoordinates = uv_array,
111+ . textureWidth = texture_width,
112+ . textureHeight = texture_height
113+ } ;
93114}
94115
95- emscripten::val projectTyped (
96- const std::vector< float >& stroke_polygon ,
97- const std::vector< float >& mesh_vertices ,
98- const std::vector< uint32_t >& mesh_indices ,
99- const std::vector< float >& mesh_uv ,
100- const std::vector< int >& mesh_faces_connectivity ,
116+ ProjectResult projectTyped (
117+ const Float32Array& stroke_polygon_js ,
118+ const Float32Array& mesh_vertices_js ,
119+ const Uint32Array& mesh_indices_js ,
120+ const Float32Array& mesh_uv_js ,
121+ const Int32Array& mesh_faces_connectivity_js ,
101122 uint32_t texture_width,
102123 uint32_t texture_height,
103- const std::vector< float >& camera_projection_matrix ,
124+ const Float32Array& camera_projection_matrix_js ,
104125 bool is_camera_perspective,
105126 uint32_t viewport_width,
106127 uint32_t viewport_height,
107- const std::vector< float >& camera_normal ,
128+ const Float32Array& camera_normal_js ,
108129 uint32_t face_id)
109130{
110- // Convert stroke polygon
131+ // Convert stroke polygon (flat array of [x1, y1, x2, y2, ...])
111132 std::vector<Point2F> stroke_points;
112- stroke_points.reserve (stroke_polygon.size () / 2 );
113- for (size_t i = 0 ; i < stroke_polygon.size (); i += 2 ) {
114- stroke_points.push_back ({stroke_polygon[i], stroke_polygon[i + 1 ]});
133+ unsigned stroke_length = stroke_polygon_js[" length" ].as <unsigned >();
134+ stroke_points.reserve (stroke_length / 2 );
135+ for (unsigned i = 0 ; i < stroke_length; i += 2 ) {
136+ float x = stroke_polygon_js[i].as <float >();
137+ float y = stroke_polygon_js[i + 1 ].as <float >();
138+ stroke_points.push_back ({x, y});
115139 }
116140
117- // Convert mesh vertices
141+ // Convert mesh vertices (flat array of [x1, y1, z1, x2, y2, z2, ...])
118142 std::vector<Point3F> vertex_points;
119- vertex_points.reserve (mesh_vertices.size () / 3 );
120- for (size_t i = 0 ; i < mesh_vertices.size (); i += 3 ) {
121- vertex_points.emplace_back (mesh_vertices[i], mesh_vertices[i + 1 ], mesh_vertices[i + 2 ]);
143+ unsigned vertices_length = mesh_vertices_js[" length" ].as <unsigned >();
144+ vertex_points.reserve (vertices_length / 3 );
145+ for (unsigned i = 0 ; i < vertices_length; i += 3 ) {
146+ float x = mesh_vertices_js[i].as <float >();
147+ float y = mesh_vertices_js[i + 1 ].as <float >();
148+ float z = mesh_vertices_js[i + 2 ].as <float >();
149+ vertex_points.emplace_back (x, y, z);
122150 }
123151
124- // Convert mesh indices
152+ // Convert mesh indices (flat array of [i1, i2, i3, i4, i5, i6, ...])
125153 std::vector<Face> face_indices;
126- face_indices.reserve (mesh_indices.size () / 3 );
127- for (size_t i = 0 ; i < mesh_indices.size (); i += 3 ) {
128- face_indices.push_back ({mesh_indices[i], mesh_indices[i + 1 ], mesh_indices[i + 2 ]});
154+ unsigned indices_length = mesh_indices_js[" length" ].as <unsigned >();
155+ face_indices.reserve (indices_length / 3 );
156+ for (unsigned i = 0 ; i < indices_length; i += 3 ) {
157+ uint32_t i1 = mesh_indices_js[i].as <uint32_t >();
158+ uint32_t i2 = mesh_indices_js[i + 1 ].as <uint32_t >();
159+ uint32_t i3 = mesh_indices_js[i + 2 ].as <uint32_t >();
160+ face_indices.push_back ({i1, i2, i3});
129161 }
130162
131- // Convert mesh UV coordinates
163+ // Convert mesh UV coordinates (flat array of [u1, v1, u2, v2, ...])
132164 std::vector<Point2F> uv_points;
133- uv_points.reserve (mesh_uv.size () / 2 );
134- for (size_t i = 0 ; i < mesh_uv.size (); i += 2 ) {
135- uv_points.push_back ({mesh_uv[i], mesh_uv[i + 1 ]});
165+ unsigned uv_length = mesh_uv_js[" length" ].as <unsigned >();
166+ uv_points.reserve (uv_length / 2 );
167+ for (unsigned i = 0 ; i < uv_length; i += 2 ) {
168+ float u = mesh_uv_js[i].as <float >();
169+ float v = mesh_uv_js[i + 1 ].as <float >();
170+ uv_points.push_back ({u, v});
136171 }
137172
138- // Convert mesh faces connectivity
173+ // Convert mesh faces connectivity (flat array of [f1, f2, f3, f4, f5, f6, ...])
139174 std::vector<FaceSigned> connectivity;
140- connectivity.reserve (mesh_faces_connectivity.size () / 3 );
141- for (size_t i = 0 ; i < mesh_faces_connectivity.size (); i += 3 ) {
142- connectivity.push_back ({mesh_faces_connectivity[i], mesh_faces_connectivity[i + 1 ], mesh_faces_connectivity[i + 2 ]});
175+ unsigned connectivity_length = mesh_faces_connectivity_js[" length" ].as <unsigned >();
176+ connectivity.reserve (connectivity_length / 3 );
177+ for (unsigned i = 0 ; i < connectivity_length; i += 3 ) {
178+ int32_t i1 = mesh_faces_connectivity_js[i].as <int32_t >();
179+ int32_t i2 = mesh_faces_connectivity_js[i + 1 ].as <int32_t >();
180+ int32_t i3 = mesh_faces_connectivity_js[i + 2 ].as <int32_t >();
181+ connectivity.push_back ({i1, i2, i3});
143182 }
144183
145184 // Convert camera projection matrix (4x4 matrix as flat array)
146185 float matrix_data[4 ][4 ];
147186 for (int i = 0 ; i < 16 ; ++i) {
148- matrix_data[i / 4 ][i % 4 ] = camera_projection_matrix [i];
187+ matrix_data[i / 4 ][i % 4 ] = camera_projection_matrix_js [i]. as < float >() ;
149188 }
150189 Matrix44F projection_matrix (matrix_data);
151190
152191 // Convert camera normal (3-element array)
153- Vector3F normal (camera_normal[0 ], camera_normal[1 ], camera_normal[2 ]);
192+ float normal_x = camera_normal_js[0 ].as <float >();
193+ float normal_y = camera_normal_js[1 ].as <float >();
194+ float normal_z = camera_normal_js[2 ].as <float >();
195+ Vector3F normal (normal_x, normal_y, normal_z);
154196
155197 // Call the projection function
156198 std::vector<Polygon> result = doProject (
@@ -169,24 +211,25 @@ emscripten::val projectTyped(
169211 face_id
170212 );
171213
172- // Convert result to JavaScript array of arrays
173- emscripten::val js_result = emscripten::val::array ();
174- for (size_t i = 0 ; i < result.size (); ++i) {
214+ // Convert result to structured return type
215+ std::vector<std::vector<float >> result_polygons;
216+ result_polygons.reserve (result.size ());
217+
218+ for (const auto & polygon : result) {
175219 std::vector<float > polygon_flat;
176- const Polygon& polygon = result[i];
177220 polygon_flat.reserve (polygon.size () * 2 );
178221 for (const auto & point : polygon) {
179222 polygon_flat.push_back (point.x );
180223 polygon_flat.push_back (point.y );
181224 }
182- js_result. set (i, emscripten::val::array (polygon_flat));
225+ result_polygons. push_back ( std::move (polygon_flat));
183226 }
184227
185- return js_result ;
228+ return ProjectResult{. polygons = result_polygons} ;
186229}
187230
188231// Structured wrapper for project function using ProjectParams
189- emscripten::val projectWithParams (const ProjectParams& params)
232+ ProjectResult projectWithParams (const ProjectParams& params)
190233{
191234 return projectTyped (
192235 params.strokePolygon ,
@@ -241,24 +284,24 @@ emscripten::val jsUnwrap(const emscripten::val& vertices_js, const emscripten::v
241284
242285 // Perform unwrapping
243286 bool success = smartUnwrap (vertices, indices, uv_coords, texture_width, texture_height);
244-
287+
245288 if (!success) {
246289 throw std::runtime_error (" Couldn't unwrap UVs!" );
247290 }
248291
249292 // Convert result to JavaScript object
250293 emscripten::val result = emscripten::val::object ();
251294 emscripten::val uv_array = emscripten::val::array ();
252-
295+
253296 for (size_t i = 0 ; i < uv_coords.size (); ++i) {
254297 uv_array.set (i * 2 , uv_coords[i].x );
255298 uv_array.set (i * 2 + 1 , uv_coords[i].y );
256299 }
257-
300+
258301 result.set (" uvCoordinates" , uv_array);
259302 result.set (" textureWidth" , texture_width);
260303 result.set (" textureHeight" , texture_height);
261-
304+
262305 return result;
263306}
264307
@@ -378,10 +421,23 @@ emscripten::val jsProject(
378421
379422EMSCRIPTEN_BINDINGS (uvula)
380423{
381- // Register array types for better TypeScript generation
382- register_vector<float >(" FloatArray" );
383- register_vector<int >(" IntArray" );
384- register_vector<uint32_t >(" UInt32Array" );
424+ // Register typed array types
425+ register_vector<float >(" Float32Array" );
426+ register_vector<std::vector<float >>(" Float32ArrayArray" );
427+
428+ // Register TypeScript-style typed arrays
429+ emscripten::register_type<Float32Array>(" Float32Array" );
430+ emscripten::register_type<Uint32Array>(" Uint32Array" );
431+ emscripten::register_type<Int32Array>(" Int32Array" );
432+
433+ // Register structured return types
434+ value_object<UnwrapResult>(" UnwrapResult" )
435+ .field (" uvCoordinates" , &UnwrapResult::uvCoordinates)
436+ .field (" textureWidth" , &UnwrapResult::textureWidth)
437+ .field (" textureHeight" , &UnwrapResult::textureHeight);
438+
439+ value_object<ProjectResult>(" ProjectResult" )
440+ .field (" polygons" , &ProjectResult::polygons);
385441
386442 // Register ProjectParams structure
387443 value_object<ProjectParams>(" ProjectParams" )
@@ -403,11 +459,6 @@ EMSCRIPTEN_BINDINGS(uvula)
403459 function (" unwrap" , &unwrapTyped);
404460 function (" project" , &projectWithParams);
405461
406- // Version information
407- value_object<uvula_info_t >(" uvula_info_t" )
408- .field (" uvula_version" , &uvula_info_t ::uvula_version)
409- .field (" git_hash" , &uvula_info_t ::git_hash);
410-
411462 function (" uvula_info" , &get_uvula_info);
412463
413464 // Utility classes for direct access if needed
0 commit comments