Exemple #1
0
int BRLFile::AddModel(char const *name)
{
    if(dbip==DBI_NULL)
        return 1;
    struct directory *dp=db_lookup(dbip, name, 1);
    if(dp == NULL)
        return 1;

    rt_init_resource( &rt_uniresource, 0, NULL );
    db_functree(dbip, dp, CsgCombine, CsgLeaf, &rt_uniresource, this);

    while(construction.size()>0) {
        Add(construction.front());
        construction.pop_front();
    }
    return 0;
}
/*
 * The only reason for this to be broken out is that
 * 2 separate locations in db_functree() call it.
 */
void
db_functree_subtree(struct db_i *dbip,
		    union tree *tp,
		    void (*comb_func) (struct db_i *, struct directory *, void *),
		    void (*leaf_func) (struct db_i *, struct directory *, void *),
		    struct resource *resp,
		    void *client_data)
{
    struct directory *dp;

    if (!tp)
	return;

    RT_CHECK_DBI(dbip);
    RT_CK_TREE(tp);
    if (resp) {
	RT_CK_RESOURCE(resp);
    }

    switch (tp->tr_op) {

	case OP_DB_LEAF:
	    if ((dp=db_lookup(dbip, tp->tr_l.tl_name, LOOKUP_NOISY)) == RT_DIR_NULL)
		return;
	    db_functree(dbip, dp, comb_func, leaf_func, resp, client_data);
	    break;

	case OP_UNION:
	case OP_INTERSECT:
	case OP_SUBTRACT:
	case OP_XOR:
	    db_functree_subtree(dbip, tp->tr_b.tb_left, comb_func, leaf_func, resp, client_data);
	    db_functree_subtree(dbip, tp->tr_b.tb_right, comb_func, leaf_func, resp, client_data);
	    break;
	default:
	    bu_log("db_functree_subtree: unrecognized operator %d\n", tp->tr_op);
	    bu_bomb("db_functree_subtree: unrecognized operator\n");
    }
}
Exemple #3
0
int
ged_keep(struct ged *gedp, int argc, const char *argv[])
{
    int i;
    struct keep_node_data knd;
    struct rt_wdb *keepfp;
    struct directory *dp;
    struct bu_vls title = BU_VLS_INIT_ZERO;
    struct db_i *new_dbip;
    const char *cmd = argv[0];
    static const char *usage = "[-R] file object(s)";

    int c;
    int flag_R = 0;

    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);

    /* initialize result */
    bu_vls_trunc(gedp->ged_result_str, 0);

    /* must be wanting help */
    if (argc == 1) {
	bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd, usage);
	return GED_HELP;
    }

    /* check for options */
    bu_optind = 1;
    while ((c = bu_getopt(argc, (char * const *)argv, "R")) != -1) {
	switch (c) {
	    case 'R':
		/* not recursively */
		flag_R = 1;
		break;
	    default:
		bu_vls_printf(gedp->ged_result_str, "Unrecognized option - %c", c);
		return GED_ERROR;
	}
    }
    /* skip options processed plus command name */
    argc -= bu_optind;
    argv += bu_optind;

    if (argc < 2) {
	bu_vls_printf(gedp->ged_result_str, "ERROR: missing file or object names\n");
	bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", cmd, usage);
	return GED_ERROR;
    }

    /* First, clear any existing counts */
    for (i = 0; i < RT_DBNHASH; i++) {
	for (dp = gedp->ged_wdbp->dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw)
	    dp->d_nref = 0;
    }

    /* Alert user if named file already exists */

    new_dbip = db_open(argv[0], DB_OPEN_READWRITE);

    if (new_dbip != DBI_NULL) {
	if (db_version(new_dbip) != db_version(gedp->ged_wdbp->dbip)) {
	    bu_vls_printf(gedp->ged_result_str, "%s: File format mismatch between '%s' and '%s'\n",
			  cmd, argv[0], gedp->ged_wdbp->dbip->dbi_filename);
	    return GED_ERROR;
	}

	if ((keepfp = wdb_dbopen(new_dbip, RT_WDB_TYPE_DB_DISK)) == NULL) {
	    bu_vls_printf(gedp->ged_result_str, "%s:  Error opening '%s'\n", cmd, argv[0]);
	    return GED_ERROR;
	} else {
	    bu_vls_printf(gedp->ged_result_str, "%s:  Appending to '%s'\n", cmd, argv[0]);

	    /* --- Scan geometry database and build in-memory directory --- */
	    db_dirbuild(new_dbip);
	}
    } else {
	/* Create a new database */
	keepfp = wdb_fopen_v(argv[0], db_version(gedp->ged_wdbp->dbip));

	if (keepfp == NULL) {
	    perror(argv[0]);
	    return GED_ERROR;
	}
    }

    knd.wdbp = keepfp;
    knd.gedp = gedp;

    /* ident record */
    if (bu_strncmp(gedp->ged_wdbp->dbip->dbi_title, "Parts of: ", 10) != 0) {
	bu_vls_strcat(&title, "Parts of: ");
    }
    bu_vls_strcat(&title, gedp->ged_wdbp->dbip->dbi_title);

    if (db_update_ident(keepfp->dbip, bu_vls_addr(&title), gedp->ged_wdbp->dbip->dbi_local2base) < 0) {
	perror("fwrite");
	bu_vls_printf(gedp->ged_result_str, "db_update_ident() failed\n");
	wdb_close(keepfp);
	bu_vls_free(&title);
	return GED_ERROR;
    }
    bu_vls_free(&title);

    for (i = 1; i < argc; i++) {
	if ((dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) == RT_DIR_NULL)
	    continue;

	if (!flag_R) {
	    /* recursively keep objects */
	    db_functree(gedp->ged_wdbp->dbip, dp, node_write, node_write, &rt_uniresource, (void *)&knd);
	} else {
	    /* keep just this object */
	    node_write(gedp->ged_wdbp->dbip, dp, (void *)&knd);
	}
    }

    wdb_close(keepfp);
    return GED_OK;
}
int
ged_killtree(struct ged *gedp, int argc, const char *argv[])
{
    struct directory *dp;
    int i;
    int c;
    struct killtree_data gktd;
    static const char *usage = "[-a|-f|-n] object(s)";

    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
    GED_CHECK_READ_ONLY(gedp, GED_ERROR);
    GED_CHECK_ARGC_GT_0(gedp, argc, GED_ERROR);

    /* initialize result */
    bu_vls_trunc(gedp->ged_result_str, 0);

    /* must be wanting help */
    if (argc == 1) {
	bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
	return GED_HELP;
    }

    gktd.gedp = gedp;
    gktd.killrefs = 0;
    gktd.print = 0;
    gktd.force = 0;
    gktd.ac = 1;
    gktd.top = NULL;

    gktd.av = (char **)bu_calloc(1, sizeof(char *) * AV_STEP, "alloc av");
    gktd.av_capacity = AV_STEP;
    BU_ASSERT(gktd.ac + argc + 2 < AV_STEP); /* potential -n opts */
    gktd.av[0] = "killrefs";
    gktd.av[1] = (char *)0;

    bu_optind = 1;
    while ((c = bu_getopt(argc, (char * const *)argv, "afn")) != -1) {
	switch (c) {
	    case 'a':
		gktd.killrefs = 1;
		break;
	    case 'n':
		gktd.print = 1;
		gktd.av[gktd.ac++] = bu_strdup("-n");
		gktd.av[gktd.ac] = (char *)0;
		break;
	    case 'f':
		gktd.force = 1;
		break;
	    default:
		bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
		bu_free(gktd.av, "free av (error)");
		gktd.av = NULL;
		return GED_ERROR;
	}
    }

    argc -= (bu_optind - 1);
    argv += (bu_optind - 1);

    /* Objects that would be killed are in the first sublist */
    if (gktd.print)
	bu_vls_printf(gedp->ged_result_str, "{");

    for (i = 1; i < argc; i++) {
	if ((dp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) == RT_DIR_NULL)
	    continue;

	/* ignore phony objects */
	if (dp->d_addr == RT_DIR_PHONY_ADDR)
	    continue;

	/* stash the what's killed so we can find refs elsewhere */
	gktd.top = argv[i];

	db_functree(gedp->ged_wdbp->dbip, dp,
		    killtree_callback, killtree_callback,
		    gedp->ged_wdbp->wdb_resp, (void *)&gktd);
    }

    /* Close the sublist of would-be killed objects. Also open the
     * sublist of objects that reference the would-be killed objects.
     */
    if (gktd.print)
	bu_vls_printf(gedp->ged_result_str, "} {");

    if (gktd.killrefs && gktd.ac > 1) {
	gedp->ged_internal_call = 1;
	(void)ged_killrefs(gedp, gktd.ac, (const char **)gktd.av);
	gedp->ged_internal_call = 0;

	for (i = 1; i < gktd.ac; i++) {
	    if (!gktd.print)
		bu_vls_printf(gedp->ged_result_str, "Freeing %s\n", gktd.av[i]);
	    bu_free((void *)gktd.av[i], "killtree_data");
	    gktd.av[i] = NULL;
	}
    }

    if (gktd.print)
	bu_vls_printf(gedp->ged_result_str, "}");

    bu_free(gktd.av, "free av");
    gktd.av = NULL;

    return GED_OK;
}
Exemple #5
0
/**
 * recursively copy a tree of geometry
 */
