464 lines
18 KiB
C
464 lines
18 KiB
C
#include "cell.h"
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#define TINYOBJ_LOADER_C_IMPLEMENTATION
|
|
#include "tinyobj_loader_c.h"
|
|
|
|
typedef struct {
|
|
const char *data;
|
|
size_t len;
|
|
} obj_reader_ctx_t;
|
|
|
|
static void obj_file_reader(void *ctx, const char *filename, int is_mtl, const char *obj_filename, char **buf, size_t *len)
|
|
{
|
|
(void)filename;
|
|
(void)obj_filename;
|
|
|
|
if (buf) *buf = NULL;
|
|
if (len) *len = 0;
|
|
if (is_mtl) return;
|
|
|
|
if (!ctx || !buf || !len) return;
|
|
|
|
obj_reader_ctx_t *rctx = (obj_reader_ctx_t *)ctx;
|
|
*buf = (char *)rctx->data;
|
|
*len = rctx->len;
|
|
}
|
|
|
|
static JSValue make_float_array(JSContext *js, const float *arr, int count)
|
|
{
|
|
JSValue a = JS_NewArray(js);
|
|
for (int i = 0; i < count; i++)
|
|
JS_SetPropertyUint32(js, a, i, JS_NewFloat64(js, arr[i]));
|
|
return a;
|
|
}
|
|
|
|
JSValue js_obj_decode(JSContext *js, JSValue this_val, int argc, JSValueConst *argv)
|
|
{
|
|
size_t len;
|
|
void *raw = js_get_blob_data(js, &len, argv[0]);
|
|
if (raw == NULL) return JS_EXCEPTION;
|
|
|
|
tinyobj_attrib_t attrib;
|
|
tinyobj_shape_t *shapes = NULL;
|
|
tinyobj_material_t *materials = NULL;
|
|
size_t num_shapes, num_materials;
|
|
|
|
obj_reader_ctx_t rctx;
|
|
rctx.data = (const char *)raw;
|
|
rctx.len = len;
|
|
|
|
int result = tinyobj_parse_obj(&attrib, &shapes, &num_shapes, &materials, &num_materials,
|
|
"blob.obj", obj_file_reader, &rctx, TINYOBJ_FLAG_TRIANGULATE);
|
|
|
|
if (result != TINYOBJ_SUCCESS)
|
|
return JS_ThrowReferenceError(js, "failed to parse OBJ file");
|
|
|
|
JSValue obj = JS_NewObject(js);
|
|
|
|
// Build unified buffer with all vertex data for all shapes
|
|
// First pass: count total vertices across all shapes
|
|
size_t total_vertices = 0;
|
|
int global_has_normals = 0;
|
|
int global_has_uvs = 0;
|
|
|
|
for (size_t si = 0; si < num_shapes; si++) {
|
|
tinyobj_shape_t *shape = &shapes[si];
|
|
total_vertices += shape->length * 3;
|
|
|
|
// Check if any shape has normals/uvs
|
|
for (size_t fi = 0; fi < shape->length; fi++) {
|
|
size_t face_idx = shape->face_offset + fi;
|
|
for (int vi = 0; vi < 3; vi++) {
|
|
tinyobj_vertex_index_t idx = attrib.faces[face_idx * 3 + vi];
|
|
if (idx.vn_idx >= 0) global_has_normals = 1;
|
|
if (idx.vt_idx >= 0) global_has_uvs = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Calculate buffer layout
|
|
size_t pos_size = total_vertices * 3 * sizeof(float);
|
|
size_t norm_size = global_has_normals ? total_vertices * 3 * sizeof(float) : 0;
|
|
size_t uv_size = global_has_uvs ? total_vertices * 2 * sizeof(float) : 0;
|
|
size_t idx_size = total_vertices * (total_vertices > 65535 ? sizeof(uint32_t) : sizeof(uint16_t));
|
|
int use_32bit = (total_vertices > 65535);
|
|
|
|
size_t total_buffer_size = pos_size + norm_size + uv_size + idx_size;
|
|
|
|
// Allocate and fill buffer
|
|
uint8_t *buffer_data = malloc(total_buffer_size);
|
|
float *positions = (float *)buffer_data;
|
|
float *normals = global_has_normals ? (float *)(buffer_data + pos_size) : NULL;
|
|
float *uvs = global_has_uvs ? (float *)(buffer_data + pos_size + norm_size) : NULL;
|
|
void *indices = buffer_data + pos_size + norm_size + uv_size;
|
|
|
|
size_t vertex_offset = 0;
|
|
for (size_t si = 0; si < num_shapes; si++) {
|
|
tinyobj_shape_t *shape = &shapes[si];
|
|
size_t num_faces = shape->length;
|
|
|
|
for (size_t fi = 0; fi < num_faces; fi++) {
|
|
size_t face_idx = shape->face_offset + fi;
|
|
|
|
for (int vi = 0; vi < 3; vi++) {
|
|
tinyobj_vertex_index_t idx = attrib.faces[face_idx * 3 + vi];
|
|
size_t v = vertex_offset;
|
|
|
|
// Position
|
|
int v_idx = idx.v_idx;
|
|
if (v_idx >= 0 && v_idx < (int)(attrib.num_vertices)) {
|
|
positions[v * 3 + 0] = attrib.vertices[v_idx * 3 + 0];
|
|
positions[v * 3 + 1] = attrib.vertices[v_idx * 3 + 1];
|
|
positions[v * 3 + 2] = attrib.vertices[v_idx * 3 + 2];
|
|
} else {
|
|
positions[v * 3 + 0] = 0;
|
|
positions[v * 3 + 1] = 0;
|
|
positions[v * 3 + 2] = 0;
|
|
}
|
|
|
|
// Normal
|
|
if (normals) {
|
|
int vn_idx = idx.vn_idx;
|
|
if (vn_idx >= 0 && vn_idx < (int)(attrib.num_normals)) {
|
|
normals[v * 3 + 0] = attrib.normals[vn_idx * 3 + 0];
|
|
normals[v * 3 + 1] = attrib.normals[vn_idx * 3 + 1];
|
|
normals[v * 3 + 2] = attrib.normals[vn_idx * 3 + 2];
|
|
} else {
|
|
normals[v * 3 + 0] = 0;
|
|
normals[v * 3 + 1] = 1;
|
|
normals[v * 3 + 2] = 0;
|
|
}
|
|
}
|
|
|
|
// UV
|
|
if (uvs) {
|
|
int vt_idx = idx.vt_idx;
|
|
if (vt_idx >= 0 && vt_idx < (int)(attrib.num_texcoords)) {
|
|
uvs[v * 2 + 0] = attrib.texcoords[vt_idx * 2 + 0];
|
|
uvs[v * 2 + 1] = attrib.texcoords[vt_idx * 2 + 1];
|
|
} else {
|
|
uvs[v * 2 + 0] = 0;
|
|
uvs[v * 2 + 1] = 0;
|
|
}
|
|
}
|
|
|
|
// Index
|
|
if (use_32bit)
|
|
((uint32_t *)indices)[v] = (uint32_t)v;
|
|
else
|
|
((uint16_t *)indices)[v] = (uint16_t)v;
|
|
|
|
vertex_offset++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create buffer
|
|
JSValue buffers_arr = JS_NewArray(js);
|
|
JSValue buf = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, buf, "blob", js_new_blob_stoned_copy(js, buffer_data, total_buffer_size));
|
|
JS_SetPropertyStr(js, buf, "byte_length", JS_NewInt64(js, total_buffer_size));
|
|
JS_SetPropertyUint32(js, buffers_arr, 0, buf);
|
|
JS_SetPropertyStr(js, obj, "buffers", buffers_arr);
|
|
|
|
// Create views
|
|
JSValue views_arr = JS_NewArray(js);
|
|
int view_idx = 0;
|
|
|
|
// Position view
|
|
JSValue pos_view = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, pos_view, "buffer", JS_NewInt32(js, 0));
|
|
JS_SetPropertyStr(js, pos_view, "byte_offset", JS_NewInt64(js, 0));
|
|
JS_SetPropertyStr(js, pos_view, "byte_length", JS_NewInt64(js, pos_size));
|
|
JS_SetPropertyStr(js, pos_view, "byte_stride", JS_NULL);
|
|
JS_SetPropertyStr(js, pos_view, "usage", JS_NewString(js, "vertex"));
|
|
JS_SetPropertyUint32(js, views_arr, view_idx++, pos_view);
|
|
int pos_view_idx = 0;
|
|
|
|
int norm_view_idx = -1;
|
|
if (global_has_normals) {
|
|
JSValue norm_view = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, norm_view, "buffer", JS_NewInt32(js, 0));
|
|
JS_SetPropertyStr(js, norm_view, "byte_offset", JS_NewInt64(js, pos_size));
|
|
JS_SetPropertyStr(js, norm_view, "byte_length", JS_NewInt64(js, norm_size));
|
|
JS_SetPropertyStr(js, norm_view, "byte_stride", JS_NULL);
|
|
JS_SetPropertyStr(js, norm_view, "usage", JS_NewString(js, "vertex"));
|
|
norm_view_idx = view_idx;
|
|
JS_SetPropertyUint32(js, views_arr, view_idx++, norm_view);
|
|
}
|
|
|
|
int uv_view_idx = -1;
|
|
if (global_has_uvs) {
|
|
JSValue uv_view = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, uv_view, "buffer", JS_NewInt32(js, 0));
|
|
JS_SetPropertyStr(js, uv_view, "byte_offset", JS_NewInt64(js, pos_size + norm_size));
|
|
JS_SetPropertyStr(js, uv_view, "byte_length", JS_NewInt64(js, uv_size));
|
|
JS_SetPropertyStr(js, uv_view, "byte_stride", JS_NULL);
|
|
JS_SetPropertyStr(js, uv_view, "usage", JS_NewString(js, "vertex"));
|
|
uv_view_idx = view_idx;
|
|
JS_SetPropertyUint32(js, views_arr, view_idx++, uv_view);
|
|
}
|
|
|
|
// Index view
|
|
JSValue idx_view = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, idx_view, "buffer", JS_NewInt32(js, 0));
|
|
JS_SetPropertyStr(js, idx_view, "byte_offset", JS_NewInt64(js, pos_size + norm_size + uv_size));
|
|
JS_SetPropertyStr(js, idx_view, "byte_length", JS_NewInt64(js, idx_size));
|
|
JS_SetPropertyStr(js, idx_view, "byte_stride", JS_NULL);
|
|
JS_SetPropertyStr(js, idx_view, "usage", JS_NewString(js, "index"));
|
|
int idx_view_idx = view_idx;
|
|
JS_SetPropertyUint32(js, views_arr, view_idx++, idx_view);
|
|
|
|
JS_SetPropertyStr(js, obj, "views", views_arr);
|
|
|
|
// Create accessors
|
|
JSValue accessors_arr = JS_NewArray(js);
|
|
int acc_idx = 0;
|
|
|
|
// Position accessor
|
|
JSValue pos_acc = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, pos_acc, "view", JS_NewInt32(js, pos_view_idx));
|
|
JS_SetPropertyStr(js, pos_acc, "byte_offset", JS_NewInt64(js, 0));
|
|
JS_SetPropertyStr(js, pos_acc, "count", JS_NewInt64(js, total_vertices));
|
|
JS_SetPropertyStr(js, pos_acc, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, pos_acc, "type", JS_NewString(js, "vec3"));
|
|
JS_SetPropertyStr(js, pos_acc, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, pos_acc, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, pos_acc, "max", JS_NULL);
|
|
int pos_acc_idx = acc_idx;
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, pos_acc);
|
|
|
|
int norm_acc_idx = -1;
|
|
if (global_has_normals) {
|
|
JSValue norm_acc = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, norm_acc, "view", JS_NewInt32(js, norm_view_idx));
|
|
JS_SetPropertyStr(js, norm_acc, "byte_offset", JS_NewInt64(js, 0));
|
|
JS_SetPropertyStr(js, norm_acc, "count", JS_NewInt64(js, total_vertices));
|
|
JS_SetPropertyStr(js, norm_acc, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, norm_acc, "type", JS_NewString(js, "vec3"));
|
|
JS_SetPropertyStr(js, norm_acc, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, norm_acc, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, norm_acc, "max", JS_NULL);
|
|
norm_acc_idx = acc_idx;
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, norm_acc);
|
|
}
|
|
|
|
int uv_acc_idx = -1;
|
|
if (global_has_uvs) {
|
|
JSValue uv_acc = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, uv_acc, "view", JS_NewInt32(js, uv_view_idx));
|
|
JS_SetPropertyStr(js, uv_acc, "byte_offset", JS_NewInt64(js, 0));
|
|
JS_SetPropertyStr(js, uv_acc, "count", JS_NewInt64(js, total_vertices));
|
|
JS_SetPropertyStr(js, uv_acc, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, uv_acc, "type", JS_NewString(js, "vec2"));
|
|
JS_SetPropertyStr(js, uv_acc, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, uv_acc, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, uv_acc, "max", JS_NULL);
|
|
uv_acc_idx = acc_idx;
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, uv_acc);
|
|
}
|
|
|
|
// Index accessor
|
|
JSValue idx_acc = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, idx_acc, "view", JS_NewInt32(js, idx_view_idx));
|
|
JS_SetPropertyStr(js, idx_acc, "byte_offset", JS_NewInt64(js, 0));
|
|
JS_SetPropertyStr(js, idx_acc, "count", JS_NewInt64(js, total_vertices));
|
|
JS_SetPropertyStr(js, idx_acc, "component_type", JS_NewString(js, use_32bit ? "u32" : "u16"));
|
|
JS_SetPropertyStr(js, idx_acc, "type", JS_NewString(js, "scalar"));
|
|
JS_SetPropertyStr(js, idx_acc, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, idx_acc, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, idx_acc, "max", JS_NULL);
|
|
int idx_acc_idx = acc_idx;
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, idx_acc);
|
|
|
|
JS_SetPropertyStr(js, obj, "accessors", accessors_arr);
|
|
|
|
// Create meshes - each shape becomes a mesh with one primitive
|
|
// But we need per-shape accessors since they reference different ranges
|
|
// Actually, for OBJ we'll create per-shape accessors that point to subranges
|
|
|
|
// Rebuild accessors per shape
|
|
JS_FreeValue(js, accessors_arr);
|
|
accessors_arr = JS_NewArray(js);
|
|
acc_idx = 0;
|
|
|
|
JSValue meshes_arr = JS_NewArray(js);
|
|
vertex_offset = 0;
|
|
|
|
for (size_t si = 0; si < num_shapes; si++) {
|
|
tinyobj_shape_t *shape = &shapes[si];
|
|
size_t shape_vertices = shape->length * 3;
|
|
|
|
// Create accessors for this shape
|
|
int shape_pos_acc = acc_idx;
|
|
JSValue spa = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, spa, "view", JS_NewInt32(js, pos_view_idx));
|
|
JS_SetPropertyStr(js, spa, "byte_offset", JS_NewInt64(js, vertex_offset * 3 * sizeof(float)));
|
|
JS_SetPropertyStr(js, spa, "count", JS_NewInt64(js, shape_vertices));
|
|
JS_SetPropertyStr(js, spa, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, spa, "type", JS_NewString(js, "vec3"));
|
|
JS_SetPropertyStr(js, spa, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, spa, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, spa, "max", JS_NULL);
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, spa);
|
|
|
|
int shape_norm_acc = -1;
|
|
if (global_has_normals) {
|
|
shape_norm_acc = acc_idx;
|
|
JSValue sna = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, sna, "view", JS_NewInt32(js, norm_view_idx));
|
|
JS_SetPropertyStr(js, sna, "byte_offset", JS_NewInt64(js, vertex_offset * 3 * sizeof(float)));
|
|
JS_SetPropertyStr(js, sna, "count", JS_NewInt64(js, shape_vertices));
|
|
JS_SetPropertyStr(js, sna, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, sna, "type", JS_NewString(js, "vec3"));
|
|
JS_SetPropertyStr(js, sna, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, sna, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, sna, "max", JS_NULL);
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, sna);
|
|
}
|
|
|
|
int shape_uv_acc = -1;
|
|
if (global_has_uvs) {
|
|
shape_uv_acc = acc_idx;
|
|
JSValue sua = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, sua, "view", JS_NewInt32(js, uv_view_idx));
|
|
JS_SetPropertyStr(js, sua, "byte_offset", JS_NewInt64(js, vertex_offset * 2 * sizeof(float)));
|
|
JS_SetPropertyStr(js, sua, "count", JS_NewInt64(js, shape_vertices));
|
|
JS_SetPropertyStr(js, sua, "component_type", JS_NewString(js, "f32"));
|
|
JS_SetPropertyStr(js, sua, "type", JS_NewString(js, "vec2"));
|
|
JS_SetPropertyStr(js, sua, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, sua, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, sua, "max", JS_NULL);
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, sua);
|
|
}
|
|
|
|
int shape_idx_acc = acc_idx;
|
|
JSValue sia = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, sia, "view", JS_NewInt32(js, idx_view_idx));
|
|
JS_SetPropertyStr(js, sia, "byte_offset", JS_NewInt64(js, vertex_offset * (use_32bit ? sizeof(uint32_t) : sizeof(uint16_t))));
|
|
JS_SetPropertyStr(js, sia, "count", JS_NewInt64(js, shape_vertices));
|
|
JS_SetPropertyStr(js, sia, "component_type", JS_NewString(js, use_32bit ? "u32" : "u16"));
|
|
JS_SetPropertyStr(js, sia, "type", JS_NewString(js, "scalar"));
|
|
JS_SetPropertyStr(js, sia, "normalized", JS_FALSE);
|
|
JS_SetPropertyStr(js, sia, "min", JS_NULL);
|
|
JS_SetPropertyStr(js, sia, "max", JS_NULL);
|
|
JS_SetPropertyUint32(js, accessors_arr, acc_idx++, sia);
|
|
|
|
// Create mesh
|
|
JSValue mesh = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, mesh, "name", shape->name ? JS_NewString(js, shape->name) : JS_NULL);
|
|
|
|
JSValue prims_arr = JS_NewArray(js);
|
|
JSValue prim = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, prim, "topology", JS_NewString(js, "triangles"));
|
|
|
|
JSValue attrs = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, attrs, "POSITION", JS_NewInt32(js, shape_pos_acc));
|
|
if (shape_norm_acc >= 0)
|
|
JS_SetPropertyStr(js, attrs, "NORMAL", JS_NewInt32(js, shape_norm_acc));
|
|
if (shape_uv_acc >= 0)
|
|
JS_SetPropertyStr(js, attrs, "TEXCOORD_0", JS_NewInt32(js, shape_uv_acc));
|
|
JS_SetPropertyStr(js, prim, "attributes", attrs);
|
|
|
|
JS_SetPropertyStr(js, prim, "indices", JS_NewInt32(js, shape_idx_acc));
|
|
JS_SetPropertyStr(js, prim, "material", JS_NULL);
|
|
|
|
JS_SetPropertyUint32(js, prims_arr, 0, prim);
|
|
JS_SetPropertyStr(js, mesh, "primitives", prims_arr);
|
|
|
|
JS_SetPropertyUint32(js, meshes_arr, si, mesh);
|
|
vertex_offset += shape_vertices;
|
|
}
|
|
|
|
JS_SetPropertyStr(js, obj, "accessors", accessors_arr);
|
|
JS_SetPropertyStr(js, obj, "meshes", meshes_arr);
|
|
|
|
// Materials from OBJ
|
|
JSValue materials_arr = JS_NewArray(js);
|
|
for (size_t i = 0; i < num_materials; i++) {
|
|
tinyobj_material_t *mat = &materials[i];
|
|
JSValue m = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, m, "name", mat->name ? JS_NewString(js, mat->name) : JS_NULL);
|
|
|
|
JSValue pbr = JS_NewObject(js);
|
|
float bc[4] = {mat->diffuse[0], mat->diffuse[1], mat->diffuse[2], 1.0f};
|
|
JS_SetPropertyStr(js, pbr, "base_color_factor", make_float_array(js, bc, 4));
|
|
JS_SetPropertyStr(js, pbr, "base_color_texture", JS_NULL);
|
|
JS_SetPropertyStr(js, pbr, "metallic_factor", JS_NewFloat64(js, 0.0));
|
|
JS_SetPropertyStr(js, pbr, "roughness_factor", JS_NewFloat64(js, 1.0));
|
|
JS_SetPropertyStr(js, pbr, "metallic_roughness_texture", JS_NULL);
|
|
JS_SetPropertyStr(js, pbr, "normal_texture", JS_NULL);
|
|
JS_SetPropertyStr(js, pbr, "occlusion_texture", JS_NULL);
|
|
float ef[3] = {mat->emission[0], mat->emission[1], mat->emission[2]};
|
|
JS_SetPropertyStr(js, pbr, "emissive_factor", make_float_array(js, ef, 3));
|
|
JS_SetPropertyStr(js, pbr, "emissive_texture", JS_NULL);
|
|
JS_SetPropertyStr(js, m, "pbr", pbr);
|
|
|
|
JS_SetPropertyStr(js, m, "alpha_mode", JS_NewString(js, "OPAQUE"));
|
|
JS_SetPropertyStr(js, m, "alpha_cutoff", JS_NewFloat64(js, 0.5));
|
|
JS_SetPropertyStr(js, m, "double_sided", JS_FALSE);
|
|
|
|
JS_SetPropertyUint32(js, materials_arr, i, m);
|
|
}
|
|
JS_SetPropertyStr(js, obj, "materials", materials_arr);
|
|
|
|
// Empty arrays for unsupported features
|
|
JS_SetPropertyStr(js, obj, "images", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, obj, "textures", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, obj, "samplers", JS_NewArray(js));
|
|
|
|
// Nodes - one node per mesh
|
|
JSValue nodes_arr = JS_NewArray(js);
|
|
JSValue scene_nodes = JS_NewArray(js);
|
|
for (size_t i = 0; i < num_shapes; i++) {
|
|
JSValue n = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, n, "name", shapes[i].name ? JS_NewString(js, shapes[i].name) : JS_NULL);
|
|
JS_SetPropertyStr(js, n, "mesh", JS_NewInt32(js, i));
|
|
JS_SetPropertyStr(js, n, "children", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, n, "matrix", JS_NULL);
|
|
float t[3] = {0, 0, 0};
|
|
float r[4] = {0, 0, 0, 1};
|
|
float s[3] = {1, 1, 1};
|
|
JS_SetPropertyStr(js, n, "translation", make_float_array(js, t, 3));
|
|
JS_SetPropertyStr(js, n, "rotation", make_float_array(js, r, 4));
|
|
JS_SetPropertyStr(js, n, "scale", make_float_array(js, s, 3));
|
|
JS_SetPropertyStr(js, n, "skin", JS_NULL);
|
|
JS_SetPropertyUint32(js, nodes_arr, i, n);
|
|
JS_SetPropertyUint32(js, scene_nodes, i, JS_NewInt32(js, i));
|
|
}
|
|
JS_SetPropertyStr(js, obj, "nodes", nodes_arr);
|
|
|
|
// Scenes
|
|
JSValue scenes_arr = JS_NewArray(js);
|
|
JSValue scene = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, scene, "nodes", scene_nodes);
|
|
JS_SetPropertyUint32(js, scenes_arr, 0, scene);
|
|
JS_SetPropertyStr(js, obj, "scenes", scenes_arr);
|
|
JS_SetPropertyStr(js, obj, "scene", JS_NewInt32(js, 0));
|
|
|
|
// Empty arrays for animations/skins
|
|
JS_SetPropertyStr(js, obj, "animations", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, obj, "skins", JS_NewArray(js));
|
|
|
|
// Extensions
|
|
JSValue exts = JS_NewObject(js);
|
|
JS_SetPropertyStr(js, exts, "used", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, exts, "required", JS_NewArray(js));
|
|
JS_SetPropertyStr(js, obj, "extensions", exts);
|
|
|
|
free(buffer_data);
|
|
tinyobj_attrib_free(&attrib);
|
|
tinyobj_shapes_free(shapes, num_shapes);
|
|
tinyobj_materials_free(materials, num_materials);
|
|
|
|
return obj;
|
|
}
|
|
|
|
static const JSCFunctionListEntry js_obj_funcs[] = {
|
|
MIST_FUNC_DEF(obj, decode, 1),
|
|
};
|
|
|
|
CELL_USE_FUNCS(js_obj_funcs)
|