BRL-CAD
vrml_write.c
Go to the documentation of this file.
1 /* V R M L _ W R I T E . C
2  * BRL-CAD
3  *
4  * Copyright (c) 1995-2014 United States Government as represented by
5  * the U.S. Army Research Laboratory.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public License
9  * version 2.1 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this file; see the file named COPYING for more
18  * information.
19  *
20  */
21 /** @file vrml_write.c
22  *
23  * Program to convert a BRL-CAD model (in a .g file) to a VRML (2.0)
24  * faceted model by calling on the NMG booleans.
25  *
26  */
27 
28 #include "common.h"
29 
30 /* system headers */
31 #include <stdlib.h>
32 #include <stddef.h>
33 #include <sys/types.h>
34 #include <sys/stat.h>
35 #include <math.h>
36 #include <string.h>
37 #include "bio.h"
38 
39 /* interface headers */
40 #include "vmath.h"
41 #include "bu/getopt.h"
42 #include "bu/units.h"
43 #include "nmg.h"
44 #include "rtgeom.h"
45 #include "raytrace.h"
46 #include "wdb.h"
47 #include "../../plugin.h"
48 
49 #define TXT_BUF_LEN 512
50 #define TXT_NAME_SIZE 128
51 
52 struct plate_mode {
53  int num_bots;
56  struct rt_bot_internal **bots;
57 };
58 
59 struct vrml_mat {
60  /* typical shader parameters */
62  int shininess;
63  double transparency;
64 
65  /* light parameters */
67  vect_t lt_dir;
69 
70  /* texture parameters */
72  int tx_w;
73  int tx_n;
74 };
75 
76 #define PL_O(_m) bu_offsetof(struct vrml_mat, _m)
77 
79  {"%s", TXT_NAME_SIZE, "ma_shader", PL_O(shader), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
80  {"%d", 1, "shine",PL_O(shininess),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
81  {"%d", 1, "sh",PL_O(shininess),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
82  {"%g", 1, "transmit",PL_O(transparency),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
83  {"%g", 1, "tr",PL_O(transparency),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
84  {"%f", 1, "angle",PL_O(lt_angle),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
85  {"%f", 1, "fract",PL_O(lt_fraction),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
86  {"%f", 3, "aim",PL_O(lt_dir),BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
87  {"%d", 1, "w", PL_O(tx_w), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
88  {"%d", 1, "n", PL_O(tx_n), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
89  {"%s", TXT_NAME_SIZE, "file",PL_O(tx_file), BU_STRUCTPARSE_FUNC_NULL, NULL, NULL },
90  {"",0, (char *)0,0,BU_STRUCTPARSE_FUNC_NULL, NULL, NULL }
91 };
92 
93 extern union tree *do_region_end1(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data);
94 extern union tree *do_region_end2(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data);
95 extern union tree *nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data);
96 
97 static char *tok_sep = " \t";
98 static int NMG_debug; /* saved arg of -X, for longjmp handling */
99 static int verbose = 0;
100 static const char *out_file = (char *)NULL; /* Output filename */
101 static FILE *fp_out; /* Output file pointer */
102 static struct db_i *dbip;
103 static struct rt_tess_tol ttol;
104 static struct bn_tol tol;
105 static struct model *the_model;
106 
107 static char *units = "mm";
108 static fastf_t scale_factor = 1.0;
109 
110 static struct db_tree_state tree_state; /* includes tol & model */
111 
112 static int regions_tried = 0;
113 static int regions_converted = 0;
114 static int bomb_cnt = 0;
115 
116 static int bot_dump = 0;
117 static int eval_all = 0;
118 
119 
120 static void
121 clean_pmp(struct plate_mode *pmp)
122 {
123  int i;
124 
125  for (i = 0; i < pmp->num_bots; i++) {
126  bu_free(pmp->bots[i]->faces, "pmp->bots[i]->faces");
127  bu_free(pmp->bots[i]->vertices, "pmp->bots[i]->vertices");
128  if ((pmp->bots[i]->bot_flags & RT_BOT_PLATE) ||
129  (pmp->bots[i]->bot_flags & RT_BOT_PLATE_NOCOS)) {
130  bu_free(pmp->bots[i]->thickness, "pmp->bots[i]->thickness");
131  }
132  if (pmp->bots[i]->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) {
133  bu_free(pmp->bots[i]->normals, "pmp->bots[i]->normals");
134  }
135  if ((pmp->bots[i]->bot_flags & RT_BOT_PLATE) ||
136  (pmp->bots[i]->bot_flags & RT_BOT_PLATE_NOCOS)) {
137  bu_bomb("about to free pmp->bots[i]->face_mode\n");
138  bu_bitv_free(pmp->bots[i]->face_mode);
139  }
140  bu_free(pmp->bots[i], "bots");
141  pmp->bots[i] = (struct rt_bot_internal *)NULL;
142  }
143 
144  pmp->num_bots = 0;
145  pmp->num_nonbots = 0;
146 }
147 
148 /* duplicate bot */
149 struct rt_bot_internal *
150 dup_bot(struct rt_bot_internal *bot_in)
151 {
152  struct rt_bot_internal *bot;
153  size_t i;
154 
155  RT_BOT_CK_MAGIC(bot_in);
156 
157  BU_ALLOC(bot, struct rt_bot_internal);
158 
159  bot->magic = bot_in->magic;
160  bot->mode = bot_in->mode;
161  bot->orientation = bot_in->orientation;
162  bot->bot_flags = bot_in->bot_flags;
163  bot->num_vertices = bot_in->num_vertices;
164  bot->num_faces = bot_in->num_faces;
165  bot->num_normals = bot_in->num_normals;
166  bot->num_face_normals = bot_in->num_face_normals;
167 
168  bot->faces = (int *)bu_calloc(bot_in->num_faces * 3, sizeof(int), "bot faces");
169  for (i = 0; i < bot_in->num_faces * 3; i++) {
170  bot->faces[i] = bot_in->faces[i];
171  }
172 
173  bot->vertices = (fastf_t *)bu_calloc(bot_in->num_vertices * 3, sizeof(fastf_t), "bot verts");
174  for (i = 0; i < bot_in->num_vertices * 3; i++) {
175  bot->vertices[i] = bot_in->vertices[i];
176  }
177 
178  if ((bot_in->bot_flags & RT_BOT_PLATE) || (bot_in->bot_flags & RT_BOT_PLATE_NOCOS)) {
179  if (bot_in->thickness) {
180  bot->thickness = (fastf_t *)bu_calloc(bot_in->num_faces, sizeof(fastf_t), "bot thickness");
181  for (i = 0; i < bot_in->num_faces; i++) {
182  bot->thickness[i] = bot_in->thickness[i];
183  }
184  } else {
185  bu_bomb("dup_bot(): flag should not say plate but thickness is null\n");
186  }
187  }
188 
189  if (bot_in->face_mode) {
190  bot->face_mode = bu_bitv_dup(bot_in->face_mode);
191  }
192 
193  if (bot_in->bot_flags & RT_BOT_HAS_SURFACE_NORMALS) {
194  bot->num_normals = bot_in->num_normals;
195  bot->normals = (fastf_t *)bu_calloc(bot_in->num_normals * 3, sizeof(fastf_t), "BOT normals");
196  bot->face_normals = (int *)bu_calloc(bot_in->num_faces * 3, sizeof(int), "BOT face normals");
197  memcpy(bot->face_normals, bot_in->face_normals, bot_in->num_faces * 3 * sizeof(int));
198  }
199 
200  return bot;
201 }
202 
203 /* return 0 when object is NOT a light or an error occurred. regions
204  * are skipped when this function returns 0.
205  */
206 static int
207 select_lights(struct db_tree_state *UNUSED(tsp), const struct db_full_path *pathp, const struct rt_comb_internal *UNUSED(combp), void *UNUSED(client_data))
208 {
209  struct directory *dp;
210  struct rt_db_internal intern;
211  struct rt_comb_internal *comb;
212  int id;
213 
214  RT_CK_FULL_PATH(pathp);
215  dp = DB_FULL_PATH_CUR_DIR(pathp);
216 
217  if (!(dp->d_flags & RT_DIR_COMB)) {
218  /* object is not a combination therefore can not be a light */
219  return 0;
220  }
221 
222  id = rt_db_get_internal(&intern, dp, dbip, (matp_t)NULL, &rt_uniresource);
223  if (id < 0) {
224  /* error occurred retrieving object */
225  bu_log("Warning: Can not load internal form of %s\n", dp->d_namep);
226  return 0;
227  }
228 
229  if (id != ID_COMBINATION) {
230  /* object is not a combination therefore can not be a light */
231  return 0;
232  }
233 
234  comb = (struct rt_comb_internal *)intern.idb_ptr;
235  RT_CK_COMB(comb);
236 
237  if (BU_STR_EQUAL(bu_vls_addr(&comb->shader), "light")) {
238  rt_db_free_internal(&intern);
239  return 1;
240  } else {
241  rt_db_free_internal(&intern);
242  return 0;
243  }
244 }
245 
246 
247 /* return 0 when IS a light or an error occurred. regions are skipped
248  * when this function returns 0.
249  */
250 static int
251 select_non_lights(struct db_tree_state *UNUSED(tsp), const struct db_full_path *pathp, const struct rt_comb_internal *UNUSED(combp), void *UNUSED(client_data))
252 {
253  struct directory *dp;
254  struct rt_db_internal intern;
255  struct rt_comb_internal *comb;
256  int id;
257 
258  RT_CK_FULL_PATH(pathp);
259  dp = DB_FULL_PATH_CUR_DIR(pathp);
260 
261  id = rt_db_get_internal(&intern, dp, dbip, (matp_t)NULL, &rt_uniresource);
262  if (id < 0) {
263  /* error occurred retrieving object */
264  bu_log("Warning: Can not load internal form of %s\n", dp->d_namep);
265  return 0;
266  }
267 
268  if ((dp->d_flags & RT_DIR_COMB) && (id == ID_COMBINATION)) {
269  comb = (struct rt_comb_internal *)intern.idb_ptr;
270  RT_CK_COMB(comb);
271  if (BU_STR_EQUAL(bu_vls_addr(&comb->shader), "light")) {
272  rt_db_free_internal(&intern);
273  return 0;
274  }
275  }
276 
277  return 1;
278 }
279 
280 
281 /* CSG objects are tessellated and stored in the tree. BOTs are
282  * processed but stored outside tree. This leaf-tess function is
283  * used when we want CSG objects tessellated and evaluated but we
284  * want to output BOTs without boolean evaluation.
285  */
286 union tree *
287 leaf_tess1(struct db_tree_state *tsp, const struct db_full_path *pathp, struct rt_db_internal *ip, void *client_data)
288 {
289  struct rt_bot_internal *bot;
290  struct plate_mode *pmp = (struct plate_mode *)client_data;
291 
292  if (ip->idb_type != ID_BOT) {
293  pmp->num_nonbots++;
294  return nmg_booltree_leaf_tess(tsp, pathp, ip, client_data);
295  }
296 
297  bot = (struct rt_bot_internal *)ip->idb_ptr;
298  RT_BOT_CK_MAGIC(bot);
299 
300  if (pmp->array_size <= pmp->num_bots) {
301  struct rt_bot_internal **bots_tmp;
302  pmp->array_size += 5;
303  bots_tmp = (struct rt_bot_internal **)bu_realloc((void *)pmp->bots,
304  pmp->array_size * sizeof(struct rt_bot_internal *), "pmp->bots");
305  pmp->bots = bots_tmp;
306  }
307 
308  /* walk tree will free the bot, so we need a copy */
309  pmp->bots[pmp->num_bots] = dup_bot(bot);
310  pmp->num_bots++;
311 
312  return (union tree *)NULL;
313 }
314 
315 /* CSG objects are skipped. BOTs are processed but stored outside
316  * tree. This leaf-tess function is used when we want to output
317  * BOTs directly to the VRML file without performing a boolean
318  * evaluation.
319  */
320 union tree *
321 leaf_tess2(struct db_tree_state *UNUSED(tsp), const struct db_full_path *UNUSED(pathp), struct rt_db_internal *ip, void *client_data)
322 {
323  struct rt_bot_internal *bot;
324  struct plate_mode *pmp = (struct plate_mode *)client_data;
325 
326  if (ip->idb_type != ID_BOT) {
327  return (union tree *)NULL;
328  }
329 
330  bot = (struct rt_bot_internal *)ip->idb_ptr;
331  RT_BOT_CK_MAGIC(bot);
332 
333  if (pmp->array_size <= pmp->num_bots) {
334  struct rt_bot_internal **bots_tmp;
335  pmp->array_size += 5;
336  bots_tmp = (struct rt_bot_internal **)bu_realloc((void *)pmp->bots,
337  pmp->array_size * sizeof(struct rt_bot_internal *), "pmp->bots");
338  pmp->bots = bots_tmp;
339  }
340 
341  /* walk tree will free the bot, so we need a copy */
342  pmp->bots[pmp->num_bots] = dup_bot(bot);
343  pmp->num_bots++;
344 
345  return (union tree *)NULL;
346 }
347 
348 
349 /* converts a geometry path to a vrml-compliant id. a buffer is
350  * allocated for use, it's the responsibility of the caller to free
351  * it.
352  *
353  * fortunately '/' is valid, so the paths should convert mostly
354  * untouched. it is probably technically possible to name something
355  * in mged such that two conversions will result in the same name, but
356  * it should be an extremely rare situation.
357  */
358 static void path_2_vrml_id(struct bu_vls *id, const char *path) {
359  static int counter = 0;
360  unsigned int i;
361  char c;
362 
363  /* poof go the previous contents just in case */
364  bu_vls_trunc(id, 0);
365 
366  if (path == NULL) {
367  bu_vls_printf(id, "NO_PATH_%d", counter++);
368  return;
369  }
370 
371  /* disallow any character from the
372  * ISO-IEC-14772-IS-VRML97WithAmendment1 spec that's not
373  * allowed for the first char.
374  */
375  c = *path;
376  switch (c) {
377  /* numbers */
378  case 0x30:
379  bu_vls_strcat(id, "_ZERO");
380  break;
381  case 0x31:
382  bu_vls_strcat(id, "_ONE");
383  break;
384  case 0x32:
385  bu_vls_strcat(id, "_TWO");
386  break;
387  case 0x33:
388  bu_vls_strcat(id, "_THREE");
389  break;
390  case 0x34:
391  bu_vls_strcat(id, "_FOUR");
392  break;
393  case 0x35:
394  bu_vls_strcat(id, "_FIVE");
395  break;
396  case 0x36:
397  bu_vls_strcat(id, "_SIX");
398  break;
399  case 0x37:
400  bu_vls_strcat(id, "_SEVEN");
401  break;
402  case 0x38:
403  bu_vls_strcat(id, "_EIGHT");
404  break;
405  case 0x39:
406  bu_vls_strcat(id, "_NINE");
407  break;
408  case 0x0:
409  case 0x1:
410  case 0x2:
411  case 0x3:
412  case 0x4:
413  case 0x5:
414  case 0x6:
415  case 0x7:
416  case 0x8:
417  case 0x9:
418  case 0x10:
419  case 0x11:
420  case 0x12:
421  case 0x13:
422  case 0x14:
423  case 0x15:
424  case 0x16:
425  case 0x17:
426  case 0x18:
427  case 0x19:
428  case 0x20:
429  /* control codes */
430  bu_vls_strcat(id, "_CTRL_");
431  break;
432  case 0x22:
433  /* " */
434  bu_vls_strcat(id, "_QUOT_");
435  break;
436  case 0x23:
437  /* # */
438  bu_vls_strcat(id, "_NUM_");
439  break;
440  case 0x27:
441  /* ' */
442  bu_vls_strcat(id, "_APOS_");
443  break;
444  case 0x2b:
445  /* + */
446  bu_vls_strcat(id, "_PLUS_");
447  break;
448  case 0x2c:
449  /*, */
450  bu_vls_strcat(id, "_COMMA_");
451  break;
452  case 0x2d:
453  /* - */
454  bu_vls_strcat(id, "_MINUS_");
455  break;
456  case 0x2e:
457  /* . */
458  bu_vls_strcat(id, "_DOT_");
459  break;
460  case 0x5b:
461  /* [ */
462  bu_vls_strcat(id, "_LBRK_");
463  break;
464  case 0x5c:
465  /* \ */
466  bu_vls_strcat(id, "_BACK_");
467  break;
468  case 0x5d:
469  /* ] */
470  bu_vls_strcat(id, "_RBRK_");
471  break;
472  case 0x7b:
473  /* { */
474  bu_vls_strcat(id, "_LBRC_");
475  break;
476  case 0x7d:
477  /* } */
478  bu_vls_strcat(id, "_RBRC_");
479  break;
480  case 0x7f:
481  /* DEL */
482  bu_vls_strcat(id, "_DEL_");
483  break;
484  default:
485  bu_vls_putc(id, c);
486  break;
487  }
488 
489  /* convert the invalid path characters to something valid */
490  for (i = 1; i < strlen(path); i++) {
491  c = *(path+i);
492 
493  /* disallow any character from the
494  * ISO-IEC-14772-IS-VRML97WithAmendment1 spec that's not
495  * allowed for subsequent characters. only difference is that
496  * #'s and numbers are allowed.
497  */
498  switch (c) {
499  case 0x0:
500  case 0x1:
501  case 0x2:
502  case 0x3:
503  case 0x4:
504  case 0x5:
505  case 0x6:
506  case 0x7:
507  case 0x8:
508  case 0x9:
509  case 0x10:
510  case 0x11:
511  case 0x12:
512  case 0x13:
513  case 0x14:
514  case 0x15:
515  case 0x16:
516  case 0x17:
517  case 0x18:
518  case 0x19:
519  case 0x20:
520  /* control codes */
521  bu_vls_strcat(id, "_CTRL_");
522  break;
523  case 0x22:
524  /* " */
525  bu_vls_strcat(id, "_QUOT_");
526  break;
527  case 0x27:
528  /* ' */
529  bu_vls_strcat(id, "_APOS_");
530  break;
531  case 0x2b:
532  /* + */
533  bu_vls_strcat(id, "_PLUS_");
534  break;
535  case 0x2c:
536  /*, */
537  bu_vls_strcat(id, "_COMMA_");
538  break;
539  case 0x2d:
540  /* - */
541  bu_vls_strcat(id, "_MINUS_");
542  break;
543  case 0x2e:
544  /* . */
545  bu_vls_strcat(id, "_DOT_");
546  break;
547  case 0x5b:
548  /* [ */
549  bu_vls_strcat(id, "_LBRK_");
550  break;
551  case 0x5c:
552  /* \ */
553  bu_vls_strcat(id, "_BACK_");
554  break;
555  case 0x5d:
556  /* ] */
557  bu_vls_strcat(id, "_RBRK_");
558  break;
559  case 0x7b:
560  /* { */
561  bu_vls_strcat(id, "_LBRC_");
562  break;
563  case 0x7d:
564  /* } */
565  bu_vls_strcat(id, "_RBRC_");
566  break;
567  case 0x7f:
568  /* DEL */
569  bu_vls_strcat(id, "_DEL_");
570  break;
571  default:
572  bu_vls_putc(id, c);
573  break;
574  } /* switch c */
575  } /* loop over chars */
576 }
577 
578 
579 static int
580 gcv_vrml_write(const char *path, struct db_i *vdbip, const struct gcv_opts *UNUSED(options))
581 {
582  size_t i;
583  struct plate_mode pm;
584  size_t num_objects = 0;
585  char **object_names = NULL;
586 
587  out_file = path;
588  dbip = vdbip;
589  bu_setlinebuf(stderr);
590 
591  the_model = nmg_mm();
592  tree_state = rt_initial_tree_state; /* struct copy */
593  tree_state.ts_tol = &tol;
594  tree_state.ts_ttol = &ttol;
595  tree_state.ts_m = &the_model;
596 
597  ttol.magic = RT_TESS_TOL_MAGIC;
598  /* Defaults, updated by command line options. */
599  ttol.abs = 0.0;
600  ttol.rel = 0.01;
601  ttol.norm = 0.0;
602 
603  tol.magic = BN_TOL_MAGIC;
604  tol.dist = 0.005;
605  tol.dist_sq = tol.dist * tol.dist;
606  tol.perp = 1e-6;
607  tol.para = 1 - tol.perp;
608 
609  /* NOTE: For visualization purposes, in the debug plot files */
610  {
611  /* WTF: This value is specific to the Bradley */
612  nmg_eue_dist = 2.0;
613  }
614 
615  BU_LIST_INIT(&RTG.rtg_vlfree); /* for vlist macros */
616 
617  if ((bot_dump == 1) && (eval_all == 1)) {
618  bu_log("BOT Dump and Evaluate All are mutually exclusive\n");
619  return 0;
620  }
621 
622  if (out_file == NULL) {
623  fp_out = stdout;
624  setmode(fileno(fp_out), O_BINARY);
625  } else {
626  if ((fp_out = fopen(out_file, "wb")) == NULL) {
627  perror("g-vrml");
628  bu_log("Cannot open %s\n", out_file);
629  return 0;
630  }
631  }
632 
633  fprintf(fp_out, "#VRML V2.0 utf8\n");
634  fprintf(fp_out, "#Units are %s\n", units);
635  /* NOTE: We may want to inquire about bounding boxes for the
636  * various groups and add Viewpoints nodes that point the camera
637  * to the center and orient for Top, Side, etc. Views. We will add
638  * some default Material Color definitions (for thousands groups)
639  * before we start defining the geometry.
640  */
641  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_999 Material { diffuseColor 0.78 0.78 0.78 } } }\n");
642  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_1999 Material { diffuseColor 0.88 0.29 0.29 } } }\n");
643  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_2999 Material { diffuseColor 0.82 0.53 0.54 } } }\n");
644  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_3999 Material { diffuseColor 0.39 0.89 0.00 } } }\n");
645  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_4999 Material { diffuseColor 1.00 0.00 0.00 } } }\n");
646  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_5999 Material { diffuseColor 0.82 0.00 0.82 } } }\n");
647  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_6999 Material { diffuseColor 0.62 0.62 0.62 } } }\n");
648  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_7999 Material { diffuseColor 0.49 0.49 0.49 } } }\n");
649  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_8999 Material { diffuseColor 0.18 0.31 0.31 } } }\n");
650  fprintf(fp_out, "Shape { appearance Appearance { material DEF Material_9999 Material { diffuseColor 0.00 0.41 0.82 } } }\n");
651 
652  /* I had hoped to create a separate sub-tree (using the Transform
653  * node) for each group name argument however, it appears they are
654  * all handled at the same time so I will only have one Transform
655  * for the complete conversion. Later on switch nodes may be added
656  * to turn on and off the groups (via ROUTE nodes).
657  */
658  fprintf(fp_out, "Transform {\n");
659  fprintf(fp_out, "\tchildren [\n");
660 
661  pm.num_bots = 0;
662  pm.num_nonbots = 0;
663 
664  if (!eval_all) {
665  pm.array_size = 5;
666  pm.bots = (struct rt_bot_internal **)bu_calloc(pm.array_size,
667  sizeof(struct rt_bot_internal *), "pm.bots");
668  }
669 
670  /* get toplevel objects */
671  {
672  struct directory **results;
674  num_objects = db_ls(dbip, DB_LS_TOPS, NULL, &results);
675  object_names = db_dpv_to_argv(results);
676  bu_free(results, "tops");
677  }
678 
679  if (eval_all) {
680  (void)db_walk_tree(dbip, num_objects, (const char **)(object_names),
681  1, /* ncpu */
682  &tree_state,
683  0,
684  nmg_region_end,
686  (void *)&pm); /* in librt/nmg_bool.c */
687  goto out;
688  }
689 
690  if (bot_dump) {
691  (void)db_walk_tree(dbip, num_objects, (const char **)(object_names),
692  1, /* ncpu */
693  &tree_state,
694  0,
695  do_region_end2,
696  leaf_tess2,
697  (void *)&pm); /* in librt/nmg_bool.c */
698  goto out;
699  }
700 
701  for (i = 0; i < num_objects; i++) {
702  struct directory *dp;
703 
704  dp = db_lookup(dbip, object_names[i], LOOKUP_QUIET);
705  if (dp == RT_DIR_NULL) {
706  bu_log("Cannot find %s\n", object_names[i]);
707  continue;
708  }
709 
710  /* light source must be a combination */
711  if (!(dp->d_flags & RT_DIR_COMB)) {
712  continue;
713  }
714 
715  fprintf(fp_out, "# Includes group %s\n", object_names[i]);
716 
717  /* walk trees selecting only light source regions */
718  (void)db_walk_tree(dbip, 1, (const char **)(&object_names[i]),
719  1, /* ncpu */
720  &tree_state,
721  select_lights,
722  do_region_end1,
723  leaf_tess1,
724  (void *)&pm); /* in librt/nmg_bool.c */
725  }
726 
727  /* Walk indicated tree(s). Each non-light-source region will be output separately */
728  (void)db_walk_tree(dbip, num_objects, (const char **)(object_names),
729  1, /* ncpu */
730  &tree_state,
731  select_non_lights,
732  do_region_end1,
733  leaf_tess1,
734  (void *)&pm); /* in librt/nmg_bool.c */
735 
736  /* Release dynamic storage */
737  nmg_km(the_model);
738 
739  if (!eval_all) {
740  bu_free(pm.bots, "pm.bots");
741  }
742 
743 out:
744  bu_free(object_names, "object_names");
745 
746  /* Now we need to close each group set */
747  fprintf(fp_out, "\t]\n}\n");
748 
749  bu_log("\nTotal of %d regions converted of %d regions attempted.\n",
750  regions_converted, regions_tried);
751 
752  if (regions_converted != regions_tried) {
753  bu_log("Of the %d which failed conversion, %d of these failed due to conversion error.\n",
754  regions_tried - regions_converted, bomb_cnt);
755  }
756 
757  fclose(fp_out);
758  bu_log("Done.\n");
759 
760  return 1;
761 }
762 
763 
764 static const struct gcv_converter converters[] = {
765  {"vrml", NULL, gcv_vrml_write},
766  {NULL, NULL, NULL}
767 };
768 
769 const struct gcv_plugin_info gcv_plugin_conv_vrml_write = {converters};
770 
771 
772 void
773 nmg_2_vrml(struct db_tree_state *tsp, const struct db_full_path *pathp, struct model *m)
774 {
775  struct mater_info *mater = &tsp->ts_mater;
776  const struct bn_tol *tol2 = tsp->ts_tol;
777  struct nmgregion *reg;
778  struct bu_ptbl verts;
779  struct vrml_mat mat;
780  struct bu_vls vls = BU_VLS_INIT_ZERO;
781  char *tok;
782  int i;
783  int first = 1;
784  int is_light = 0;
785  point_t ave_pt = VINIT_ZERO;
786  struct bu_vls shape_name = BU_VLS_INIT_ZERO;
787  char *full_path;
788  /* There may be a better way to capture the region_id, than
789  * getting the rt_comb_internal structure, (and may be a better
790  * way to capture the rt_comb_internal struct), but for now I just
791  * copied the method used in select_lights/select_non_lights above,
792  * could have used a global variable but I noticed none other were
793  * used, so I didn't want to be the first
794  */
795  struct directory *dp;
796  struct rt_db_internal intern;
797  struct rt_comb_internal *comb;
798  int id;
799 
800  /* static due to libbu exception handling */
801  static float r, g, b;
802 
803  NMG_CK_MODEL(m);
804 
805  full_path = db_path_to_string(pathp);
806 
807  RT_CK_FULL_PATH(pathp);
808  dp = DB_FULL_PATH_CUR_DIR(pathp);
809 
810  if (!(dp->d_flags & RT_DIR_COMB)) {
811  return;
812  }
813 
814  id = rt_db_get_internal(&intern, dp, dbip, (matp_t)NULL, &rt_uniresource);
815  if (id < 0) {
816  bu_log("Cannot internal form of %s\n", dp->d_namep);
817  return;
818  }
819 
820  if (id != ID_COMBINATION) {
821  bu_log("Directory/database mismatch!\n\t is '%s' a combination or not?\n",
822  dp->d_namep);
823  return;
824  }
825 
826  comb = (struct rt_comb_internal *)intern.idb_ptr;
827  RT_CK_COMB(comb);
828 
829  if (mater->ma_color_valid) {
830  r = mater->ma_color[0];
831  g = mater->ma_color[1];
832  b = mater->ma_color[2];
833  } else {
834  r = g = b = 0.5;
835  }
836 
837  if (mater->ma_shader) {
838  tok = strtok(mater->ma_shader, tok_sep);
839  bu_strlcpy(mat.shader, tok, TXT_NAME_SIZE);
840  } else {
841  mat.shader[0] = '\0';
842  }
843 
844  mat.shininess = -1;
845  mat.transparency = -1.0;
846  mat.lt_fraction = -1.0;
847  VSETALL(mat.lt_dir, 0.0);
848  mat.lt_angle = -1.0;
849  mat.tx_file[0] = '\0';
850  mat.tx_w = -1;
851  mat.tx_n = -1;
852  bu_vls_strcpy(&vls, &mater->ma_shader[strlen(mat.shader)]);
853  (void)bu_struct_parse(&vls, vrml_mat_parse, (char *)&mat, NULL);
854 
855  if (bu_strncmp("light", mat.shader, 5) == 0) {
856  /* this is a light source */
857  is_light = 1;
858  } else {
859  path_2_vrml_id(&shape_name, full_path);
860  fprintf(fp_out, "\t\tDEF %s Shape {\n", bu_vls_addr(&shape_name));
861 
862  fprintf(fp_out, "\t\t\t# Component_ID: %ld %s\n", comb->region_id, full_path);
863  fprintf(fp_out, "\t\t\tappearance Appearance {\n");
864 
865  if (bu_strncmp("plastic", mat.shader, 7) == 0) {
866  if (mat.shininess < 0) {
867  mat.shininess = 10;
868  }
869  if (mat.transparency < SMALL_FASTF) {
870  mat.transparency = 0.0;
871  }
872 
873  fprintf(fp_out, "\t\t\t\tmaterial Material {\n");
874  fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g \n", r, g, b);
875  fprintf(fp_out, "\t\t\t\t\tshininess %g\n", 1.0-exp(-(double)mat.shininess/20.0));
876  if (mat.transparency > SMALL_FASTF) {
877  fprintf(fp_out, "\t\t\t\t\ttransparency %g\n", mat.transparency);
878  }
879  fprintf(fp_out, "\t\t\t\t\tspecularColor %g %g %g \n\t\t\t\t}\n", 1.0, 1.0, 1.0);
880  } else if (bu_strncmp("glass", mat.shader, 5) == 0) {
881  if (mat.shininess < 0) {
882  mat.shininess = 4;
883  }
884  if (mat.transparency < SMALL_FASTF) {
885  mat.transparency = 0.8;
886  }
887 
888  fprintf(fp_out, "\t\t\t\tmaterial Material {\n");
889  fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g \n", r, g, b);
890  fprintf(fp_out, "\t\t\t\t\tshininess %g\n", 1.0-exp(-(double)mat.shininess/20.0));
891  if (mat.transparency > SMALL_FASTF) {
892  fprintf(fp_out, "\t\t\t\t\ttransparency %g\n", mat.transparency);
893  }
894  fprintf(fp_out, "\t\t\t\t\tspecularColor %g %g %g \n\t\t\t\t}\n", 1.0, 1.0, 1.0);
895  } else if (bu_strncmp("texture", mat.shader, 7) == 0) {
896  if (mat.tx_w < 0) {
897  mat.tx_w = 512;
898  }
899  if (mat.tx_n < 0) {
900  mat.tx_n = 512;
901  }
902  if (strlen(mat.tx_file)) {
903  int tex_fd;
904  unsigned char tex_buf[TXT_BUF_LEN * 3];
905 
906  if ((tex_fd = open(mat.tx_file, O_RDONLY | O_BINARY)) == (-1)) {
907  bu_log("Cannot open texture file (%s)\n", mat.tx_file);
908  perror("g-vrml: ");
909  } else {
910  long tex_len;
911  long bytes_read = 0;
912  long bytes_to_go = 0;
913 
914  /* Johns note - need to check (test) the texture stuff */
915  fprintf(fp_out, "\t\t\t\ttextureTransform TextureTransform {\n");
916  fprintf(fp_out, "\t\t\t\t\tscale 1.33333 1.33333\n\t\t\t\t}\n");
917  fprintf(fp_out, "\t\t\t\ttexture PixelTexture {\n");
918  fprintf(fp_out, "\t\t\t\t\trepeatS TRUE\n");
919  fprintf(fp_out, "\t\t\t\t\trepeatT TRUE\n");
920  fprintf(fp_out, "\t\t\t\t\timage %d %d %d\n", mat.tx_w, mat.tx_n, 3);
921  tex_len = mat.tx_w*mat.tx_n * 3;
922  while (bytes_read < tex_len) {
923  int nbytes;
924  long readval;
925 
926  bytes_to_go = tex_len - bytes_read;
927  CLAMP(bytes_to_go, 0, TXT_BUF_LEN * 3);
928 
929  nbytes = 0;
930  while (nbytes < bytes_to_go) {
931  readval = read(tex_fd, &tex_buf[nbytes], bytes_to_go-nbytes);
932  if (readval < 0) {
933  perror("READ ERROR");
934  break;
935  } else {
936  nbytes += readval;
937  }
938  }
939  bytes_read += nbytes;
940  for (i = 0; i < nbytes; i += 3) {
941  fprintf(fp_out, "\t\t\t0x%02x%02x%02x\n",
942  tex_buf[i], tex_buf[i+1], tex_buf[i+2]);
943  }
944  }
945  fprintf(fp_out, "\t\t\t\t}\n");
946 
947  close(tex_fd);
948  }
949  }
950  } else if (mater->ma_color_valid) {
951  /* no shader specified, but a color is assigned */
952  fprintf(fp_out, "\t\t\t\tmaterial Material {\n");
953  fprintf(fp_out, "\t\t\t\t\tdiffuseColor %g %g %g }\n", r, g, b);
954  } else {
955  /* If no color was defined set the colors according to the thousands groups */
956  int thou = comb->region_id / 1000;
957  thou == 0 ? fprintf(fp_out, "\t\t\tmaterial USE Material_999\n")
958  : thou == 1 ? fprintf(fp_out, "\t\t\tmaterial USE Material_1999\n")
959  : thou == 2 ? fprintf(fp_out, "\t\t\tmaterial USE Material_2999\n")
960  : thou == 3 ? fprintf(fp_out, "\t\t\tmaterial USE Material_3999\n")
961  : thou == 4 ? fprintf(fp_out, "\t\t\tmaterial USE Material_4999\n")
962  : thou == 5 ? fprintf(fp_out, "\t\t\tmaterial USE Material_5999\n")
963  : thou == 6 ? fprintf(fp_out, "\t\t\tmaterial USE Material_6999\n")
964  : thou == 7 ? fprintf(fp_out, "\t\t\tmaterial USE Material_7999\n")
965  : thou == 8 ? fprintf(fp_out, "\t\t\tmaterial USE Material_8999\n")
966  : fprintf(fp_out, "\t\t\tmaterial USE Material_9999\n");
967  }
968  }
969 
970  if (!is_light) {
971  nmg_triangulate_model(m, tol2);
972  fprintf(fp_out, "\t\t\t}\n");
973  fprintf(fp_out, "\t\t\tgeometry IndexedFaceSet {\n");
974  fprintf(fp_out, "\t\t\t\tcoord Coordinate {\n");
975  }
976 
977  /* get list of vertices */
978  nmg_vertex_tabulate(&verts, &m->magic);
979  if (!is_light) {
980  fprintf(fp_out, "\t\t\t\t\tpoint [");
981  } else {
982  VSETALL(ave_pt, 0.0);
983  }
984 
985  for (i = 0; i < BU_PTBL_END(&verts); i++) {
986  struct vertex *v;
987  struct vertex_g *vg;
988  point_t pt_meters;
989 
990  v = (struct vertex *)BU_PTBL_GET(&verts, i);
991  NMG_CK_VERTEX(v);
992  vg = v->vg_p;
993  NMG_CK_VERTEX_G(vg);
994 
995  /* convert to desired units */
996  VSCALE(pt_meters, vg->coord, scale_factor);
997 
998  if (is_light) {
999  VADD2(ave_pt, ave_pt, pt_meters);
1000  }
1001 
1002  if (first) {
1003  if (!is_light) {
1004  fprintf(fp_out, " %10.10e %10.10e %10.10e, # point %d\n", V3ARGS(pt_meters), i);
1005  }
1006  first = 0;
1007  } else if (!is_light) {
1008  fprintf(fp_out, "\t\t\t\t\t%10.10e %10.10e %10.10e, # point %d\n", V3ARGS(pt_meters), i);
1009  }
1010  }
1011 
1012  if (!is_light) {
1013  fprintf(fp_out, "\t\t\t\t\t]\n\t\t\t\t}\n");
1014  } else {
1015  fastf_t one_over_count;
1016  one_over_count = 1.0/(fastf_t)BU_PTBL_END(&verts);
1017  VSCALE(ave_pt, ave_pt, one_over_count);
1018  }
1019 
1020  first = 1;
1021  if (!is_light) {
1022  fprintf(fp_out, "\t\t\t\tcoordIndex [\n");
1023  for (BU_LIST_FOR(reg, nmgregion, &m->r_hd)) {
1024  struct shell *s;
1025 
1026  NMG_CK_REGION(reg);
1027  for (BU_LIST_FOR(s, shell, &reg->s_hd)) {
1028  struct faceuse *fu;
1029 
1030  NMG_CK_SHELL(s);
1031  for (BU_LIST_FOR(fu, faceuse, &s->fu_hd)) {
1032  struct loopuse *lu;
1033 
1034  NMG_CK_FACEUSE(fu);
1035 
1036  if (fu->orientation != OT_SAME) {
1037  continue;
1038  }
1039 
1040  for (BU_LIST_FOR(lu, loopuse, &fu->lu_hd)) {
1041  struct edgeuse *eu;
1042 
1043  NMG_CK_LOOPUSE(lu);
1044  if (BU_LIST_FIRST_MAGIC(&lu->down_hd) != NMG_EDGEUSE_MAGIC) {
1045  continue;
1046  }
1047 
1048  if (!first) {
1049  fprintf(fp_out, ",\n");
1050  } else {
1051  first = 0;
1052  }
1053 
1054  fprintf(fp_out, "\t\t\t\t\t");
1055  for (BU_LIST_FOR(eu, edgeuse, &lu->down_hd)) {
1056  struct vertex *v;
1057 
1058  NMG_CK_EDGEUSE(eu);
1059  v = eu->vu_p->v_p;
1060  NMG_CK_VERTEX(v);
1061  fprintf(fp_out, " %d,", bu_ptbl_locate(&verts, (long *)v));
1062  }
1063  fprintf(fp_out, "-1");
1064  }
1065  }
1066  }
1067  }
1068  fprintf(fp_out, "\n\t\t\t\t]\n\t\t\t\tnormalPerVertex FALSE\n");
1069  fprintf(fp_out, "\t\t\t\tconvex FALSE\n");
1070  fprintf(fp_out, "\t\t\t\tcreaseAngle 0.5\n");
1071  fprintf(fp_out, "\t\t\t}\n\t\t}\n");
1072  } else {
1073  mat.lt_fraction = 0.0;
1074  mat.lt_angle = 180.0;
1075  VSETALL(mat.lt_dir, 0.0);
1076 
1077  if (!ZERO(mat.lt_dir[X]) || !ZERO(mat.lt_dir[Y]) || !ZERO(mat.lt_dir[Z])) {
1078  fprintf(fp_out, "\t\tSpotLight {\n");
1079  fprintf(fp_out, "\t\t\ton \tTRUE\n");
1080  if (mat.lt_fraction > 0.0) {
1081  fprintf(fp_out, "\t\t\tintensity \t%g\n", mat.lt_fraction);
1082  }
1083  fprintf(fp_out, "\t\t\tcolor \t%g %g %g\n", r, g, b);
1084  fprintf(fp_out, "\t\t\tlocation \t%g %g %g\n", V3ARGS(ave_pt));
1085  fprintf(fp_out, "\t\t\tdirection \t%g %g %g\n", V3ARGS(mat.lt_dir));
1086  fprintf(fp_out, "\t\t\tcutOffAngle \t%g }\n", mat.lt_angle);
1087  } else {
1088  fprintf(fp_out, "\t\tPointLight {\n\t\t\ton TRUE\n\t\t\tintensity 1\n\t\t\tcolor %g %g %g\n\t\t\tlocation %g %g %g\n\t\t}\n",
1089  r, g, b, V3ARGS(ave_pt));
1090  }
1091  }
1092 
1093  bu_vls_free(&vls);
1094  bu_vls_free(&shape_name);
1095 }
1096 
1097 
1098 void
1099 bot2vrml(struct plate_mode *pmp, const struct db_full_path *pathp, int region_id)
1100 {
1101  struct bu_vls shape_name = BU_VLS_INIT_ZERO;
1102  char *path_str;
1103  int appearance;
1104  struct rt_bot_internal *bot;
1105  int bot_num;
1106  size_t i;
1107  size_t vert_count=0;
1108 
1109  path_str = db_path_to_string(pathp);
1110 
1111  path_2_vrml_id(&shape_name, path_str);
1112 
1113  fprintf(fp_out, "\t\tDEF %s Shape {\n\t\t\t# Component_ID: %d %s\n",
1114  bu_vls_addr(&shape_name), region_id, path_str);
1115 
1116  bu_free(path_str, "result of db_path_to_string");
1117  bu_vls_free(&shape_name);
1118 
1119  appearance = region_id / 1000;
1120  appearance = appearance * 1000 + 999;
1121  fprintf(fp_out, "\t\t\tappearance Appearance {\n\t\t\tmaterial USE Material_%d\n\t\t\t}\n", appearance);
1122  fprintf(fp_out, "\t\t\tgeometry IndexedFaceSet {\n\t\t\t\tcoord Coordinate {\n\t\t\t\tpoint [\n");
1123 
1124  for (bot_num = 0; bot_num < pmp->num_bots; bot_num++) {
1125  bot = pmp->bots[bot_num];
1126  RT_BOT_CK_MAGIC(bot);
1127  for (i = 0; i < bot->num_vertices; i++) {
1128  point_t pt;
1129 
1130  VSCALE(pt, &bot->vertices[i*3], scale_factor);
1131  fprintf(fp_out, "\t\t\t\t\t%10.10e %10.10e %10.10e, # point %lu\n", V3ARGS(pt), (long unsigned int)vert_count);
1132  vert_count++;
1133  }
1134  }
1135  fprintf(fp_out, "\t\t\t\t\t]\n\t\t\t\t}\n\t\t\t\tcoordIndex [\n");
1136  vert_count = 0;
1137  for (bot_num = 0; bot_num < pmp->num_bots; bot_num++) {
1138  bot = pmp->bots[bot_num];
1139  RT_BOT_CK_MAGIC(bot);
1140  for (i = 0; i < bot->num_faces; i++) {
1141  fprintf(fp_out, "\t\t\t\t\t%lu, %lu, %lu, -1,\n",
1142  (long unsigned int)vert_count+bot->faces[i*3],
1143  (long unsigned int)vert_count+bot->faces[i*3+1],
1144  (long unsigned int)vert_count+bot->faces[i*3+2]);
1145  }
1146  vert_count += bot->num_vertices;
1147  }
1148  fprintf(fp_out, "\t\t\t\t]\n\t\t\t\tnormalPerVertex FALSE\n");
1149  fprintf(fp_out, "\t\t\t\tconvex TRUE\n");
1150  fprintf(fp_out, "\t\t\t\tcreaseAngle 0.5\n");
1151  fprintf(fp_out, "\t\t\t\tsolid FALSE\n");
1152  fprintf(fp_out, "\t\t\t}\n\t\t}\n");
1153 }
1154 
1155 
1156 /*
1157  * Called from db_walk_tree().
1158  * This routine must be prepared to run in parallel.
1159  */
1160 union tree *
1161 do_region_end1(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data)
1162 {
1163  struct plate_mode *pmp = (struct plate_mode *)client_data;
1164  char *name;
1165 
1166  if (pmp->num_bots > 0 && pmp->num_nonbots > 0) {
1167  bu_log("pmp->num_bots = %d pmp->num_nonbots = %d\n", pmp->num_bots, pmp->num_nonbots);
1168  bu_bomb("region was both bot and non-bot objects\n");
1169  }
1170  if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) {
1171  bu_log("\nConverted %d%% so far (%d of %d)\n",
1172  regions_tried > 0 ? (regions_converted * 100) / regions_tried : 0,
1173  regions_converted, regions_tried);
1174  }
1175 
1176  if (pmp->num_bots > 0) {
1177  regions_tried++;
1178  name = db_path_to_string(pathp);
1179  bu_log("Attempting %s\n", name);
1180  bu_free(name, "db_path_to_string");
1181  bot2vrml(pmp, pathp, tsp->ts_regionid);
1182  clean_pmp(pmp);
1183  regions_converted++;
1184  return (union tree *)NULL;
1185  } else {
1186  return nmg_region_end(tsp, pathp, curtree, client_data);
1187  }
1188 }
1189 
1190 /*
1191  * Called from db_walk_tree().
1192  * This routine must be prepared to run in parallel.
1193  *
1194  * Only send bots from structure outside tree to vrml file.
1195  */
1196 union tree *
1197 do_region_end2(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *UNUSED(curtree), void *client_data)
1198 {
1199  struct plate_mode *pmp = (struct plate_mode *)client_data;
1200  char *name;
1201 
1202  if ((pmp->num_bots > 0) && (RT_G_DEBUG&DEBUG_TREEWALK || verbose)) {
1203  bu_log("\nConverted %d%% so far (%d of %d)\n",
1204  regions_tried > 0 ? (regions_converted * 100) / regions_tried : 0,
1205  regions_converted, regions_tried);
1206  }
1207 
1208  if (pmp->num_bots > 0) {
1209  regions_tried++;
1210  name = db_path_to_string(pathp);
1211  bu_log("Attempting %s\n", name);
1212  bu_free(name, "db_path_to_string");
1213  bot2vrml(pmp, pathp, tsp->ts_regionid);
1214  clean_pmp(pmp);
1215  regions_converted++;
1216  }
1217 
1218  return (union tree *)NULL;
1219 }
1220 
1221 
1222 static union tree *
1223 process_boolean(union tree *curtree, struct db_tree_state *tsp, const struct db_full_path *pathp)
1224 {
1225  union tree *ret_tree = TREE_NULL;
1226 
1227  /* Begin bomb protection */
1228  if (!BU_SETJUMP) {
1229  /* try */
1230  ret_tree = nmg_booltree_evaluate(curtree, tsp->ts_tol, &rt_uniresource);
1231  } else {
1232  /* catch */
1233  char *name = db_path_to_string(pathp);
1234 
1235  bu_log("Conversion of %s FAILED due to error!!!\n", name);
1236 
1237  bomb_cnt++;
1238 
1239  /* Sometimes the NMG library adds debugging bits when
1240  * it detects an internal error, before before bombing out.
1241  */
1242  RTG.NMG_debug = NMG_debug; /* restore mode */
1243 
1244  /* Release any intersector 2d tables */
1246 
1247  bu_free(name, "db_path_to_string");
1248  } BU_UNSETJUMP; /* Relinquish the protection */
1249 
1250  return ret_tree;
1251 }
1252 
1253 union tree *
1254 nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *UNUSED(client_data))
1255 {
1256  struct nmgregion *r;
1257  struct bu_list vhead;
1258  union tree *ret_tree;
1259  char *name;
1260 
1261  RT_CK_TESS_TOL(tsp->ts_ttol);
1262  BN_CK_TOL(tsp->ts_tol);
1263  NMG_CK_MODEL(*tsp->ts_m);
1264 
1265  BU_LIST_INIT(&vhead);
1266 
1267  if (RT_G_DEBUG&DEBUG_TREEWALK || verbose) {
1268  bu_log("\nConverted %d%% so far (%d of %d)\n",
1269  regions_tried > 0 ? (regions_converted * 100) / regions_tried : 0,
1270  regions_converted, regions_tried);
1271  }
1272 
1273  if (curtree->tr_op == OP_NOP) {
1274  return curtree;
1275  }
1276 
1277  name = db_path_to_string(pathp);
1278  bu_log("Attempting %s\n", name);
1279 
1280  regions_tried++;
1281  ret_tree = process_boolean(curtree, tsp, pathp);
1282 
1283  if (ret_tree) {
1284  r = ret_tree->tr_d.td_r;
1285  } else {
1286  r = (struct nmgregion *)NULL;
1287  }
1288 
1289  bu_free(name, "db_path_to_string");
1290  if (r != (struct nmgregion *)NULL) {
1291  struct shell *s;
1292  int empty_region = 0;
1293 
1294  /* kill zero length edgeuse and cracks */
1295  s = BU_LIST_FIRST(shell, &r->s_hd);
1296  while (BU_LIST_NOT_HEAD(&s->l, &r->s_hd)) {
1297  struct shell *next_s;
1298  next_s = BU_LIST_PNEXT(shell, &s->l);
1299  (void)nmg_keu_zl(s, tsp->ts_tol); /* kill zero length edgeuse */
1300  if (nmg_kill_cracks(s)) {
1301  /* true when shell is empty */
1302  if (nmg_ks(s)) {
1303  /* true when nmg region is empty */
1304  empty_region = 1;
1305  break;
1306  }
1307  }
1308  s = next_s;
1309  }
1310 
1311  if (!empty_region) {
1312  /* Write the nmgregion to the output file */
1313  nmg_2_vrml(tsp, pathp, r->m_p);
1314  regions_converted++;
1315  } else {
1316  bu_log("WARNING: Nothing left after Boolean evaluation of %s (due to cleanup)\n",
1317  db_path_to_string(pathp));
1318  }
1319 
1320  } else {
1321  bu_log("WARNING: Nothing left after Boolean evaluation of %s (due to error or null result)\n",
1322  db_path_to_string(pathp));
1323  }
1324 
1325  NMG_CK_MODEL(*tsp->ts_m);
1326 
1327  /* Dispose of original tree, so that all associated dynamic
1328  * memory is released now, not at the end of all regions.
1329  * A return of TREE_NULL from this routine signals an error,
1330  * so we need to cons up an OP_NOP node to return.
1331  */
1332  db_free_tree(curtree, &rt_uniresource); /* does a nmg_kr (i.e. kill nmg region) */
1333 
1334  BU_ALLOC(curtree, union tree);
1335  RT_TREE_INIT(curtree);
1336  curtree->tr_op = OP_NOP;
1337  return curtree;
1338 }
1339 
1340 /*
1341  * Local Variables:
1342  * mode: C
1343  * tab-width: 8
1344  * indent-tabs-mode: t
1345  * c-file-style: "stroustrup"
1346  * End:
1347  * ex: shiftwidth=4 tabstop=8
1348  */
char * d_namep
pointer to name string
Definition: raytrace.h:859
struct rt_bot_internal ** bots
Definition: vrml_write.c:56
#define BU_LIST_FOR(p, structure, hp)
Definition: list.h:365
Definition: raytrace.h:800
struct model ** ts_m
ptr to ptr to NMG "model"
Definition: raytrace.h:1072
#define NMG_EDGEUSE_MAGIC
Definition: magic.h:120
void bu_log(const char *,...) _BU_ATTR_PRINTF12
Definition: log.c:176
int rt_db_get_internal(struct rt_db_internal *ip, const struct directory *dp, const struct db_i *dbip, const mat_t mat, struct resource *resp)
Definition: dir.c:76
const struct db_tree_state rt_initial_tree_state
Definition: globals.c:90
struct mater_info ts_mater
material properties
Definition: raytrace.h:1047
Definition: list.h:118
struct nmgregion * td_r
ptr to NMG region
Definition: raytrace.h:1168
#define OP_NOP
Leaf with no effect.
Definition: raytrace.h:1132
union tree * leaf_tess1(struct db_tree_state *tsp, const struct db_full_path *pathp, struct rt_db_internal *ip, void *client_data)
Definition: vrml_write.c:287
double dist
>= 0
Definition: tol.h:73
int shininess
Definition: vrml_write.c:62
if lu s
Definition: nmg_mod.c:3860
Definition: clone.c:90
struct bu_list rtg_vlfree
head of bn_vlist freelist
Definition: raytrace.h:1698
void bu_vls_strcat(struct bu_vls *vp, const char *s)
Definition: vls.c:368
lu
Definition: nmg_mod.c:3855
int nmg_keu_zl(struct shell *s, const struct bn_tol *tol)
Definition: nmg_mk.c:3089
#define VSETALL(a, s)
Definition: color.c:54
void bu_vls_trunc(struct bu_vls *vp, int len)
Definition: vls.c:198
void bot2vrml(struct plate_mode *pmp, const struct db_full_path *pathp, int region_id)
Definition: vrml_write.c:1099
#define ID_BOT
Bag o' triangles.
Definition: raytrace.h:488
double dist_sq
dist * dist
Definition: tol.h:74
struct directory * db_lookup(const struct db_i *, const char *name, int noisy)
Definition: db_lookup.c:153
#define RT_CK_COMB(_p)
Definition: raytrace.h:955
#define BN_TOL_MAGIC
Definition: magic.h:74
#define SMALL_FASTF
Definition: defines.h:342
fastf_t lt_fraction
Definition: vrml_write.c:66
Header file for the BRL-CAD common definitions.
#define DB_FULL_PATH_CUR_DIR(_pp)
Definition: db_fullpath.h:51
Definition: gcv.c:8
char ma_color_valid
non-0 ==> ma_color is non-default
Definition: raytrace.h:524
int tx_n
Definition: vrml_write.c:73
#define ID_COMBINATION
Combination Record.
Definition: raytrace.h:499
double transparency
Definition: vrml_write.c:63
void nmg_2_vrml(struct db_tree_state *tsp, const struct db_full_path *pathp, struct model *m)
Definition: vrml_write.c:773
#define RT_TREE_INIT(_p)
Definition: raytrace.h:1189
NMG_CK_LOOPUSE(lu)
Definition: ptbl.h:62
double rel
rel dist tol
Definition: raytrace.h:181
int nmg_ks(struct shell *s)
Definition: nmg_mk.c:1546
void bu_vls_free(struct bu_vls *vp)
Definition: vls.c:248
int bu_strncmp(const char *string1, const char *string2, size_t n)
Definition: str.c:191
Definition: color.c:49
const struct bu_structparse vrml_mat_parse[]
Definition: vrml_write.c:78
struct resource rt_uniresource
default. Defined in librt/globals.c
Definition: globals.c:41
#define RT_G_DEBUG
Definition: raytrace.h:1718
uint32_t NMG_debug
debug bits for NMG's see nmg.h
Definition: raytrace.h:1699
#define BU_ALLOC(_ptr, _type)
Definition: malloc.h:223
void * bu_calloc(size_t nelem, size_t elsize, const char *str)
Definition: malloc.c:321
#define BU_PTBL_GET(ptbl, i)
Definition: ptbl.h:108
#define LOOKUP_QUIET
Definition: raytrace.h:893
#define DB_LS_TOPS
Definition: raytrace.h:4657
#define bu_strlcpy(dst, src, size)
Definition: str.h:60
#define TREE_NULL
Definition: raytrace.h:1181
#define V3ARGS(a)
Definition: color.c:56
#define RT_CK_TESS_TOL(_p)
Definition: raytrace.h:184
char * strtok(char *s, const char *delim)
void nmg_km(struct model *m)
Definition: nmg_mk.c:1634
void db_free_tree(union tree *tp, struct resource *resp)
Definition: db_tree.c:1296
union tree * nmg_region_end(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data)
Definition: vrml_write.c:1254
union tree * nmg_booltree_leaf_tess(struct db_tree_state *tsp, const struct db_full_path *pathp, struct rt_db_internal *ip, void *client_data)
Definition: nmg_bool.c:1175
char * options
Definition: gqa.c:56
char tx_file[TXT_NAME_SIZE]
Definition: vrml_write.c:71
#define PL_O(_m)
Definition: vrml_write.c:76
struct bu_vls shader
Definition: raytrace.h:950
char * ma_shader
shader name & parms
Definition: raytrace.h:527
vect_t lt_dir
Definition: vrml_write.c:67
union tree * leaf_tess2(struct db_tree_state *tsp, const struct db_full_path *pathp, struct rt_db_internal *ip, void *client_data)
Definition: vrml_write.c:321
#define BU_LIST_PNEXT(structure, p)
Definition: list.h:422
void * bu_realloc(void *ptr, size_t siz, const char *str)
int num_nonbots
Definition: vrml_write.c:54
#define UNUSED(parameter)
Definition: common.h:239
void nmg_triangulate_model(struct model *m, const struct bn_tol *tol)
Definition: nmg_tri.c:3818
goto out
Definition: nmg_mod.c:3846
Support for uniform tolerances.
Definition: tol.h:71
#define BN_CK_TOL(_p)
Definition: tol.h:82
#define BU_LIST_FIRST_MAGIC(hp)
Definition: list.h:416
char * db_path_to_string(const struct db_full_path *pp)
Definition: db_fullpath.c:191
char * bu_vls_addr(const struct bu_vls *vp)
Definition: vls.c:111
struct tree::tree_nmgregion tr_d
struct bu_bitv * bu_bitv_dup(const struct bu_bitv *bv)
union tree * do_region_end1(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data)
Definition: vrml_write.c:1161
fastf_t lt_angle
Definition: vrml_write.c:68
#define BU_STRUCTPARSE_FUNC_NULL
Definition: parse.h:153
size_t db_ls(const struct db_i *dbip, int flags, const char *pattern, struct directory ***dpv)
Definition: ls.c:58
int bu_ptbl_locate(const struct bu_ptbl *b, const long *p)
float ma_color[3]
explicit color: 0..1
Definition: raytrace.h:522
#define RT_CK_FULL_PATH(_p)
Definition: db_fullpath.h:59
struct model * nmg_mm(void)
Definition: nmg_mk.c:235
char ** db_dpv_to_argv(struct directory **dpv)
Definition: ls.c:123
double perp
nearly 0
Definition: tol.h:75
uint32_t magic
Definition: raytrace.h:179
union tree * do_region_end2(struct db_tree_state *tsp, const struct db_full_path *pathp, union tree *curtree, void *client_data)
Definition: vrml_write.c:1197
#define ZERO(val)
Definition: units.c:38
#define BU_LIST_INIT(_hp)
Definition: list.h:148
void nmg_isect2d_final_cleanup(void)
Definition: nmg_inter.c:647
void * idb_ptr
Definition: raytrace.h:195
int nmg_kill_cracks(struct shell *s)
Definition: nmg_misc.c:8187
#define RT_DIR_COMB
combination
Definition: raytrace.h:884
uint32_t magic
Definition: tol.h:72
#define TXT_NAME_SIZE
Definition: vrml_write.c:50
#define BU_PTBL_END(ptbl)
Definition: ptbl.h:106
const struct rt_tess_tol * ts_ttol
Tessellation tolerance.
Definition: raytrace.h:1070
#define TXT_BUF_LEN
Definition: vrml_write.c:49
int bu_struct_parse(const struct bu_vls *in_vls, const struct bu_structparse *desc, const char *base, void *data)
Definition: parse.c:878
double abs
absolute dist tol
Definition: raytrace.h:180
#define BU_UNSETJUMP
Definition: parallel.h:193
void bu_vls_printf(struct bu_vls *vls, const char *fmt,...) _BU_ATTR_PRINTF23
Definition: vls.c:694
#define RT_DIR_NULL
Definition: raytrace.h:875
const struct gcv_plugin_info gcv_plugin_conv_vrml_write
Definition: vrml_write.c:769
void bu_bitv_free(struct bu_bitv *bv)
Definition: bitv.c:113
int num_bots
Definition: vrml_write.c:53
int array_size
Definition: vrml_write.c:55
Definition: color.c:51
void bu_vls_strcpy(struct bu_vls *vp, const char *s)
Definition: vls.c:310
double norm
normal tol
Definition: raytrace.h:182
union tree * nmg_booltree_evaluate(register union tree *tp, const struct bn_tol *tol, struct resource *resp)
Definition: nmg_bool.c:1307
double nmg_eue_dist
Definition: globals.c:49
void bu_free(void *ptr, const char *str)
Definition: malloc.c:328
char shader[TXT_NAME_SIZE]
Definition: vrml_write.c:61
#define RT_TESS_TOL_MAGIC
Definition: magic.h:170
int ts_regionid
GIFT compat region ID code.
Definition: raytrace.h:1043
ustring shader
#define BU_SETJUMP
Definition: parallel.h:192
NMG_CK_SHELL(s)
int tx_w
Definition: vrml_write.c:72
#define BU_VLS_INIT_ZERO
Definition: vls.h:84
int db_walk_tree(struct db_i *dbip, int argc, const char **argv, int ncpu, const struct db_tree_state *init_state, int(*reg_start_func)(struct db_tree_state *, const struct db_full_path *, const struct rt_comb_internal *, void *client_data), union tree *(*reg_end_func)(struct db_tree_state *, const struct db_full_path *, union tree *, void *client_data), union tree *(*leaf_func)(struct db_tree_state *, const struct db_full_path *, struct rt_db_internal *, void *client_data), void *client_data)
#define DEBUG_TREEWALK
22 Database tree traversal
Definition: raytrace.h:107
struct rt_bot_internal * dup_bot(struct rt_bot_internal *bot_in)
Definition: vrml_write.c:150
HIDDEN void verbose(struct human_data_t *dude)
Definition: human.c:2008
int d_flags
flags
Definition: raytrace.h:869
Definition: vls.h:56
void bu_setlinebuf(FILE *fp)
Definition: linebuf.c:44
void bu_bomb(const char *str) _BU_ATTR_NORETURN
Definition: bomb.c:91
void db_update_nref(struct db_i *dbip, struct resource *resp)
Definition: db_match.c:75
const struct bn_tol * ts_tol
Math tolerance.
Definition: raytrace.h:1071
double fastf_t
Definition: defines.h:300
void bu_vls_putc(struct bu_vls *vp, int c)
Definition: vls.c:666
#define BU_LIST_NOT_HEAD(p, hp)
Definition: list.h:324
double para
nearly 1
Definition: tol.h:76
void rt_db_free_internal(struct rt_db_internal *ip)
Definition: dir.c:216
Definition: color.c:50
#define BU_LIST_FIRST(structure, hp)
Definition: list.h:312
void nmg_vertex_tabulate(struct bu_ptbl *tab, const uint32_t *magic_p)
Definition: nmg_info.c:1985
#define BU_STR_EQUAL(s1, s2)
Definition: str.h:126
struct rt_g RTG
Definition: globals.c:39