1 #include <arcan_shmif.h>
2 #include <arcan_shmif_sub.h>
3
4 #include "decode.h"
5
6 #define TINYOBJ_LOADER_C_IMPLEMENTATION
7 #include "parsers/tinyobj_loader_c.h"
8
process_obj(struct arcan_shmif_cont * C,char * buf,size_t buf_sz)9 static int process_obj(struct arcan_shmif_cont* C, char* buf, size_t buf_sz)
10 {
11 tinyobj_attrib_t attrib;
12 tinyobj_shape_t* shapes = NULL;
13 size_t num_shapes;
14 tinyobj_material_t* materials = NULL;
15 size_t num_materials;
16
17 int rv = tinyobj_parse_obj(&attrib, &shapes, &num_shapes,
18 &materials, &num_materials, buf, buf_sz, 1 /* triangulate */);
19
20 /* obj is 'trivial' enough that it is better to unpack/load in the engine/lua
21 * level, but have some obj support here in order for basic testing - the main
22 * target here is still cgltf */
23
24 /* tinyobj_parse_mtl_file */
25 /* also don't have a way to communicate animations */
26
27 free(buf);
28 if (rv != TINYOBJ_SUCCESS)
29 return EXIT_FAILURE;
30
31 tinyobj_attrib_free(&attrib);
32 /* tinyobj_materials_free */
33 return EXIT_SUCCESS;
34 }
35
decode_3d(struct arcan_shmif_cont * cont,struct arg_arr * args)36 int decode_3d(struct arcan_shmif_cont* cont, struct arg_arr* args)
37 {
38 FILE* fpek = NULL;
39 const char* file = NULL;
40 size_t inbuf_sz = 0;
41 char* inbuf = NULL;
42
43 /* two modes we want to support, 'single file' once mode and as a decoder
44 * daemon that gets fed files repeatedly in order to save setup */
45 if (arg_lookup(args, "file", 0, &file)){
46 fpek = fopen(file, "r");
47 if (!fpek){
48 char buf[64];
49 snprintf(buf, sizeof(buf), "couldn't open %s", file);
50 return show_use(cont, buf);
51 }
52 }
53 else {
54 int fd = wait_for_file(cont, "obj;gltf", NULL);
55 if (-1 == fd){
56 return EXIT_FAILURE;
57 }
58 fpek = fdopen(fd, "r");
59 }
60
61 fseek(fpek, 0, SEEK_END);
62 long pos = ftell(fpek);
63 fseek(fpek, 0, SEEK_SET);
64 if (pos <= 0){
65 char buf[64];
66 snprintf(buf, sizeof(buf), "invalid length (%ld) in %s", pos, file);
67 fclose(fpek);
68 return show_use(cont, buf);
69 }
70
71 /* read the whole thing in memory, the catch 22 is that we need to parse
72 * to know the reasonable size so we can set the context to that, but we
73 * want to drop privileges before then, so need to do it in stages */
74 inbuf = malloc(pos);
75 if (!inbuf){
76 fclose(fpek);
77 return show_use(cont, "out of memory");
78 }
79
80 if (1 != fread(inbuf, pos, 1, fpek)){
81 fclose(fpek);
82 free(inbuf);
83 return show_use(cont, "couldn't load");
84 }
85
86 inbuf_sz = pos;
87 fclose(fpek);
88
89 if (!inbuf_sz)
90 return show_use(cont, "no data in file");
91
92 /* need fuller shmif permissions here as new subsegments are used for
93 * each additional 'surface' */
94 arcan_shmif_privsep(cont, "shmif", NULL, 0);
95
96 /* assume .obj for now */
97 return process_obj(cont, inbuf, inbuf_sz);
98
99 /* now we know the real unpack size, so resize to that */
100 return EXIT_SUCCESS;
101 }
102