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