static struct directory *
copy_tree(struct db_i *_dbip, struct directory *dp, struct resource *resp, struct clone_state *state)
{
    size_t i;
    union record *rp = (union record *)NULL;
    struct directory *mdp = (struct directory *)NULL;
    struct directory *copy = (struct directory *)NULL;

    struct bu_vls *copyname = NULL;
    struct bu_vls *nextname = NULL;

    /* get the name of what the object "should" get cloned to */
    copyname = get_name(_dbip, dp, state, 0);

    /* copy the object */
    if (dp->d_flags & RT_DIR_COMB) {

	if (db_version(_dbip) < 5) {
	    /* A v4 method of peeking into a combination */

	    int errors = 0;

	    /* get an in-memory record of this object */
	    if ((rp = db_getmrec(_dbip, dp)) == (union record *)0) {
		TCL_READ_ERR;
		goto done_copy_tree;
	    }
	    /*
	     * if it is a combination/region, copy the objects that
	     * make up the object.
	     */
	    for (i = 1; i < dp->d_len; i++) {
		if ((mdp = db_lookup(_dbip, rp[i].M.m_instname, LOOKUP_NOISY)) == RT_DIR_NULL) {
		    errors++;
		    bu_log("WARNING: failed to locate \"%s\"\n", rp[i].M.m_instname);
		    continue;
		}
		copy = copy_tree(_dbip, mdp, resp, state);
		if (!copy) {
		    errors++;
		    bu_log("WARNING: unable to fully clone \"%s\"\n", rp[i].M.m_instname);
		}
	    }

	    if (errors) {
		bu_log("WARNING: some elements of \"%s\" could not be cloned\n", dp->d_namep);
	    }

	    /* copy this combination itself */
	    copy_comb(_dbip, dp, (genptr_t)state);
	} else
	    /* A v5 method of peeking into a combination */
	    db_functree(_dbip, dp, copy_comb, copy_solid, resp, (genptr_t)state);
    } else if (dp->d_flags & RT_DIR_SOLID)
	/* leaf node -- make a copy the object */
	copy_solid(_dbip, dp, (genptr_t)state);
    else {
	Tcl_AppendResult(state->interp, "clone:  ", dp->d_namep, " is neither a combination or a primitive?\n", (char *)NULL);
	goto done_copy_tree;
    }

    nextname = get_name(_dbip, dp, state, 0);
    if (bu_vls_strcmp(copyname, nextname) == 0)
	bu_log("ERROR: unable to successfully clone \"%s\" to \"%s\"\n", dp->d_namep, bu_vls_addr(copyname));
    else
	copy = db_lookup(_dbip, bu_vls_addr(copyname), LOOKUP_QUIET);

 done_copy_tree:
    if (rp)
	bu_free((char *)rp, "copy_tree record[]");
    if (copyname)
	bu_free((char *)copyname, "free get_name() copyname");
    if (nextname)
	bu_free((char *)nextname, "free get_name() copyname");

    return copy;
}
Exemple #6
0
int
main(int argc, char *argv[])
{
    size_t i;
    int ret;
    int c;
    double percent;
    char copy_buffer[CP_BUF_SIZE] = {0};
    struct directory *dp;

    bu_setprogname(argv[0]);
    bu_setlinebuf(stderr);

    bu_log("%s", brlcad_ident("BRL-CAD to IGES Translator"));
    bu_log("Please direct bug reports to <*****@*****.**>\n\n");

    tree_state = rt_initial_tree_state;	/* struct copy */
    tree_state.ts_tol = &tol;
    tree_state.ts_ttol = &ttol;
    tree_state.ts_m = &the_model;

    ttol.magic = RT_TESS_TOL_MAGIC;
    /* Defaults, updated by command line options. */
    ttol.abs = 0.0;
    ttol.rel = 0.01;
    ttol.norm = 0.0;

    /* FIXME: These need to be improved */
    tol.magic = BN_TOL_MAGIC;
    tol.dist = 0.0005;
    tol.dist_sq = tol.dist * tol.dist;
    tol.perp = 1e-6;
    tol.para = 1 - tol.perp;

    the_model = nmg_mm();
    BU_LIST_INIT(&RTG.rtg_vlfree);	/* for vlist macros */

    rt_init_resource(&rt_uniresource, 0, NULL);

    prog_name = argv[0];

    /* Get command line arguments. */
    while ((c = bu_getopt(argc, argv, "ftsmd:a:n:o:p:r:vx:P:X:")) != -1) {
	switch (c) {
	    case 'f':		/* Select facetized output */
		mode = FACET_MODE;
		multi_file = 0;
		break;
	    case 't':
		mode = TRIMMED_SURF_MODE;
		multi_file = 0;
		break;
	    case 'm':		/* multi-file mode */
		multi_file = 1;
		mode = TRIMMED_SURF_MODE;
		break;
	    case 's':		/* Select NURB output */
		do_nurbs = 1;
		break;
	    case 'v':
		verbose++;
		break;
	    case 'a':		/* Absolute tolerance. */
		ttol.abs = atof(bu_optarg);
		break;
	    case 'r':		/* Relative tolerance. */
		ttol.rel = atof(bu_optarg);
		break;
	    case 'n':		/* Surface normal tolerance. */
		ttol.norm = atof(bu_optarg);
		break;
	    case 'd':		/* distance tolerance */
		tol.dist = atof(bu_optarg);
		tol.dist_sq = tol.dist * tol.dist;
		break;
	    case 'x':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.debug);
		break;
	    case 'X':
		sscanf(bu_optarg, "%x", (unsigned int *)&RTG.NMG_debug);
		NMG_debug = RTG.NMG_debug;
		break;
	    case 'o':		/* Output file name. */
		output_file = bu_optarg;
		break;
	    case 'P':
		ncpu = atoi(bu_optarg);
		break;
	    default:
		usage(argv[0]);
		break;
	}
    }

    if (bu_optind+1 >= argc) {
	usage(argv[0]);
    }

    /* Open BRL-CAD database */
    argc -= bu_optind;
    argv += bu_optind;
    db_name = argv[0];
    if ((DBIP = db_open(db_name, DB_OPEN_READONLY)) == DBI_NULL) {
	perror("g-iges");
	bu_exit(1, "ERROR: unable to open geometry database file (%s)\n", db_name);
    }

    /* Scan the database */
    if (db_dirbuild(DBIP)) {
	bu_exit(1, "db_dirbuild failed\n");
    }

    if (!multi_file) {
	/* let the IGES routines know the selected tolerances and the database pointer */
	iges_init(&tol, &ttol, verbose, DBIP);

	/* Open the output file */
	if (output_file == NULL)
	    fp_dir = stdout;
	else {
	    if ((fp_dir = fopen(output_file, "wb")) == NULL) {
		perror(output_file);
		bu_exit(1, "Cannot open output file: %s\n", output_file);
	    }
	}

	/* Open the temporary file for the parameter section */
	if ((fp_param = bu_temp_file(NULL, 0)) == NULL) {
	    perror("g-iges");
	    bu_exit(1, "Cannot open temporary file\n");
	}

	/* Write start and global sections of the IGES file */
	w_start_global(fp_dir, fp_param, argv[0], prog_name, output_file, __DATE__, brlcad_version());
    } else {
	if (!bu_file_directory(output_file)) {
	    bu_exit(1, "-o option must provide a directory, %s is not a directory\n", output_file);
	}
    }

    /* Count object references */
