cis_config
ObjSerialize.h
1 #ifndef CISOBJSERIALIZE_H_
2 #define CISOBJSERIALIZE_H_
3 
4 #include <../tools.h>
5 
6 #ifdef __cplusplus /* If this is a C++ compiler, use C linkage */
7 extern "C" {
8 #endif
9 
11 typedef struct obj_t {
12  int nvert;
13  int nface;
14  float **vertices;
15  int **faces;
16  int **vertex_colors;
17  char material[100];
18  int ntexc;
19  int nnorm;
20  float **texcoords;
21  float **normals;
23  int **face_normals;
24 } obj_t;
25 
30 static inline
31 obj_t init_obj() {
32  obj_t x;
33  x.nvert = 0;
34  x.nface = 0;
35  x.ntexc = 0;
36  x.nnorm = 0;
37  x.vertices = NULL;
38  x.faces = NULL;
39  x.vertex_colors = NULL;
40  x.material[0] = '\0';
41  x.texcoords = NULL;
42  x.normals = NULL;
43  x.face_texcoords = NULL;
44  x.face_normals = NULL;
45  return x;
46 };
47 
52 static inline
53 void free_obj(obj_t *p) {
54  int i;
55  if (p->vertices != NULL) {
56  for (i = 0; i < p->nvert; i++) {
57  if (p->vertices[i] != NULL) {
58  free(p->vertices[i]);
59  p->vertices[i] = NULL;
60  }
61  }
62  free(p->vertices);
63  p->vertices = NULL;
64  }
65  if (p->vertex_colors != NULL) {
66  for (i = 0; i < p->nvert; i++) {
67  if (p->vertex_colors[i] != NULL) {
68  free(p->vertex_colors[i]);
69  p->vertex_colors[i] = NULL;
70  }
71  }
72  free(p->vertex_colors);
73  p->vertex_colors = NULL;
74  }
75  if (p->faces != NULL) {
76  for (i = 0; i < p->nface; i++) {
77  if (p->faces[i] != NULL) {
78  free(p->faces[i]);
79  p->faces[i] = NULL;
80  }
81  }
82  free(p->faces);
83  p->faces = NULL;
84  }
85  if (p->texcoords != NULL) {
86  for (i = 0; i < p->ntexc; i++) {
87  if (p->texcoords[i] != NULL) {
88  free(p->texcoords[i]);
89  p->texcoords[i] = NULL;
90  }
91  }
92  free(p->texcoords);
93  p->texcoords = NULL;
94  }
95  if (p->normals != NULL) {
96  for (i = 0; i < p->nnorm; i++) {
97  if (p->normals[i] != NULL) {
98  free(p->normals[i]);
99  p->normals[i] = NULL;
100  }
101  }
102  free(p->normals);
103  p->normals = NULL;
104  }
105  if (p->face_texcoords != NULL) {
106  for (i = 0; i < p->nface; i++) {
107  if (p->face_texcoords[i] != NULL) {
108  free(p->face_texcoords[i]);
109  p->face_texcoords[i] = NULL;
110  }
111  }
112  free(p->face_texcoords);
113  p->face_texcoords = NULL;
114  }
115  if (p->face_normals != NULL) {
116  for (i = 0; i < p->nface; i++) {
117  if (p->face_normals[i] != NULL) {
118  free(p->face_normals[i]);
119  p->face_normals[i] = NULL;
120  }
121  }
122  free(p->face_normals);
123  p->face_normals = NULL;
124  }
125  p->material[0] = '\0';
126  p->nvert = 0;
127  p->nface = 0;
128  p->ntexc = 0;
129  p->nnorm = 0;
130 };
131 
142 static inline
143 int alloc_obj(obj_t *p, int nvert, int nface,
144  int ntexc, int nnorm, int do_color) {
145  int i;
146  free_obj(p); // Ensure that existing data is freed
147  p->nvert = nvert;
148  p->nface = nface;
149  p->ntexc = ntexc;
150  p->nnorm = nnorm;
151  // Allocate vertices
152  float **new_vert = (float**)malloc(p->nvert*sizeof(float*));
153  if (new_vert == NULL) {
154  cislog_error("alloc_obj: Failed to allocate vertices.");
155  free_obj(p);
156  return -1;
157  }
158  p->vertices = new_vert;
159  for (i = 0; i < p->nvert; i++) {
160  float *ivert = (float*)malloc(3*sizeof(float));
161  if (ivert == NULL) {
162  cislog_error("alloc_obj: Failed to allocate vertex %d.", i);
163  free_obj(p);
164  return -1;
165  }
166  p->vertices[i] = ivert;
167  }
168  cislog_debug("alloc_obj: Allocated %d vertices.", nvert);
169  // Allocate vertex colors
170  if (do_color) {
171  int **new_vert = (int**)malloc(p->nvert*sizeof(int*));
172  if (new_vert == NULL) {
173  cislog_error("alloc_obj: Failed to allocate vertex_colors.");
174  free_obj(p);
175  return -1;
176  }
177  p->vertex_colors = new_vert;
178  for (i = 0; i < p->nvert; i++) {
179  int *ivert = (int*)malloc(3*sizeof(int));
180  if (ivert == NULL) {
181  cislog_error("alloc_obj: Failed to allocate vertex color %d.", i);
182  free_obj(p);
183  return -1;
184  }
185  p->vertex_colors[i] = ivert;
186  }
187  cislog_debug("alloc_obj: Allocated %d vertex colors.", nvert);
188  }
189  // Allocate texcoords
190  float **new_texc = (float**)malloc(p->ntexc*sizeof(float*));
191  if (new_texc == NULL) {
192  cislog_error("alloc_obj: Failed to allocate texcoords.");
193  free_obj(p);
194  return -1;
195  }
196  p->texcoords = new_texc;
197  for (i = 0; i < p->ntexc; i++) {
198  float *itexc = (float*)malloc(2*sizeof(float));
199  if (itexc == NULL) {
200  cislog_error("alloc_obj: Failed to allocate texcoord %d.", i);
201  free_obj(p);
202  return -1;
203  }
204  p->texcoords[i] = itexc;
205  }
206  cislog_debug("alloc_obj: Allocated %d texcoords.", ntexc);
207  // Allocate normals
208  float **new_norm = (float**)malloc(p->nnorm*sizeof(float*));
209  if (new_norm == NULL) {
210  cislog_error("alloc_obj: Failed to allocate normals.");
211  free_obj(p);
212  return -1;
213  }
214  p->normals = new_norm;
215  for (i = 0; i < p->nnorm; i++) {
216  float *inorm = (float*)malloc(3*sizeof(float));
217  if (inorm == NULL) {
218  cislog_error("alloc_obj: Failed to allocate normal %d.", i);
219  free_obj(p);
220  return -1;
221  }
222  p->normals[i] = inorm;
223  }
224  cislog_debug("alloc_obj: Allocated %d normals.", nnorm);
225  // Allocate faces
226  int **new_face = (int**)malloc(p->nface*sizeof(int*));
227  if (new_face == NULL) {
228  cislog_error("alloc_obj: Failed to allocate faces.");
229  free_obj(p);
230  return -1;
231  }
232  p->faces = new_face;
233  for (i = 0; i < p->nface; i++) {
234  int *iface = (int*)malloc(3*sizeof(int));
235  if (iface == NULL) {
236  cislog_error("alloc_obj: Failed to allocate face %d.", i);
237  free_obj(p);
238  return -1;
239  }
240  p->faces[i] = iface;
241  }
242  cislog_debug("alloc_obj: Allocated %d faces.", nface);
243  // Allocate face texcoords
244  int **new_ftexc = (int**)malloc(p->nface*sizeof(int*));
245  if (new_ftexc == NULL) {
246  cislog_error("alloc_obj: Failed to allocate face texcoords.");
247  free_obj(p);
248  return -1;
249  }
250  p->face_texcoords = new_ftexc;
251  for (i = 0; i < p->nface; i++) {
252  int *iftexc = (int*)malloc(3*sizeof(int));
253  if (iftexc == NULL) {
254  cislog_error("alloc_obj: Failed to allocate texcoords for face %d.", i);
255  free_obj(p);
256  return -1;
257  }
258  p->face_texcoords[i] = iftexc;
259  }
260  cislog_debug("alloc_obj: Allocated %d face texcoords.", nface);
261  // Allocate face normals
262  int **new_fnorm = (int**)malloc(p->nface*sizeof(int*));
263  if (new_fnorm == NULL) {
264  cislog_error("alloc_obj: Failed to allocate face normals.");
265  free_obj(p);
266  return -1;
267  }
268  p->face_normals = new_fnorm;
269  for (i = 0; i < p->nface; i++) {
270  int *ifnorm = (int*)malloc(3*sizeof(int));
271  if (ifnorm == NULL) {
272  cislog_error("alloc_obj: Failed to allocate normals for face %d.", i);
273  free_obj(p);
274  return -1;
275  }
276  p->face_normals[i] = ifnorm;
277  }
278  cislog_debug("alloc_obj: Allocated %d face normals.", nface);
279  // Return
280  cislog_debug("alloc_obj: Allocated for %d vertices and %d faces.",
281  p->nvert, p->nface);
282  return 0;
283 };
284 
295 static inline
296 int serialize_obj(const seri_t s, char *buf, const size_t buf_size,
297  int *args_used, va_list ap) {
298  args_used[0] = 0;
299  int msg_len = 0;
300  int ilen;
301  char iline[500];
302  // Get argument
303  obj_t p = va_arg(ap, obj_t);
304  args_used[0] = 1;
305  buf[0] = '\0';
306  // Format header
307  char header_format[500] = "# Author cis_auto\n"
308  "# Generated by cis_interface\n";
309  if (strlen(p.material) != 0) {
310  sprintf(header_format + strlen(header_format), "usemtl %s\n", p.material);
311  }
312  ilen = strlen(header_format);
313  if (ilen >= (buf_size - msg_len)) {
314  cislog_error("serialize_obj: Buffer (size = %d) is not large "
315  "enough to contain the header (size = %d).", buf_size, ilen);
316  return msg_len + ilen;
317  }
318  strcat(buf, header_format);
319  msg_len = msg_len + ilen;
320  // Add vertex information
321  int i, j;
322  for (i = 0; i < p.nvert; i++) {
323  if (p.vertex_colors != NULL) {
324  ilen = snprintf(buf + msg_len, buf_size - msg_len, "v %f %f %f %d %d %d\n",
325  p.vertices[i][0], p.vertices[i][1], p.vertices[i][2],
326  p.vertex_colors[i][0], p.vertex_colors[i][1], p.vertex_colors[i][2]);
327  } else {
328  ilen = snprintf(buf + msg_len, buf_size - msg_len, "v %f %f %f\n",
329  p.vertices[i][0], p.vertices[i][1], p.vertices[i][2]);
330  }
331  if (ilen < 0) {
332  cislog_error("serialize_obj: Error formatting vertex %d.", i);
333  return -1;
334  } else if (ilen >= (buf_size - msg_len)) {
335  cislog_error("serialize_obj: Buffer (size = %d) is not large "
336  "enough to contain vertex %d (size = %d).",
337  buf_size, i, ilen + msg_len);
338  return msg_len + ilen;
339  }
340  msg_len = msg_len + ilen;
341  }
342  // Add texcoord information
343  for (i = 0; i < p.ntexc; i++) {
344  ilen = snprintf(buf + msg_len, buf_size - msg_len, "vt %f %f\n",
345  p.texcoords[i][0], p.texcoords[i][1]);
346  if (ilen < 0) {
347  cislog_error("serialize_obj: Error formatting texcoord %d.", i);
348  return -1;
349  } else if (ilen >= (buf_size - msg_len)) {
350  cislog_error("serialize_obj: Buffer (size = %d) is not large "
351  "enough to contain texcoord %d (size = %d).",
352  buf_size, i, ilen + msg_len);
353  return msg_len + ilen;
354  }
355  msg_len = msg_len + ilen;
356  }
357  // Add normal information
358  for (i = 0; i < p.nnorm; i++) {
359  ilen = snprintf(buf + msg_len, buf_size - msg_len, "vn %f %f %f\n",
360  p.normals[i][0], p.normals[i][1], p.normals[i][2]);
361  if (ilen < 0) {
362  cislog_error("serialize_obj: Error formatting normal %d.", i);
363  return -1;
364  } else if (ilen >= (buf_size - msg_len)) {
365  cislog_error("serialize_obj: Buffer (size = %d) is not large "
366  "enough to contain normal %d (size = %d).",
367  buf_size, i, ilen + msg_len);
368  return msg_len + ilen;
369  }
370  msg_len = msg_len + ilen;
371  }
372  // Add face information
373  for (i = 0; i < p.nface; i++) {
374  char ival[10];
375  sprintf(iline, "f");
376  for (j = 0; j < 3; j++) {
377  sprintf(ival, " %d", p.faces[i][j] + 1);
378  strcat(iline, ival);
379  strcat(iline, "/");
380  if (p.face_texcoords[i][j] >= 0) {
381  sprintf(ival, "%d", p.face_texcoords[i][j] + 1);
382  strcat(iline, ival);
383  }
384  strcat(iline, "/");
385  if (p.face_normals[i][j] >= 0) {
386  sprintf(ival, "%d", p.face_normals[i][j] + 1);
387  strcat(iline, ival);
388  }
389  }
390  ilen = snprintf(buf + msg_len, buf_size - msg_len, "%s\n", iline);
391  if (ilen < 0) {
392  cislog_error("serialize_obj: Error formatting line face %d.", i);
393  return -1;
394  } else if (ilen > (buf_size - msg_len)) {
395  cislog_error("serialize_obj: Buffer (size = %d) is not large "
396  "enough to contain line for face %d (size = %d).",
397  buf_size, i, ilen + msg_len);
398  return msg_len + ilen;
399  }
400  msg_len = msg_len + ilen;
401  }
402  return msg_len;
403 };
404 
405 
414 static inline
415 int deserialize_obj(const seri_t s, const char *buf, const size_t buf_siz,
416  va_list ap) {
417  int out = 1;
418  int do_colors = 0;
419  size_t *sind = NULL;
420  size_t *eind = NULL;
421  int nlines = 0;
422  int j;
423  int nvert = 0, nface = 0, ntexc = 0, nnorm = 0, nmatl = 0;
424  // Get argument
425  obj_t *p = va_arg(ap, obj_t*);
426  // Counts
427  int n_re_vert = 7;
428  int n_re_face = 3*3 + 1;
429  int n_re_texc = 3;
430  int n_re_norm = 4;
431  int n_re_matl = 2;
432  char re_vert[100] = "v ([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+) ([^ \n]+)";
433  char re_face[100] = "f ([^ \n/]*)/([^ \n/]*)/([^ \n/]*) "
434  "([^ \n/]*)/([^ \n/]*)/([^ \n/]*) "
435  "([^ \n/]*)/([^ \n/]*)/([^ \n/]*)";
436  char re_texc[100] = "vt ([^ \n]+) ([^ \n]+)";
437  char re_norm[100] = "vn ([^ \n]+) ([^ \n]+) ([^ \n]+)";
438  char re_matl[100] = "usemtl ([^\n]+)";
439  nvert = count_matches(re_vert, buf);
440  if (nvert != 0) {
441  do_colors = 1;
442  } else {
443  strcpy(re_vert, "v ([^ \n]+) ([^ \n]+) ([^ \n]+)");
444  n_re_vert = 4;
445  nvert = count_matches(re_vert, buf);
446  }
447  nface = count_matches(re_face, buf);
448  ntexc = count_matches(re_texc, buf);
449  nnorm = count_matches(re_norm, buf);
450  nmatl = count_matches(re_matl, buf);
451  cislog_debug("deserialize_obj: expecting %d verts, %d faces, %d texcoords, %d normals",
452  nvert, nface, ntexc, nnorm);
453  // Allocate
454  if (out > 0) {
455  int ret = alloc_obj(p, nvert, nface, ntexc, nnorm, do_colors);
456  if (ret < 0) {
457  cislog_error("deserialize_obj: Error allocating obj structure.");
458  out = -1;
459  }
460  }
461  // Locate lines
462  int cvert = 0, cface = 0, ctexc = 0, cnorm = 0, cmatl = 0;
463  size_t cur_pos = 0;
464  char iline[500];
465  size_t iline_siz = 0;
466  size_t sind_line, eind_line;
467  if (out > 0) {
468  /* char ival[10]; */
469  /* size_t ival_siz = 0; */
470  while (cur_pos < buf_siz) {
471  cislog_debug("deserialize_obj: Starting position %d/%d",
472  cur_pos, buf_siz);
473  int n_sub_matches = find_match("([^\n]*)\n", buf + cur_pos,
474  &sind_line, &eind_line);
475  if (n_sub_matches == 0) {
476  cislog_debug("deserialize_obj: End of file.");
477  sind_line = 0;
478  eind_line = buf_siz - cur_pos;
479  }
480  iline_siz = eind_line - sind_line;
481  memcpy(iline, buf + cur_pos, iline_siz);
482  iline[iline_siz] = '\0';
483  cislog_debug("deserialize_obj: iline = %s", iline);
484  // Match line
485  if (find_matches("#[^\n]*", iline, &sind, &eind) == 1) {
486  // Comment
487  cislog_debug("deserialize_obj: Comment");
488  } else if (find_matches(re_matl, iline, &sind, &eind) == n_re_matl) {
489  // Material
490  cislog_debug("deserialize_obj: Material");
491  int matl_size = eind[1] - sind[1];
492  memcpy(p->material, iline+sind[1], matl_size);
493  p->material[matl_size] = '\0';
494  cmatl++;
495  } else if (find_matches(re_vert, iline, &sind, &eind) == n_re_vert) {
496  // Vertex
497  cislog_debug("deserialize_obj: Vertex");
498  for (j = 0; j < 3; j++) {
499  p->vertices[cvert][j] = atof(iline + sind[j+1]);
500  }
501  if (do_colors) {
502  for (j = 0; j < 3; j++) {
503  p->vertex_colors[cvert][j] = atoi(iline + sind[j+4]);
504  }
505  }
506  cvert++;
507  } else if (find_matches(re_norm, iline, &sind, &eind) == n_re_norm) {
508  // Normals
509  cislog_debug("deserialize_obj: Normals");
510  for (j = 0; j < 3; j++) {
511  p->normals[cnorm][j] = atof(iline + sind[j+1]);
512  }
513  cnorm++;
514  } else if (find_matches(re_texc, iline, &sind, &eind) == n_re_texc) {
515  // Texcoords
516  cislog_debug("deserialize_obj: Texcoords");
517  for (j = 0; j < 2; j++) {
518  p->texcoords[ctexc][j] = atof(iline + sind[j+1]);
519  }
520  ctexc++;
521  } else if (find_matches(re_face, iline, &sind, &eind) == n_re_face) {
522  // Face
523  int n_sub_matches = find_matches(re_face, iline, &sind, &eind);
524  cislog_debug("deserialize_obj: Face");
525  for (j = 0; j < 3; j++) {
526  p->faces[cface][j] = atoi(iline + sind[3*j+1]) - 1;
527  if ((eind[3*j+2] - sind[3*j+2]) == 0)
528  p->face_texcoords[cface][j] = -1;
529  else
530  p->face_texcoords[cface][j] = atoi(iline + sind[3*j+2]) - 1;
531  if ((eind[3*j+3] - sind[3*j+3]) == 0)
532  p->face_normals[cface][j] = -1;
533  else
534  p->face_normals[cface][j] = atoi(iline + sind[3*j+3]) - 1;
535  }
536  cface++;
537  } else if (find_matches("\n+", iline, &sind, &eind) == 1) {
538  // Empty line
539  cislog_debug("deserialize_obj: Empty line");
540  } else {
541  cislog_error("deserialize_obj: Could not match line: %s", iline);
542  out = -1;
543  break;
544  }
545  nlines++;
546  cur_pos = cur_pos + eind_line;
547  cislog_debug("deserialize_obj: Advancing to position %d/%d",
548  cur_pos, buf_siz);
549  }
550  }
551  if (out > 0) {
552  if (cvert != nvert) {
553  cislog_error("deserialize_obj: Found %d verts, expected %d.", cvert, nvert);
554  out = -1;
555  }
556  if (cface != nface) {
557  cislog_error("deserialize_obj: Found %d faces, expected %d.", cface, nface);
558  out = -1;
559  }
560  if (ctexc != ntexc) {
561  cislog_error("deserialize_obj: Found %d texcs, expected %d.", ctexc, ntexc);
562  out = -1;
563  }
564  if (cnorm != nnorm) {
565  cislog_error("deserialize_obj: Found %d norms, expected %d.", cnorm, nnorm);
566  out = -1;
567  }
568  if (cmatl != nmatl) {
569  cislog_error("deserialize_obj: Found %d materials, expected %d.", cmatl, nmatl);
570  out = -1;
571  }
572  }
573  // Return
574  if (sind != NULL) free(sind);
575  if (eind != NULL) free(eind);
576  if (out < 0) {
577  free_obj(p);
578  }
579  return out;
580 };
581 
582 #ifdef __cplusplus /* If this is a C++ compiler, end C linkage */
583 }
584 #endif
585 
586 #endif /*CISOBJSERIALIZE_H_*/
int ** face_normals
Indices of normals for each face.
Definition: ObjSerialize.h:23
int ** face_texcoords
Indices of texcoords for each face.
Definition: ObjSerialize.h:22
Serializer structure.
Definition: SerializeBase.h:19
Obj structure.
Definition: ObjSerialize.h:11
int nvert
Number of vertices.
Definition: ObjSerialize.h:12
char material[100]
Material that should be used for faces.
Definition: ObjSerialize.h:17
int ntexc
Number of texture coordinates.
Definition: ObjSerialize.h:18
int ** vertex_colors
RGB colors of each vertex.
Definition: ObjSerialize.h:16
int nface
Number faces.
Definition: ObjSerialize.h:13
int ** faces
Indices of the vertices composing each face.
Definition: ObjSerialize.h:15
float ** normals
X, Y, Z direction of normals.
Definition: ObjSerialize.h:21
float ** texcoords
Texture coordinates.
Definition: ObjSerialize.h:20
float ** vertices
X, Y, Z positions of vertices.
Definition: ObjSerialize.h:14
int nnorm
Number of normals.
Definition: ObjSerialize.h:19