/* for (i = 1; i < argc; i++) {
   dp = db_lookup(DBIP, argv[i], 1);
   db_functree(DBIP, dp, count_refs, 0, NULL);
   }	*/

    /* tree tops must have independent status, so we need to remember them */
    independent = (argv+1);
    no_of_indeps = (size_t)argc-1;

    if (mode == FACET_MODE) {
	/* Walk indicated tree(s).  Each region will be output
	 * as a single manifold solid BREP object */

	ret = db_walk_tree(DBIP, argc-1, (const char **)(argv+1),
			   ncpu,
			   &tree_state,
			   0,			/* take all regions */
			   do_nmg_region_end,
			   nmg_booltree_leaf_tess,
			   (void *)NULL);	/* in librt/nmg_bool.c */

	if (ret)
	    bu_exit(1, "g-iges: Could not facetize anything!");

	if (!multi_file) {
	    /* Now walk the same trees again, but only output groups */
	    for (i = 1; i < (size_t)argc; i++) {
		char *ptr;

		ptr = strrchr(argv[i], '/');
		if (ptr != NULL) {
		    ptr++;
		} else {
		    ptr = argv[i];
		}
		dp = db_lookup(DBIP, ptr, 1);
		if (!dp) {
		    bu_log("WARNING: Unable to locate %s in %s\n, skipping\n", ptr, db_name);
		    continue;
		}
		db_functree(DBIP, dp, csg_comb_func, 0, &rt_uniresource, NULL);
	    }
	}
    } else if (mode == CSG_MODE) {
	/* Walk indicated tree(s). Each combination and solid will be output
	 * as a CSG object, unless there is no IGES equivalent (then the
	 * solid will be tessellated and output as a BREP object) */

	for (i = 1; i < (size_t)argc; i++) {
	    dp = db_lookup(DBIP, argv[i], 1);
	    if (!dp) {
		bu_log("WARNING: Unable to locate %s in %s\n, skipping\n", argv[i], db_name);
		continue;
	    }
	    db_functree(DBIP, dp, csg_comb_func, csg_leaf_func, &rt_uniresource, NULL);
	}
    } else if (mode == TRIMMED_SURF_MODE) {
	/* Walk the indicated tree(s). Each region is output as a collection
	 * of trimmed NURBS */

	ret = db_walk_tree(DBIP, argc-1, (const char **)(argv+1),
			   ncpu,
			   &tree_state,
			   0,			/* take all regions */
			   do_nmg_region_end,
			   nmg_booltree_leaf_tess,
			   (void *)NULL);	/* in librt/nmg_bool.c */

	if (ret)
	    bu_exit(1, "g-iges: Could not facetize anything!");

    }

    if (!multi_file) {
	/* Copy the parameter section from the temporary file to the output file */
	if ((bu_fseek(fp_param, 0, 0))) {
	    perror("g-iges");
	    bu_exit(1, "Cannot seek to start of temporary file\n");
	}

	while ((i = fread(copy_buffer, 1, CP_BUF_SIZE, fp_param)))
	    if (fwrite(copy_buffer, 1, i, fp_dir) != i) {
		perror("g-iges");
		bu_exit(1, "Error in copying parameter data to %s\n", output_file);
	    }

	/* Write the terminate section */
	w_terminate(fp_dir);
    }

    /* Print some statistics */
    Print_stats(stdout);

    /* report on the success rate for facetizing regions */
    if (mode == FACET_MODE || mode == TRIMMED_SURF_MODE) {
	percent = 0;
	if (regions_tried>0) percent = ((double)regions_done * 100) / regions_tried;
	bu_log("Tried %d regions, %d converted to nmg's successfully.  %g%%\n",
	       regions_tried, regions_done, percent);
    }

    /* re-iterate warnings */
    if (scale_error || solid_error || comb_error)
	bu_log("WARNING: the IGES file produced has errors:\n");
    if (scale_error)
	bu_log("\t%d scaled objects found, written to IGES file without being scaled\n", scale_error);
    if (solid_error)
	bu_log("\t%d solids were not converted to IGES format\n", solid_error);
    if (comb_error)
	bu_log("\t%d combinations were not converted to IGES format\n", comb_error);

    return 0;
}
void
db_functree(struct db_i *dbip,
	    struct directory *dp,
	    void (*comb_func) (struct db_i *, struct directory *, void *),
	    void (*leaf_func) (struct db_i *, struct directory *, void *),
	    struct resource *resp,
	    void *client_data)
{
    register size_t i;

    RT_CK_DBI(dbip);
    if (resp) {
	RT_CK_RESOURCE(resp);
    }

    if ((!dp) || (!comb_func && !leaf_func)) {
	return; /* nothing to do */
    }

    if (RT_G_DEBUG&DEBUG_DB) {
	bu_log("db_functree(%s) %p, %p, comb=%lx, leaf=%lx, client_data=%p\n",
	       dp->d_namep, (void *)dbip, (void *)dp,
	       (long unsigned int)comb_func, (long unsigned int)leaf_func,
	       client_data);
    }

    if (dp->d_flags & RT_DIR_COMB) {
	if (db_version(dbip) < 5) {
	    register union record *rp;
	    register struct directory *mdp;
	    /*
	     * Load the combination into local record buffer
	     * This is in external v4 format.
	     */
	    if ((rp = db_getmrec(dbip, dp)) == (union record *)0)
		return;

	    /* recurse */
	    for (i=1; i < dp->d_len; i++) {
		if ((mdp = db_lookup(dbip, rp[i].M.m_instname, LOOKUP_NOISY)) == RT_DIR_NULL)
		    continue;
		db_functree(dbip, mdp, comb_func, leaf_func, resp, client_data);
	    }
	    bu_free((char *)rp, "db_functree record[]");
	} else {
	    struct rt_db_internal in;
	    struct rt_comb_internal *comb;

	    if (rt_db_get_internal5(&in, dp, dbip, NULL, resp) < 0)
		return;

	    comb = (struct rt_comb_internal *)in.idb_ptr;
	    db_functree_subtree(dbip, comb->tree, comb_func, leaf_func, resp, client_data);
	    rt_db_free_internal(&in);
	}

	/* Finally, the combination itself */
	if (comb_func)
	    comb_func(dbip, dp, client_data);

    } else if (dp->d_flags & RT_DIR_SOLID || dp->d_major_type & DB5_MAJORTYPE_BINARY_MASK) {
	if (leaf_func)
	    leaf_func(dbip, dp, client_data);
    } else {
	bu_log("db_functree:  %s is neither COMB nor SOLID?\n",
	       dp->d_namep);
    }
}
int main(int argc, char *argv[])
{
    int c;
    struct directory* dp;
    struct db_i *dbip;

    /* setup BRL-CAD environment */
    bu_setprogname(argv[0]);
    bu_setlinebuf(stderr);

    /* process command line arguments */
    while ((c = bu_getopt(argc, argv, "vo:ys:fh?")) != -1) {
	switch (c) {
	    case 'v':
		verbose++;
		break;

	    case 'o':
		out_file = bu_optarg;
		break;

	    case 'y':
		yup++;
		break;

	    case 's':
		sscanf(bu_optarg, "%f", &scale);
		break;

	    case 'f':
		flip_normals++;
		break;

	    default:
		print_usage(argv[0]);
	}
    }
    /* param check */
    if (bu_optind+1 >= argc)
	print_usage(argv[0]);

    /* get database filename and object */
    db_file = argv[bu_optind++];
    object = argv[bu_optind];

    /* open BRL-CAD database */
    if ((dbip = db_open(db_file, DB_OPEN_READONLY)) == DBI_NULL) {
	perror(argv[0]);
	bu_exit(1, "Cannot open geometry database file %s\n", db_file);
    }
    if (db_dirbuild(dbip))
	bu_exit(1, "db_dirbuild() failed!\n");

    if (verbose)
	fprintf(stderr, ">> opened db '%s'\n", dbip->dbi_title);

    /* setup output stream */
    if (out_file == NULL) {
	fp_out = stdout;
	setmode(fileno(fp_out), O_BINARY);
    } else {
	if ((fp_out = fopen(out_file, "wb")) == NULL) {
	    bu_log("Cannot open %s\n", out_file);
	    perror(argv[0]);
	    return 2;
	}
    }

    /* find requested object */
    db_update_nref(dbip, &rt_uniresource);

    dp = db_lookup(dbip, object, 0);
    if (dp == RT_DIR_NULL)
	bu_exit(1, "Object %s not found in database!\n", object);

    /* generate mesh list */
    db_functree(dbip, dp, NULL, mesh_tracker, &rt_uniresource, NULL);
    if (verbose)
	fprintf(stderr, ">> mesh count: %d\n", mesh_count);

    /* write out header */
    write_header(dbip);

    /* write out meshes */
    write_mesh_data();

    /* finish */
    dealloc_mesh_list();
    db_close(dbip);
    return 0;
}