Revision: 76402
          http://sourceforge.net/p/brlcad/code/76402
Author:   starseeker
Date:     2020-07-22 01:27:01 +0000 (Wed, 22 Jul 2020)
Log Message:
-----------
Get as far as archer launching, although the tree and display are not working.

Modified Paths:
--------------
    brlcad/branches/gedplugins/src/libged/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/analyze/analyze.c
    brlcad/branches/gedplugins/src/libged/bot/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/bot/ged_bot.h
    brlcad/branches/gedplugins/src/libged/brep/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/check/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/comb/comb.c
    brlcad/branches/gedplugins/src/libged/draw/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/draw/draw.c
    brlcad/branches/gedplugins/src/libged/editit/editit.c
    brlcad/branches/gedplugins/src/libged/ged.c
    brlcad/branches/gedplugins/src/libged/ged_util.c
    brlcad/branches/gedplugins/src/libged/how/how.c
    brlcad/branches/gedplugins/src/libged/list/list.c
    brlcad/branches/gedplugins/src/libged/pnts_util.h
    brlcad/branches/gedplugins/src/libged/rt/rt.c
    brlcad/branches/gedplugins/src/libged/rtcheck/rtcheck.c
    brlcad/branches/gedplugins/src/libged/select/select.c
    brlcad/branches/gedplugins/src/libged/tops/tops.c
    brlcad/branches/gedplugins/src/libged/view/CMakeLists.txt
    brlcad/branches/gedplugins/src/libged/view/center.cpp

Added Paths:
-----------
    brlcad/branches/gedplugins/src/libged/draw/loadview.c
    brlcad/branches/gedplugins/src/libged/draw/preview.c

Removed Paths:
-------------
    brlcad/branches/gedplugins/src/libged/loadview/
    brlcad/branches/gedplugins/src/libged/preview/

Modified: brlcad/branches/gedplugins/src/libged/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/CMakeLists.txt        2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/CMakeLists.txt        2020-07-22 
01:27:01 UTC (rev 76402)
@@ -64,6 +64,7 @@
   get_solid_kp.c
   inside.c
   path.c
+  pnts_util.c
   polyclip.cpp
   qray.c
   rotate_about.c
@@ -270,7 +271,6 @@
   png/png.c
   png2fb/png2fb.c
   pnts/pnts.cpp
-  pnts_util.c
   prcolor/prcolor.c
   prefix/prefix.c
   preview/preview.c
@@ -562,7 +562,6 @@
 add_subdirectory(lc)
 add_subdirectory(lint)
 add_subdirectory(list)
-add_subdirectory(loadview)
 add_subdirectory(lod)
 add_subdirectory(log)
 add_subdirectory(lookat)
@@ -603,7 +602,6 @@
 add_subdirectory(pnts)
 add_subdirectory(prcolor)
 add_subdirectory(prefix)
-add_subdirectory(preview)
 add_subdirectory(process)
 add_subdirectory(protate)
 add_subdirectory(ps)

Modified: brlcad/branches/gedplugins/src/libged/analyze/analyze.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/analyze/analyze.c     2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/analyze/analyze.c     2020-07-22 
01:27:01 UTC (rev 76402)
@@ -29,8 +29,6 @@
 #include <string.h>
 #include <assert.h>
 
-
-
 #include "vmath.h"
 #include "bn.h"
 #include "bg/polygon.h"

Modified: brlcad/branches/gedplugins/src/libged/bot/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/bot/CMakeLists.txt    2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/bot/CMakeLists.txt    2020-07-22 
01:27:01 UTC (rev 76402)
@@ -6,11 +6,30 @@
   ${GED_INCLUDE_DIRS}
   )
 
+set(BOT_SRCS
+       bot_condense.c
+       bot.cpp
+       bot_decimate.c
+       bot_dump.c
+       bot_face_fuse.c
+       bot_face_sort.c
+       bot_flip.c
+       bot_fuse.c
+       bot_merge.c
+       bot_smooth.c
+       bot_split.c
+       bot_sync.c
+       bot_vertex_fuse.c
+       check.cpp
+       extrude.cpp
+       remesh.cpp
+       )
+
 add_definitions(-DGED_PLUGIN)
-add_library(ged-bot SHARED bot.cpp)
+add_library(ged-bot SHARED ${BOT_SRCS})
 target_link_libraries(ged-bot libged libbu)
 set_property(TARGET ged-bot APPEND PROPERTY COMPILE_DEFINITIONS BRLCADBUILD 
HAVE_CONFIG_H)
-VALIDATE_STYLE(ged-bot bot.cpp)
+VALIDATE_STYLE(ged-bot ${BOT_SRCS})
 PLUGIN_SETUP(ged-bot ged)
 
 # Local Variables:
@@ -19,3 +38,4 @@
 # indent-tabs-mode: t
 # End:
 # ex: shiftwidth=2 tabstop=8
+

Modified: brlcad/branches/gedplugins/src/libged/bot/ged_bot.h
===================================================================
--- brlcad/branches/gedplugins/src/libged/bot/ged_bot.h 2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/bot/ged_bot.h 2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -68,11 +68,11 @@
 
 int _bot_cmd_msgs(void *bs, int argc, const char **argv, const char *us, const 
char *ps);
 
-GED_EXPORT int _bot_cmd_extrude(void *bs, int argc, const char **argv);
+GED_EXPORT extern int _bot_cmd_extrude(void *bs, int argc, const char **argv);
 
-GED_EXPORT int _bot_cmd_check(void *bs, int argc, const char **argv);
+GED_EXPORT extern int _bot_cmd_check(void *bs, int argc, const char **argv);
 
-GED_EXPORT int _bot_cmd_remesh(void *bs, int argc, const char **argv);
+GED_EXPORT extern int _bot_cmd_remesh(void *bs, int argc, const char **argv);
 
 __END_DECLS
 

Modified: brlcad/branches/gedplugins/src/libged/brep/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/brep/CMakeLists.txt   2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/brep/CMakeLists.txt   2020-07-22 
01:27:01 UTC (rev 76402)
@@ -6,11 +6,23 @@
   ${GED_INCLUDE_DIRS}
   )
 
+set(BREP_SRCS
+       brep.cpp
+       conversion.cpp
+       csg.cpp
+       info.cpp
+       intersect.cpp
+       pick.cpp
+       plot.cpp
+       tikz.cpp
+       valid.cpp
+       )
+
 add_definitions(-DGED_PLUGIN)
-add_library(ged-brep SHARED brep.cpp)
+add_library(ged-brep SHARED ${BREP_SRCS})
 target_link_libraries(ged-brep libged libbu)
 set_property(TARGET ged-brep APPEND PROPERTY COMPILE_DEFINITIONS BRLCADBUILD 
HAVE_CONFIG_H)
-VALIDATE_STYLE(ged-brep brep.cpp)
+VALIDATE_STYLE(ged-brep ${BREP_SRCS})
 PLUGIN_SETUP(ged-brep ged)
 
 # Local Variables:
@@ -19,3 +31,4 @@
 # indent-tabs-mode: t
 # End:
 # ex: shiftwidth=2 tabstop=8
+

Modified: brlcad/branches/gedplugins/src/libged/check/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/check/CMakeLists.txt  2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/check/CMakeLists.txt  2020-07-22 
01:27:01 UTC (rev 76402)
@@ -6,11 +6,25 @@
   ${GED_INCLUDE_DIRS}
   )
 
+set(CHECK_SRCS
+       check_adj_air.c
+       check.c
+       check_centroid.c
+       check_exp_air.c
+       check_gap.c
+       check_mass.c
+       check_moments.c
+       check_overlaps.c
+       check_surf_area.c
+       check_unconf_air.c
+       check_volume.c
+       )
+
 add_definitions(-DGED_PLUGIN)
-add_library(ged-check SHARED check.c)
+add_library(ged-check SHARED ${CHECK_SRCS})
 target_link_libraries(ged-check libged libbu)
 set_property(TARGET ged-check APPEND PROPERTY COMPILE_DEFINITIONS BRLCADBUILD 
HAVE_CONFIG_H)
-VALIDATE_STYLE(ged-check check.c)
+VALIDATE_STYLE(ged-check ${CHECK_SRCS})
 PLUGIN_SETUP(ged-check ged)
 
 # Local Variables:
@@ -19,3 +33,4 @@
 # indent-tabs-mode: t
 # End:
 # ex: shiftwidth=2 tabstop=8
+

Modified: brlcad/branches/gedplugins/src/libged/comb/comb.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/comb/comb.c   2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/comb/comb.c   2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -772,204 +772,7 @@
 }
 
 
-/*
- * Add an instance of object 'objp' to combination 'name'.
- * If the combination does not exist, it is created.
- * region_flag is 1 (region), or 0 (group).
- *
- * Preserves the GIFT semantics.
- */
-struct directory *
-_ged_combadd(struct ged *gedp,
-            struct directory *objp,
-            char *combname,
-            int region_flag,   /* true if adding region */
-            db_op_t relation,  /* = UNION, SUBTRACT, INTERSECT */
-            int ident,         /* "Region ID" */
-            int air            /* Air code */)
-{
-    int ac = 1;
-    const char *av[2];
 
-    av[0] = objp->d_namep;
-    av[1] = NULL;
-
-    if (_ged_combadd2(gedp, combname, ac, av, region_flag, relation, ident, 
air, NULL, 1) == GED_ERROR)
-       return RT_DIR_NULL;
-
-    /* Done changing stuff - update nref. */
-    db_update_nref(gedp->ged_wdbp->dbip, &rt_uniresource);
-
-    return db_lookup(gedp->ged_wdbp->dbip, combname, LOOKUP_QUIET);
-}
-
-
-/*
- * Add an instance of object 'objp' to combination 'name'.
- * If the combination does not exist, it is created.
- * region_flag is 1 (region), or 0 (group).
- *
- * Preserves the GIFT semantics.
- */
-int
-_ged_combadd2(struct ged *gedp,
-             char *combname,
-             int argc,
-             const char *argv[],
-             int region_flag,  /* true if adding region */
-             db_op_t relation, /* = UNION, SUBTRACT, INTERSECT */
-             int ident,        /* "Region ID" */
-             int air,          /* Air code */
-             matp_t m,         /* Matrix */
-             int validate      /* 1 to check if new members exist, 0 to just 
add them */)
-{
-    struct directory *dp;
-    struct directory *objp;
-    struct rt_db_internal intern;
-    struct rt_comb_internal *comb;
-    union tree *tp;
-    struct rt_tree_array *tree_list;
-    size_t node_count;
-    size_t actual_count;
-    size_t curr_count;
-    int i;
-
-    if (argc < 1)
-       return GED_ERROR;
-
-    /*
-     * Check to see if we have to create a new combination
-     */
-    if ((dp = db_lookup(gedp->ged_wdbp->dbip,  combname, LOOKUP_QUIET)) == 
RT_DIR_NULL) {
-       int flags;
-
-       if (region_flag)
-           flags = RT_DIR_REGION | RT_DIR_COMB;
-       else
-           flags = RT_DIR_COMB;
-
-       RT_DB_INTERNAL_INIT(&intern);
-       intern.idb_major_type = DB5_MAJORTYPE_BRLCAD;
-       intern.idb_type = ID_COMBINATION;
-       intern.idb_meth = &OBJ[ID_COMBINATION];
-
-       GED_DB_DIRADD(gedp, dp, combname, -1, 0, flags, (void 
*)&intern.idb_type, 0);
-
-       BU_ALLOC(comb, struct rt_comb_internal);
-       RT_COMB_INTERNAL_INIT(comb);
-
-       intern.idb_ptr = (void *)comb;
-
-       if (region_flag) {
-           comb->region_flag = 1;
-           comb->region_id = ident;
-           comb->aircode = air;
-           comb->los = gedp->ged_wdbp->wdb_los_default;
-           comb->GIFTmater = gedp->ged_wdbp->wdb_mat_default;
-           bu_vls_printf(gedp->ged_result_str, "Creating region with attrs: 
region_id=%d, ", ident);
-           if (air)
-               bu_vls_printf(gedp->ged_result_str, "air=%d, ", air);
-           bu_vls_printf(gedp->ged_result_str, "los=%d, material_id=%d\n",
-                         gedp->ged_wdbp->wdb_los_default,
-                         gedp->ged_wdbp->wdb_mat_default);
-       } else {
-           comb->region_flag = 0;
-       }
-
-       goto addmembers;
-    } else if (!(dp->d_flags & RT_DIR_COMB)) {
-       bu_vls_printf(gedp->ged_result_str, "%s exists, but is not a 
combination\n", dp->d_namep);
-       return GED_ERROR;
-    }
-
-    /* combination exists, add a new member */
-    GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, &rt_uniresource, 
0);
-
-    comb = (struct rt_comb_internal *)intern.idb_ptr;
-    RT_CK_COMB(comb);
-
-    if (region_flag && !comb->region_flag) {
-       bu_vls_printf(gedp->ged_result_str, "%s: not a region\n", dp->d_namep);
-       return GED_ERROR;
-    }
-
-addmembers:
-    if (comb->tree && db_ck_v4gift_tree(comb->tree) < 0) {
-       db_non_union_push(comb->tree, &rt_uniresource);
-       if (db_ck_v4gift_tree(comb->tree) < 0) {
-           bu_vls_printf(gedp->ged_result_str, "Cannot flatten tree for 
editing\n");
-           rt_db_free_internal(&intern);
-           return GED_ERROR;
-       }
-    }
-
-    /* make space for an extra leaf */
-    curr_count = db_tree_nleaves(comb->tree);
-    node_count = curr_count + argc;
-    tree_list = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct 
rt_tree_array), "tree list");
-
-    /* flatten tree */
-    if (comb->tree) {
-       actual_count = argc + (struct rt_tree_array 
*)db_flatten_tree(tree_list, comb->tree, OP_UNION, 1, &rt_uniresource) - 
tree_list;
-       BU_ASSERT(actual_count == node_count);
-       comb->tree = TREE_NULL;
-    }
-
-    for (i = 0; i < argc; ++i) {
-       if (validate) {
-           if ((objp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) 
== RT_DIR_NULL) {
-               bu_vls_printf(gedp->ged_result_str, "skip member %s\n", 
argv[i]);
-               continue;
-           }
-       }
-
-       /* insert new member at end */
-       switch (relation) {
-       case DB_OP_INTERSECT:
-           tree_list[curr_count].tl_op = OP_INTERSECT;
-           break;
-       case DB_OP_SUBTRACT:
-           tree_list[curr_count].tl_op = OP_SUBTRACT;
-           break;
-       default:
-           if (relation != DB_OP_UNION) {
-               bu_vls_printf(gedp->ged_result_str, "unrecognized relation 
(assume UNION)\n");
-           }
-           tree_list[curr_count].tl_op = OP_UNION;
-           break;
-       }
-
-       /* make new leaf node, and insert at end of list */
-       BU_GET(tp, union tree);
-       RT_TREE_INIT(tp);
-       tree_list[curr_count].tl_tree = tp;
-       tp->tr_l.tl_op = OP_DB_LEAF;
-       tp->tr_l.tl_name = bu_strdup(argv[i]);
-       if (m) {
-           tp->tr_l.tl_mat = (matp_t)bu_malloc(sizeof(mat_t), "mat copy");
-           MAT_COPY(tp->tr_l.tl_mat, m);
-       } else {
-           tp->tr_l.tl_mat = (matp_t)NULL;
-       }
-
-       ++curr_count;
-    }
-
-    /* rebuild the tree */
-    comb->tree = (union tree *)db_mkgift_tree(tree_list, node_count, 
&rt_uniresource);
-
-    /* and finally, write it out */
-    GED_DB_PUT_INTERNAL(gedp, dp, &intern, &rt_uniresource, 0);
-
-    bu_free((char *)tree_list, "combadd: tree_list");
-
-    /* Done changing stuff - update nref. */
-    db_update_nref(gedp->ged_wdbp->dbip, &rt_uniresource);
-
-    return GED_OK;
-}
-
-
 #ifdef GED_PLUGIN
 #include "../include/plugin.h"
 struct ged_cmd_impl comb_cmd_impl = {

Modified: brlcad/branches/gedplugins/src/libged/draw/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/draw/CMakeLists.txt   2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/draw/CMakeLists.txt   2020-07-22 
01:27:01 UTC (rev 76402)
@@ -6,11 +6,17 @@
   ${GED_INCLUDE_DIRS}
   )
 
+set(DRAW_SRCS
+  draw.c
+  loadview.c
+  preview.c
+  )
+
 add_definitions(-DGED_PLUGIN)
-add_library(ged-draw SHARED draw.c)
+add_library(ged-draw SHARED ${DRAW_SRCS})
 target_link_libraries(ged-draw libged libbu)
 set_property(TARGET ged-draw APPEND PROPERTY COMPILE_DEFINITIONS BRLCADBUILD 
HAVE_CONFIG_H)
-VALIDATE_STYLE(ged-draw draw.c)
+VALIDATE_STYLE(ged-draw ${DRAW_SRCS})
 PLUGIN_SETUP(ged-draw ged)
 
 # Local Variables:

Modified: brlcad/branches/gedplugins/src/libged/draw/draw.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/draw/draw.c   2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/draw/draw.c   2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -159,28 +159,6 @@
     return curtree;
 }
 
-/**
- * Once the vlist has been created, perform the common tasks
- * in handling the drawn solid.
- *
- * This routine must be prepared to run in parallel.
- */
-void
-_ged_drawH_part2(int dashflag, struct bu_list *vhead, const struct 
db_full_path *pathp, struct db_tree_state *tsp, struct _ged_client_data *dgcdp)
-{
-
-    if (dgcdp->wireframe_color_override) {
-       unsigned char wcolor[3];
-
-       wcolor[0] = (unsigned char)dgcdp->wireframe_color[0];
-       wcolor[1] = (unsigned char)dgcdp->wireframe_color[1];
-       wcolor[2] = (unsigned char)dgcdp->wireframe_color[2];
-       dl_add_path(dgcdp->gdlp, dashflag, dgcdp->transparency, dgcdp->dmode, 
dgcdp->hiddenLine, vhead, pathp, tsp, wcolor, 
dgcdp->gedp->ged_create_vlist_solid_callback, dgcdp->freesolid);
-    } else {
-       dl_add_path(dgcdp->gdlp, dashflag, dgcdp->transparency, dgcdp->dmode, 
dgcdp->hiddenLine, vhead, pathp, tsp, NULL, 
dgcdp->gedp->ged_create_vlist_solid_callback, dgcdp->freesolid);
-    }
-}
-
 static int
 get_path_and_state(
     struct db_tree_state *tsp,
@@ -563,25 +541,6 @@
     return curtree;
 }
 
-
-void
-_ged_cvt_vlblock_to_solids(struct ged *gedp, struct bn_vlblock *vbp, const 
char *name, int copy)
-{
-    size_t i;
-    char shortname[32] = {0};
-    char namebuf[64] = {0};
-
-    bu_strlcpy(shortname, name, sizeof(shortname));
-
-    for (i = 0; i < vbp->nused; i++) {
-       if (BU_LIST_IS_EMPTY(&(vbp->head[i])))
-           continue;
-       snprintf(namebuf, 64, "%s%lx", shortname, vbp->rgb[i]);
-       invent_solid(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, 
gedp->ged_create_vlist_solid_callback, gedp->ged_free_vlist_callback, namebuf, 
&vbp->head[i], vbp->rgb[i], copy, 1.0, 0, gedp->freesolid, 0);
-    }
-}
-
-
 /*
  * This routine is the drawable geometry object's analog of rt_gettrees().
  * Add a set of tree hierarchies to the active set.
@@ -1356,10 +1315,29 @@
 };
 
 const struct ged_cmd draw_cmd = { &draw_cmd_impl };
-const struct ged_cmd *draw_cmds[] = { &draw_cmd, NULL };
 
-static const struct ged_plugin pinfo = { draw_cmds, 1 };
+extern int ged_loadview_core(struct ged *gedp, int argc, const char *argv[]);
 
+struct ged_cmd_impl loadview_cmd_impl = {
+    "loadview",
+    ged_loadview_core,
+    GED_CMD_DEFAULT
+};
+const struct ged_cmd loadview_cmd = { &loadview_cmd_impl };
+
+extern int ged_preview_core(struct ged *gedp, int argc, const char *argv[]);
+
+struct ged_cmd_impl preview_cmd_impl = {
+    "preview",
+    ged_preview_core,
+    GED_CMD_DEFAULT
+};
+const struct ged_cmd preview_cmd = { &preview_cmd_impl };
+
+const struct ged_cmd *draw_cmds[] = { &draw_cmd, &loadview_cmd, &preview_cmd, 
NULL };
+
+static const struct ged_plugin pinfo = { draw_cmds, 3 };
+
 COMPILER_DLLEXPORT const struct ged_plugin *ged_plugin_info()
 {
     return &pinfo;

Copied: brlcad/branches/gedplugins/src/libged/draw/loadview.c (from rev 76401, 
brlcad/branches/gedplugins/src/libged/loadview/loadview.c)
===================================================================
--- brlcad/branches/gedplugins/src/libged/draw/loadview.c                       
        (rev 0)
+++ brlcad/branches/gedplugins/src/libged/draw/loadview.c       2020-07-22 
01:27:01 UTC (rev 76402)
@@ -0,0 +1,414 @@
+/*                         L O A D V I E W . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2008-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file libged/loadview.c
+ *
+ * The loadview command.
+ *
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+
+#include "../ged_private.h"
+
+/**
+ * here we define a minimal table of commands that are supported by the
+ * loadview command.  unsupported commands are those that have no bearing on
+ * view restoration.
+ */
+struct command_tab ged_loadview_cmdtab[] = {
+    {"viewsize", "size in mm", "set view size",
+     _ged_cm_vsize,    2, 2},
+    {"eye_pt", "xyz of eye", "set eye point",
+     _ged_cm_eyept,    4, 4},
+    {"lookat_pt", "x y z [yflip]", "set eye look direction, in X-Y plane",
+     _ged_cm_lookat_pt,        4, 5},
+    {"viewrot", "4x4 matrix", "set view direction from matrix",
+     _ged_cm_vrot,     17, 17},
+    {"orientation", "quaternion", "set view direction from quaternion",
+     _ged_cm_orientation,      5, 5},
+    {"set",    "", "show or set parameters",
+     _ged_cm_set,              1, 999},
+
+    /* begin unsupported commands (for view loading) */
+
+    {"start", "frame number", "start a new frame",
+     _ged_cm_null,     2, 2},
+    {"clean", "", "clean articulation from previous frame",
+     _ged_cm_null,     1, 1},
+    {"end",    "", "end of frame setup, begin raytrace",
+     _ged_cm_end,              1, 1},
+
+    /* not output, by default in saveview */
+
+    {"multiview", "", "produce stock set of views",
+     _ged_cm_null,     1, 1},
+    {"anim",   "path type args", "specify articulation animation",
+     _ged_cm_null,     4, 999},
+    {"tree",   "treetop(s)", "specify alternate list of tree tops",
+     _ged_cm_null,     1, 999},
+    {"ae", "azim elev", "specify view as azim and elev, in degrees",
+     _ged_cm_null,             3, 3},
+    {"opt", "-flags", "set flags, like on command line",
+     _ged_cm_null,             2, 999},
+
+    /* this is a quick hack used for quietly parsing the EOF delimiter in the
+     * script files.
+     */
+    {"EOF", "", "End of file delimiter",
+     _ged_cm_null,             1, 1},
+
+    /* XXX support for the ae command is not included, though it probably 
should */
+    {(char *)0, (char *)0, (char *)0,
+     0,                0, 0    /* END */}
+};
+
+
+int
+ged_loadview_core(struct ged *gedp, int argc, const char *argv[])
+{
+    int ret;
+    int failed = 0;
+    FILE *fp;
+    char buffer[512] = {0};
+
+    /* data pulled from script file */
+    int perspective=-1;
+#define MAX_DBNAME 2048
+    char name[MAX_DBNAME] = {0};
+    char *dbName = name;
+    char objects[10000] = {0};
+    char *editArgv[3];
+    static const char *usage = "filename";
+
+    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
+    GED_CHECK_VIEW(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;
+    }
+
+    /* make sure the file exists */
+    if (!bu_file_exists(argv[1], NULL)) {
+       bu_log("Error: File %s does not exist\n", argv[1]);
+       return GED_ERROR;
+    }
+
+    /* open the file for reading */
+    if ((fp = fopen(argv[1], "r")) == NULL) {
+       perror(argv[1]);
+       return GED_ERROR;
+    }
+
+    _ged_current_gedp = gedp;
+
+    /* turn perspective mode off, by default.  A "-p" option in the
+     * view script will turn it back on.
+     */
+    gedp->ged_gvp->gv_perspective = 0;
+
+    /* iterate over the contents of the raytrace script */
+    /* TODO: change to bu_fgets or bu_vls_fgets */
+    while (!feof(fp)) {
+       memset(buffer, 0, 512);
+       ret = fscanf(fp, "%512s", buffer);
+       if (ret != 1) {
+           bu_log("Failed to read buffer\n");
+           failed++;
+       }
+
+       if (bu_strncmp(buffer, "-p", 2) == 0) {
+           char perspective_angle[128] = {0};
+           const char *perspective_argv[2] = {"perspective", NULL};
+           perspective_argv[1] = perspective_angle;
+
+           /* we found perspective */
+
+           buffer[0] = ' ';
+           buffer[1] = ' ';
+           sscanf(buffer, "%d", &perspective);
+           /* bu_log("perspective=%d\n", perspective);*/
+           snprintf(perspective_angle, sizeof(perspective_angle), "%d", 
perspective);
+
+           ged_perspective(gedp, 2, (const char **)perspective_argv);
+
+       } else if (bu_strncmp(buffer, "$*", 2) == 0) {
+           /* the next read is the file name, the objects come
+            * after that
+            */
+
+           memset(dbName, 0, MAX_DBNAME);
+           ret = fscanf(fp, "%2048s", dbName); /* MAX_DBNAME */
+           if (ret != 1) {
+               bu_log("Failed to read database name\n");
+               failed++;
+           }
+
+           /* if the last character is a line termination,
+            * remove it (it should always be unless the user
+            * modifies the file)
+            */
+           if (*(dbName + strlen(dbName) - 1)=='\\') {
+               memset(dbName+strlen(dbName)-1, 0, 1);
+           }
+           /* bu_log("dbName=%s\n", dbName); */
+
+           /* if the name was wrapped in quotes, remove them */
+           if (dbName[0] == '\'' && *(dbName + strlen(dbName) - 1) == '\'') {
+               dbName++;
+               memset(dbName + strlen(dbName)-1, 0, 1);
+           }
+    
+           if (!bu_file_same(gedp->ged_wdbp->dbip->dbi_filename, dbName)) {
+               /* warn here if they are not the same file, otherwise,
+                * proceed as expected, and try to load the objects.
+                */
+               bu_log("WARNING: view script seems to reference a different 
database\n([%s] != [%s])\n", dbName, gedp->ged_wdbp->dbip->dbi_filename);
+           }
+
+           /* get rid of anything that may be displayed, since we
+            * will load objects that are listed in the script next.
+            *
+            * TODO: should only zap if the objects to be displayed
+            * all exist.
+            */
+           (void)ged_zap(gedp, 1, NULL);
+
+           /* now get the objects listed */
+           ret = fscanf(fp, "%10000s", objects);
+           if (ret != 1) {
+               bu_log("Failed to read object names\n");
+               failed++;
+           }
+
+           /* bu_log("OBJECTS=%s\n", objects);*/
+           while ((!feof(fp)) && (bu_strncmp(objects, "\\", 1) != 0)) {
+
+               /* clean off the single quotes... */
+               if (bu_strncmp(objects, "'", 1) == 0) {
+                   objects[0]=' ';
+                   memset(objects+strlen(objects)-1, ' ', 1);
+                   sscanf(objects, "%10000s", objects);
+               }
+
+               editArgv[0] = "draw";
+               editArgv[1] = objects;
+               editArgv[2] = (char *)NULL;
+               if (ged_draw(gedp, 2, (const char **)editArgv) != GED_OK) {
+                   bu_vls_printf(gedp->ged_result_str, "Unable to load object: 
%s\n", objects);
+               }
+
+               /* bu_log("objects=%s\n", objects);*/
+               ret = fscanf(fp, "%10000s", objects);
+               if (ret != 1) {
+                   bu_log("Failed to read object names\n");
+                   failed++;
+               }
+           }
+
+           /* end iteration over reading in listed objects */
+       } else if (bu_strncmp(buffer, "<<EOF", 5) == 0) {
+           char *cmdBuffer = NULL;
+           /* we are almost done .. read in the view commands */
+
+           while ((cmdBuffer = rt_read_cmd(fp)) != NULL) {
+               /* even unsupported commands should return successfully as
+                * they should be calling ged_cm_null()
+                */
+               if (rt_do_cmd((struct rt_i *)0, cmdBuffer, ged_loadview_cmdtab) 
< 0) {
+                   bu_vls_printf(gedp->ged_result_str, "command failed: %s\n", 
cmdBuffer);
+                   failed++;
+               }
+               bu_free((void *)cmdBuffer, "loadview cmdBuffer");
+           }
+           /* end iteration over rt commands */
+
+       }
+       /* end check for non-view values (dbname, etc.) */
+
+    }
+    /* end iteration over file until eof */
+    fclose(fp);
+
+    if (failed)
+       return GED_ERROR;
+
+    return GED_OK;
+}
+
+
+int
+_ged_cm_vsize(const int argc, const char **argv)
+{
+    if (argc < 2)
+       return -1;
+    /* for some reason, scale is supposed to be half of size... */
+    _ged_current_gedp->ged_gvp->gv_size = atof(argv[1]);
+    _ged_current_gedp->ged_gvp->gv_scale = _ged_current_gedp->ged_gvp->gv_size 
* 0.5;
+    _ged_current_gedp->ged_gvp->gv_isize = 1.0 / 
_ged_current_gedp->ged_gvp->gv_size;
+    return 0;
+}
+
+
+int
+_ged_cm_eyept(const int argc, const char **argv)
+{
+    if (argc < 4)
+       return -1;
+    _ged_eye_model[X] = atof(argv[1]);
+    _ged_eye_model[Y] = atof(argv[2]);
+    _ged_eye_model[Z] = atof(argv[3]);
+
+    /* Processing is deferred until view 'end' */
+    return 0;
+}
+
+
+int
+_ged_cm_lookat_pt(const int argc, const char **argv)
+{
+    point_t pt;
+    vect_t dir;
+
+    if (argc < 4)
+       return -1;
+    pt[X] = atof(argv[1]);
+    pt[Y] = atof(argv[2]);
+    pt[Z] = atof(argv[3]);
+
+    VSUB2(dir, pt, _ged_eye_model);
+    VUNITIZE(dir);
+
+    /*
+     * At the moment bn_mat_lookat() will return NAN's if the
+     * direction vector is aligned with the Z axis. The following is a
+     * workaround.
+     */
+    {
+       vect_t neg_Z_axis = VINIT_ZERO;
+       neg_Z_axis[Z] = -1.0;
+       bn_mat_fromto(_ged_viewrot, dir, neg_Z_axis, 
&_ged_current_gedp->ged_wdbp->wdb_tol);
+    }
+
+    /* Final processing is deferred until view 'end', but eye_pt
+     * must have been specified before here (for now)
+     */
+    return 0;
+}
+
+
+int
+_ged_cm_vrot(const int argc, const char **argv)
+{
+    int i;
+
+    if (argc < 17)
+       return -1;
+    for (i = 0; i < 16; i++)
+       _ged_viewrot[i] = atof(argv[i+1]);
+    /* Processing is deferred until view 'end' */
+    return 0;
+}
+
+
+int
+_ged_cm_orientation(const int argc, const char **argv)
+{
+    int i;
+    quat_t quat;
+
+    if (argc < 4)
+       return -1;
+
+    for (i = 0; i < 4; i++)
+       quat[i] = atof(argv[i+1]);
+    quat_quat2mat(_ged_viewrot, quat);
+
+    return 0;
+}
+
+
+int
+_ged_cm_set(const int UNUSED(argc), const char **UNUSED(argv))
+{
+    return -1;
+}
+
+
+/**
+ * any commands that are not supported or implemented may call this null
+ * routine to avoid rt_do_cmd() "command not found" error reporting
+ */
+int
+_ged_cm_null(const int argc, const char **argv)
+{
+    if (argc < 0 || argv == NULL)
+       return 1;
+
+    return 0;
+}
+
+
+/**
+ * process the 'end' of a view.  currently, requires an eye point be
+ * specified beforehand.
+ */
+int
+_ged_cm_end(const int argc, const char **argv)
+{
+    struct bu_vls eye = BU_VLS_INIT_ZERO;
+    char *eye_argv[5] = {"eye", NULL, NULL, NULL, NULL};
+
+    if (argc < 0 || argv == NULL)
+       return 1;
+
+    /* now we have to finish view calculations that are deferred until
+     * the end command runs.
+     */
+    MAT_COPY(_ged_current_gedp->ged_gvp->gv_rotation, _ged_viewrot);
+    MAT_DELTAS_VEC_NEG(_ged_current_gedp->ged_gvp->gv_center, _ged_eye_model);
+    bview_update(_ged_current_gedp->ged_gvp);
+
+    bu_vls_printf(&eye, "%lf %lf %lf", V3ARGS(_ged_eye_model));
+    bu_argv_from_string(eye_argv+1, 4, bu_vls_addr(&eye));
+    ged_eye(_ged_current_gedp, 4, (const char **)eye_argv);
+    bu_vls_free(&eye);
+
+    return 0;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Copied: brlcad/branches/gedplugins/src/libged/draw/preview.c (from rev 76401, 
brlcad/branches/gedplugins/src/libged/preview/preview.c)
===================================================================
--- brlcad/branches/gedplugins/src/libged/draw/preview.c                        
        (rev 0)
+++ brlcad/branches/gedplugins/src/libged/draw/preview.c        2020-07-22 
01:27:01 UTC (rev 76402)
@@ -0,0 +1,451 @@
+/*                         P R E V I E W . C
+ * BRL-CAD
+ *
+ * Copyright (c) 2008-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This library is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ */
+/** @file libged/preview.c
+ *
+ * The preview command.
+ *
+ */
+
+#include "common.h"
+
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <time.h>
+#include "bsocket.h"
+
+#include "bu/cmd.h"
+#include "bu/getopt.h"
+
+#include "../ged_private.h"
+
+static struct bn_vlblock *preview_vbp;
+static double preview_delay;
+static int preview_mode;
+static int preview_desiredframe;
+static int preview_finalframe;
+static int preview_currentframe;
+static int preview_tree_walk_needed;
+static int draw_eye_path;
+static char *image_name = NULL;
+
+
+/* FIXME: this shouldn't exist as a static array and doesn't even seem
+ * to be necessary.  gd_rt_cmd points into it as an argv, but the
+ * elements can probably be dup'd strings and released by the caller.
+ */
+#define MAXARGS 9000
+static char rt_cmd_storage[MAXARGS*9];
+
+
+int
+ged_cm_anim(const int argc, const char **argv)
+{
+
+    if (_ged_current_gedp->ged_wdbp->dbip == DBI_NULL)
+       return 0;
+
+    if (db_parse_anim(_ged_current_gedp->ged_wdbp->dbip, argc, (const char 
**)argv) < 0) {
+       bu_vls_printf(_ged_current_gedp->ged_result_str, "cm_anim:  %s %s 
failed\n", argv[1], argv[2]);
+       return -1;              /* BAD */
+    }
+
+    preview_tree_walk_needed = 1;
+
+    return 0;
+}
+
+
+int
+ged_cm_clean(const int UNUSED(argc), const char **UNUSED(argv))
+{
+    if (_ged_current_gedp->ged_wdbp->dbip == DBI_NULL)
+       return 0;
+
+    /*f_zap(NULL, interp, 0, (char **)0);*/
+
+    /* Free animation structures */
+    db_free_anim(_ged_current_gedp->ged_wdbp->dbip);
+
+    preview_tree_walk_needed = 0;
+    return 0;
+}
+
+
+int
+ged_cm_end(const int UNUSED(argc), const char **UNUSED(argv))
+{
+    vect_t xlate;
+    vect_t new_cent;
+    vect_t xv, yv;                     /* view x, y */
+    vect_t xm, ym;                     /* model x, y */
+    struct bu_list *vhead = &preview_vbp->head[0];
+
+    /* Only display the frames the user is interested in */
+    if (preview_currentframe < preview_desiredframe) return 0;
+    if (preview_finalframe && preview_currentframe > preview_finalframe) 
return 0;
+
+    /* Record eye path as a polyline.  Move, then draws */
+    if (BU_LIST_IS_EMPTY(vhead)) {
+       RT_ADD_VLIST(vhead, _ged_eye_model, BN_VLIST_LINE_MOVE);
+    } else {
+       RT_ADD_VLIST(vhead, _ged_eye_model, BN_VLIST_LINE_DRAW);
+    }
+
+    /* First step:  put eye at view center (view 0, 0, 0) */
+    MAT_COPY(_ged_current_gedp->ged_gvp->gv_rotation, _ged_viewrot);
+    MAT_DELTAS_VEC_NEG(_ged_current_gedp->ged_gvp->gv_center, _ged_eye_model);
+    bview_update(_ged_current_gedp->ged_gvp);
+
+    /*
+     * Compute camera orientation notch to right (+X) and up (+Y)
+     * Done here, with eye in center of view.
+     */
+    VSET(xv, 0.05, 0.0, 0.0);
+    VSET(yv, 0.0, 0.05, 0.0);
+    MAT4X3PNT(xm, _ged_current_gedp->ged_gvp->gv_view2model, xv);
+    MAT4X3PNT(ym, _ged_current_gedp->ged_gvp->gv_view2model, yv);
+    RT_ADD_VLIST(vhead, xm, BN_VLIST_LINE_DRAW);
+    RT_ADD_VLIST(vhead, _ged_eye_model, BN_VLIST_LINE_MOVE);
+    RT_ADD_VLIST(vhead, ym, BN_VLIST_LINE_DRAW);
+    RT_ADD_VLIST(vhead, _ged_eye_model, BN_VLIST_LINE_MOVE);
+
+    /* Second step:  put eye at view 0, 0, 1.
+     * For eye to be at 0, 0, 1, the old 0, 0, -1 needs to become 0, 0, 0.
+     */
+    VSET(xlate, 0.0, 0.0, -1.0);       /* correction factor */
+    MAT4X3PNT(new_cent, _ged_current_gedp->ged_gvp->gv_view2model, xlate);
+    MAT_DELTAS_VEC_NEG(_ged_current_gedp->ged_gvp->gv_center, new_cent);
+    bview_update(_ged_current_gedp->ged_gvp);
+
+    /* If new treewalk is needed, get new objects into view. */
+    if (preview_tree_walk_needed) {
+       const char *av[2];
+
+       av[0] = "zap";
+       av[1] = NULL;
+
+       (void)ged_zap(_ged_current_gedp, 1, av);
+       _ged_drawtrees(_ged_current_gedp, 
_ged_current_gedp->ged_gdp->gd_rt_cmd_len, (const char 
**)&_ged_current_gedp->ged_gdp->gd_rt_cmd[1], preview_mode, (struct 
_ged_client_data *)0);
+    }
+
+    if (_ged_current_gedp->ged_refresh_handler != 
GED_REFRESH_CALLBACK_PTR_NULL)
+       
(*_ged_current_gedp->ged_refresh_handler)(_ged_current_gedp->ged_refresh_clientdata);
+
+    if (preview_delay > 0) {
+       struct timeval tv;
+       fd_set readfds;
+
+       FD_ZERO(&readfds);
+       FD_SET(fileno(stdin), &readfds);
+       tv.tv_sec = (long)preview_delay;
+       tv.tv_usec = (long)((preview_delay - tv.tv_sec) * 1000000);
+       select(fileno(stdin)+1, &readfds, (fd_set *)0, (fd_set *)0, &tv);
+    }
+
+    return 0;
+}
+
+
+int
+ged_cm_multiview(const int UNUSED(argc), const char **UNUSED(argv))
+{
+    return -1;
+}
+
+
+int
+ged_cm_start(const int argc, const char **argv)
+{
+    if (argc < 2)
+       return -1;
+    preview_currentframe = atoi(argv[1]);
+    preview_tree_walk_needed = 0;
+
+    return 0;
+}
+
+
+int
+ged_cm_tree(const int argc, const char **argv)
+{
+    int i = 1;
+    char *cp = rt_cmd_storage;
+
+    for (i = 1;  i < argc && i < MAXARGS; i++) {
+       bu_strlcpy(cp, argv[i], MAXARGS*9);
+       _ged_current_gedp->ged_gdp->gd_rt_cmd[i] = cp;
+       cp += strlen(cp) + 1;
+    }
+    _ged_current_gedp->ged_gdp->gd_rt_cmd[i] = (char *)0;
+    _ged_current_gedp->ged_gdp->gd_rt_cmd_len = i-1;
+
+    preview_tree_walk_needed = 1;
+
+    return 0;
+}
+
+
+struct command_tab ged_preview_cmdtab[] = {
+    {"start", "frame number", "start a new frame",
+     ged_cm_start,     2, 2},
+    {"viewsize", "size in mm", "set view size",
+     _ged_cm_vsize,    2, 2},
+    {"eye_pt", "xyz of eye", "set eye point",
+     _ged_cm_eyept,    4, 4},
+    {"lookat_pt", "x y z [yflip]", "set eye look direction, in X-Y plane",
+     _ged_cm_lookat_pt,        4, 5},
+    {"orientation", "quaternion", "set view direction from quaternion",
+     _ged_cm_orientation,      5, 5},
+    {"viewrot", "4x4 matrix", "set view direction from matrix",
+     _ged_cm_vrot,     17, 17},
+    {"end",    "", "end of frame setup, begin raytrace",
+     ged_cm_end,               1, 1},
+    {"multiview", "", "produce stock set of views",
+     ged_cm_multiview, 1, 1},
+    {"anim",   "path type args", "specify articulation animation",
+     ged_cm_anim,      4, 999},
+    {"tree",   "treetop(s)", "specify alternate list of tree tops",
+     ged_cm_tree,      1, 999},
+    {"clean", "", "clean articulation from previous frame",
+     ged_cm_clean,     1, 1},
+    {"set",    "", "show or set parameters",
+     _ged_cm_set,              1, 999},
+    {"ae", "azim elev", "specify view as azim and elev, in degrees",
+     _ged_cm_null,             3, 3},
+    {"opt", "-flags", "set flags, like on command line",
+     _ged_cm_null,             2, 999},
+    {(char *)0, (char *)0, (char *)0,
+     0,                0, 0}   /* END */
+};
+
+
+int
+ged_loadframe(struct ged *gedp, FILE *fp)
+{
+    char *cmd;
+
+    int end = 0;
+    while (!end && ((cmd = rt_read_cmd(fp)) != NULL)) {
+       /* Hack to prevent running framedone scripts prematurely */
+       if (cmd[0] == '!') {
+           if (preview_currentframe < preview_desiredframe ||
+               (preview_finalframe && preview_currentframe > 
preview_finalframe)) {
+               bu_free((void *)cmd, "preview ! cmd");
+               continue;
+           }
+       }
+
+       if (cmd[0] == 'e' && bu_strncmp(cmd, "end", 3) == 0) {
+           end = 1;
+       }
+
+       if (rt_do_cmd((struct rt_i *)0, cmd, ged_preview_cmdtab) < 0)
+           bu_vls_printf(gedp->ged_result_str, "command failed: %s\n", cmd);
+       bu_free((void *)cmd, "preview cmd");
+    }
+
+    if (end) {
+       return GED_OK; /* possible more frames */
+    }
+    return GED_ERROR; /* end of frames */
+}
+
+
+/**
+ * Preview a new style RT animation script.
+ * Note that the RT command parser code is used, rather than the
+ * MGED command parser, because of the differences in format.
+ * The RT parser expects command handlers of the form "ged_cm_xxx()",
+ * and all communications are done via global variables.
+ *
+ * For the moment, the only preview mode is the normal one,
+ * moving the eyepoint as directed.
+ * However, as a bonus, the eye path is left behind as a vector plot.
+ */
+int
+ged_preview_core(struct ged *gedp, int argc, const char *argv[])
+{
+    static const char *usage = "[-v] [-e] [-o image_name.ext]  [-d sec_delay] 
[-D start frame] [-K last frame] rt_script_file";
+
+    FILE *fp;
+    int c;
+    vect_t temp;
+    char **vp;
+    size_t args = 0;
+    struct bu_vls extension = BU_VLS_INIT_ZERO;
+    struct bu_vls name = BU_VLS_INIT_ZERO;
+    char *dot;
+
+    GED_CHECK_DATABASE_OPEN(gedp, GED_ERROR);
+    GED_CHECK_DRAWABLE(gedp, GED_ERROR);
+    GED_CHECK_VIEW(gedp, 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;
+    }
+
+    if (argc < 2) {
+       bu_vls_printf(gedp->ged_result_str, "Usage: %s %s", argv[0], usage);
+       return GED_ERROR;
+    }
+
+    preview_delay = 0;                 /* Full speed, by default */
+    preview_mode = 1;                  /* wireframe drawing */
+    preview_desiredframe = 0;
+    preview_finalframe = 0;
+    draw_eye_path = 0;
+    _ged_current_gedp = gedp;
+    image_name = NULL;
+
+    /* Parse options */
+    bu_optind = 1;                     /* re-init bu_getopt() */
+    while ((c=bu_getopt(argc, (char * const *)argv, "d:evD:K:o:")) != -1) {
+       switch (c) {
+           case 'd':
+               preview_delay = atof(bu_optarg);
+               break;
+           case 'D':
+               preview_desiredframe = atof(bu_optarg);
+               break;
+           case 'e':
+               draw_eye_path = 1;
+               break;
+           case 'K':
+               preview_finalframe = atof(bu_optarg);
+               break;
+           case 'o':
+               image_name = bu_optarg;
+               break;
+           case 'v':
+               preview_mode = 3;       /* Like "ev" */
+               break;
+           default: {
+               bu_vls_printf(gedp->ged_result_str, "option '%c' unknown\n", c);
+               bu_vls_printf(gedp->ged_result_str, "        -d#     
inter-frame delay\n");
+               bu_vls_printf(gedp->ged_result_str, "        -e      overlay 
plot of eye path\n");
+               bu_vls_printf(gedp->ged_result_str, "        -v      polygon 
rendering (visual)\n");
+               bu_vls_printf(gedp->ged_result_str, "        -D#     desired 
starting frame\n");
+               bu_vls_printf(gedp->ged_result_str, "        -K#     final 
frame\n");
+               bu_vls_printf(gedp->ged_result_str, "        -o image_name.ext  
   output frame to file typed by extension(defaults to PIX)\n");
+               return GED_ERROR;
+           }
+
+               break;
+       }
+    }
+    argc -= bu_optind-1;
+    argv += bu_optind-1;
+
+    if ((fp = fopen(argv[1], "r")) == NULL) {
+       perror(argv[1]);
+       return GED_ERROR;
+    }
+
+    args = argc + 2 + ged_who_argc(gedp);
+    gedp->ged_gdp->gd_rt_cmd = (char **)bu_calloc(args, sizeof(char *), "alloc 
gd_rt_cmd");
+    vp = &gedp->ged_gdp->gd_rt_cmd[0];
+    *vp++ = bu_strdup("tree");
+
+    /* Build list of top-level objects in view, in 
_ged_current_gedp->ged_gdp->gd_rt_cmd[] */
+    _ged_current_gedp->ged_gdp->gd_rt_cmd_len = ged_who_argv(gedp, vp, (const 
char **)&_ged_current_gedp->ged_gdp->gd_rt_cmd[args]);
+    /* Print out the command we are about to run */
+    vp = &_ged_current_gedp->ged_gdp->gd_rt_cmd[0];
+    while ((vp != NULL) && (*vp))
+       bu_vls_printf(gedp->ged_result_str, "%s ", *vp++);
+
+    bu_vls_printf(gedp->ged_result_str, "\n");
+
+    preview_vbp = rt_vlblock_init();
+
+    bu_vls_printf(gedp->ged_result_str, "eyepoint at (0, 0, 1) viewspace\n");
+
+
+    /*
+     * Initialize the view to the current one provided by the ged
+     * structure in case a view specification is never given.
+     */
+    MAT_COPY(_ged_viewrot, gedp->ged_gvp->gv_rotation);
+    VSET(temp, 0.0, 0.0, 1.0);
+    MAT4X3PNT(_ged_eye_model, gedp->ged_gvp->gv_view2model, temp);
+
+    if (image_name) {
+       /* parse file name and possible extension */
+       if ((dot = strrchr(image_name, '.')) != (char *) NULL) {
+           bu_vls_strncpy(&name, image_name, dot - image_name);
+           bu_vls_strcpy(&extension, dot);
+       } else {
+           bu_vls_strcpy(&extension, "");
+           bu_vls_strcpy(&name, image_name);
+       }
+    }
+    while (ged_loadframe(gedp, fp) == GED_OK) {
+       if (image_name) {
+           struct bu_vls fullname = BU_VLS_INIT_ZERO;
+           const char *screengrab_args[3];
+           int screengrab_argc = 0;
+
+           screengrab_args[screengrab_argc++] = "screengrab";
+
+           bu_vls_sprintf(&fullname, "%s%05d%s", bu_vls_addr(&name),
+                          preview_currentframe, bu_vls_addr(&extension));
+           screengrab_args[screengrab_argc++] = bu_vls_addr(&fullname);
+
+           /* ged_png(gedp, screengrab_argc, screengrab_args); */
+           ged_screen_grab(gedp, screengrab_argc, screengrab_args);
+
+           bu_vls_free(&fullname);
+       }
+    }
+
+    if (image_name) {
+       bu_vls_free(&name);
+       bu_vls_free(&extension);
+    }
+
+    fclose(fp);
+    fp = NULL;
+
+    if (draw_eye_path)
+       _ged_cvt_vlblock_to_solids(gedp, preview_vbp, "EYE_PATH", 0);
+
+    if (preview_vbp) {
+       bn_vlblock_free(preview_vbp);
+       preview_vbp = (struct bn_vlblock *)NULL;
+    }
+    db_free_anim(gedp->ged_wdbp->dbip);        /* Forget any anim commands */
+
+    return GED_OK;
+}
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */

Modified: brlcad/branches/gedplugins/src/libged/editit/editit.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/editit/editit.c       2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/editit/editit.c       2020-07-22 
01:27:01 UTC (rev 76402)
@@ -41,221 +41,8 @@
 #include "ged.h"
 #include "../ged_private.h"
 
-#define WIN_EDITOR "\"c:/Program Files/Windows NT/Accessories/wordpad\""
-#define MAC_EDITOR "/Applications/TextEdit.app/Contents/MacOS/TextEdit"
-#define EMACS_EDITOR "emacs"
-#define NANO_EDITOR "nano"
-#define VIM_EDITOR "vim"
-#define VI_EDITOR "vi"
 
 int
-_ged_editit(const char *editstring, const char *filename)
-{
-#ifdef HAVE_UNISTD_H
-    int xpid = 0;
-    int status = 0;
-#endif
-    int pid = 0;
-    char **avtmp = (char **)NULL;
-    const char *terminal = (char *)NULL;
-    const char *terminal_opt = (char *)NULL;
-    const char *editor = (char *)NULL;
-    const char *editor_opt = (char *)NULL;
-    const char *file = (const char *)filename;
-
-#if defined(SIGINT) && defined(SIGQUIT)
-    void (*s2)();
-    void (*s3)();
-#endif
-
-    if (!file) {
-       bu_log("INTERNAL ERROR: editit filename missing\n");
-       return 0;
-    }
-
-    char *editstring_cpy = NULL;
-
-    /* convert the edit string into pieces suitable for arguments to execlp */
-
-    if (editstring != NULL) {
-       editstring_cpy = bu_strdup(editstring);
-       avtmp = (char **)bu_calloc(5, sizeof(char *), "ged_editit: editstring 
args");
-       bu_argv_from_string(avtmp, 4, editstring_cpy);
-
-       if (avtmp[0] && !BU_STR_EQUAL(avtmp[0], "(null)"))
-           terminal = avtmp[0];
-       if (avtmp[1] && !BU_STR_EQUAL(avtmp[1], "(null)"))
-           terminal_opt = avtmp[1];
-       if (avtmp[2] && !BU_STR_EQUAL(avtmp[2], "(null)"))
-           editor = avtmp[2];
-       if (avtmp[3] && !BU_STR_EQUAL(avtmp[3], "(null)"))
-           editor_opt = avtmp[3];
-    } else {
-       editor = getenv("EDITOR");
-
-       /* still unset? try windows */
-       if (!editor || editor[0] == '\0') {
-           if (bu_file_exists(WIN_EDITOR, NULL)) {
-               editor = WIN_EDITOR;
-           }
-       }
-
-       /* still unset? try mac os x */
-       if (!editor || editor[0] == '\0') {
-           if (bu_file_exists(MAC_EDITOR, NULL)) {
-               editor = MAC_EDITOR;
-           }
-       }
-
-       /* still unset? try emacs */
-       if (!editor || editor[0] == '\0') {
-           editor = bu_which(EMACS_EDITOR);
-       }
-
-       /* still unset? try nano */
-       if (!editor || editor[0] == '\0') {
-           editor = bu_which(NANO_EDITOR);
-       }
-
-       /* still unset? try vim */
-       if (!editor || editor[0] == '\0') {
-           editor = bu_which(VIM_EDITOR);
-       }
-
-       /* still unset? As a last resort, go with vi -
-        * vi is part of the POSIX standard, which is as
-        * close as we can get currently to an editor
-        * that should always be present:
-        * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html */
-       if (!editor || editor[0] == '\0') {
-           editor = bu_which(VI_EDITOR);
-       }
-    }
-
-    if (!editor) {
-       bu_log("INTERNAL ERROR: editit editor missing\n");
-       return 0;
-    }
-
-    /* print a message to let the user know they need to quit their
-     * editor before the application will come back to life.
-     */
-    {
-       int length;
-       struct bu_vls str = BU_VLS_INIT_ZERO;
-       struct bu_vls sep = BU_VLS_INIT_ZERO;
-       char *editor_basename;
-
-       if (terminal && editor_opt) {
-           bu_log("Invoking [%s %s %s] via %s\n\n", editor, editor_opt, file, 
terminal);
-       } else if (terminal) {
-           bu_log("Invoking [%s %s] via %s\n\n", editor, file, terminal);
-       } else if (editor_opt) {
-           bu_log("Invoking [%s %s %s]\n\n", editor, editor_opt, file);
-       } else {
-           bu_log("Invoking [%s %s]\n\n", editor, file);
-       }
-       editor_basename = bu_path_basename(editor, NULL);
-       bu_vls_sprintf(&str, "\nNOTE: You must QUIT %s before %s will respond 
and continue.\n", editor_basename, bu_getprogname());
-       for (length = bu_vls_strlen(&str) - 2; length > 0; length--) {
-           bu_vls_putc(&sep, '*');
-       }
-       bu_log("%s%s%s\n\n", bu_vls_addr(&sep), bu_vls_addr(&str), 
bu_vls_addr(&sep));
-       bu_vls_free(&str);
-       bu_vls_free(&sep);
-       bu_free(editor_basename, "editor_basename free");
-    }
-
-#if defined(SIGINT) && defined(SIGQUIT)
-    s2 = signal(SIGINT, SIG_IGN);
-    s3 = signal(SIGQUIT, SIG_IGN);
-#endif
-
-#ifdef HAVE_UNISTD_H
-    if ((pid = fork()) < 0) {
-       perror("fork");
-       return 0;
-    }
-#endif
-
-    if (pid == 0) {
-       /* Don't call bu_log() here in the child! */
-
-#if defined(SIGINT) && defined(SIGQUIT)
-       /* deja vu */
-       (void)signal(SIGINT, SIG_DFL);
-       (void)signal(SIGQUIT, SIG_DFL);
-#endif
-
-       {
-
-#if defined(_WIN32) && !defined(__CYGWIN__)
-           char buffer[RT_MAXLINE + 1] = {0};
-           STARTUPINFO si = {0};
-           PROCESS_INFORMATION pi = {0};
-           si.cb = sizeof(STARTUPINFO);
-           si.lpReserved = NULL;
-           si.lpReserved2 = NULL;
-           si.cbReserved2 = 0;
-           si.lpDesktop = NULL;
-           si.dwFlags = 0;
-
-           snprintf(buffer, RT_MAXLINE, "%s %s", editor, file);
-
-           CreateProcess(NULL, buffer, NULL, NULL, TRUE, 
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
-           WaitForSingleObject(pi.hProcess, INFINITE);
-           return 1;
-#else
-           char *editor_basename = bu_path_basename(editor, NULL);
-           if (BU_STR_EQUAL(editor_basename, "TextEdit")) {
-               /* close stdout/stderr so we don't get blather from TextEdit 
about service registration failure */
-               close(fileno(stdout));
-               close(fileno(stderr));
-           }
-           bu_free(editor_basename, "editor_basename free");
-
-           if (!terminal && !editor_opt) {
-               (void)execlp(editor, editor, file, NULL);
-           } else if (!terminal) {
-               (void)execlp(editor, editor, editor_opt, file, NULL);
-           } else if (terminal && !terminal_opt) {
-               (void)execlp(terminal, terminal, editor, file, NULL);
-           } else if (terminal && !editor_opt) {
-               (void)execlp(terminal, terminal, terminal_opt, editor, file, 
NULL);
-           } else {
-               (void)execlp(terminal, terminal, terminal_opt, editor, 
editor_opt, file, NULL);
-           }
-#endif
-           /* should not reach */
-           perror(editor);
-           bu_exit(1, NULL);
-       }
-    }
-
-#ifdef HAVE_UNISTD_H
-    /* wait for the editor to terminate */
-    while ((xpid = wait(&status)) >= 0) {
-       if (xpid == pid) {
-           break;
-       }
-    }
-#endif
-
-#if defined(SIGINT) && defined(SIGQUIT)
-    (void)signal(SIGINT, s2);
-    (void)signal(SIGQUIT, s3);
-#endif
-
-    if (editstring != NULL) {
-       bu_free((void *)avtmp, "ged_editit: avtmp");
-       bu_free(editstring_cpy, "editstring copy");
-    }
-
-    return 1;
-}
-
-
-int
 ged_editit_core(struct ged *gedp, int argc, const char *argv[])
 {
     int ret = 0;

Modified: brlcad/branches/gedplugins/src/libged/ged.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/ged.c 2020-07-22 00:38:30 UTC (rev 
76401)
+++ brlcad/branches/gedplugins/src/libged/ged.c 2020-07-22 01:27:01 UTC (rev 
76402)
@@ -51,9 +51,10 @@
 #include "./ged_private.h"
 #include "./qray.h"
 
-/* TODO
- * Ew.  Make this go away... */
+/* TODO:  Ew.  Globals. Make this go away... */
 struct ged *_ged_current_gedp;
+vect_t _ged_eye_model;
+mat_t _ged_viewrot;
 
 /* FIXME: this function should not exist.  passing pointers as strings
  * indicates a failure in design and lazy coding.

Modified: brlcad/branches/gedplugins/src/libged/ged_util.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/ged_util.c    2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/ged_util.c    2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -31,7 +31,16 @@
 #include <stdlib.h>
 #include <string.h>
 
+#ifdef HAVE_SYS_TYPES_H
+#  include <sys/types.h>
+#endif
+
+#include "bio.h"
+#include "bresource.h"
+
+
 #include "bu/app.h"
+#include "bu/file.h"
 #include "bu/path.h"
 #include "bu/sort.h"
 #include "bu/str.h"
@@ -928,8 +937,900 @@
     return vp-start;
 }
 
+void
+_ged_do_list(struct ged *gedp, struct directory *dp, int verbose)
+{
+    int id;
+    struct rt_db_internal intern;
 
+    RT_CK_DBI(gedp->ged_wdbp->dbip);
+
+    if (dp->d_major_type == DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
+       /* this is the _GLOBAL object */
+       struct bu_attribute_value_set avs;
+       struct bu_attribute_value_pair *avp;
+
+       bu_vls_strcat(gedp->ged_result_str, dp->d_namep);
+       bu_vls_strcat(gedp->ged_result_str, ": global attributes object\n");
+       bu_avs_init_empty(&avs);
+       if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
+           bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
%s\n", dp->d_namep);
+           return;
+       }
+/* !!! left off here*/
+       for (BU_AVS_FOR(avp, &avs)) {
+           if (BU_STR_EQUAL(avp->name, "units")) {
+               double conv;
+               const char *str;
+
+               conv = atof(avp->value);
+               bu_vls_strcat(gedp->ged_result_str, "\tunits: ");
+               if ((str=bu_units_string(conv)) == NULL) {
+                   bu_vls_strcat(gedp->ged_result_str, "Unrecognized units\n");
+               } else {
+                   bu_vls_strcat(gedp->ged_result_str, str);
+                   bu_vls_putc(gedp->ged_result_str, '\n');
+               }
+           } else {
+               bu_vls_putc(gedp->ged_result_str, '\t');
+               bu_vls_strcat(gedp->ged_result_str, avp->name);
+               bu_vls_strcat(gedp->ged_result_str, ": ");
+               bu_vls_strcat(gedp->ged_result_str, avp->value);
+               bu_vls_putc(gedp->ged_result_str, '\n');
+           }
+       }
+    } else {
+
+       if ((id = rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip,
+                                    (fastf_t *)NULL, &rt_uniresource)) < 0) {
+           bu_vls_printf(gedp->ged_result_str, "rt_db_get_internal(%s) 
failure\n", dp->d_namep);
+           rt_db_free_internal(&intern);
+           return;
+       }
+
+       bu_vls_printf(gedp->ged_result_str, "%s:  ", dp->d_namep);
+
+       if (!OBJ[id].ft_describe ||
+           OBJ[id].ft_describe(gedp->ged_result_str,
+                               &intern,
+                               verbose,
+                               gedp->ged_wdbp->dbip->dbi_base2local) < 0)
+           bu_vls_printf(gedp->ged_result_str, "%s: describe error\n", 
dp->d_namep);
+       rt_db_free_internal(&intern);
+    }
+}
+
+/**
+ * Once the vlist has been created, perform the common tasks
+ * in handling the drawn solid.
+ *
+ * This routine must be prepared to run in parallel.
+ */
+void
+_ged_drawH_part2(int dashflag, struct bu_list *vhead, const struct 
db_full_path *pathp, struct db_tree_state *tsp, struct _ged_client_data *dgcdp)
+{
+
+    if (dgcdp->wireframe_color_override) {
+       unsigned char wcolor[3];
+
+       wcolor[0] = (unsigned char)dgcdp->wireframe_color[0];
+       wcolor[1] = (unsigned char)dgcdp->wireframe_color[1];
+       wcolor[2] = (unsigned char)dgcdp->wireframe_color[2];
+       dl_add_path(dgcdp->gdlp, dashflag, dgcdp->transparency, dgcdp->dmode, 
dgcdp->hiddenLine, vhead, pathp, tsp, wcolor, 
dgcdp->gedp->ged_create_vlist_solid_callback, dgcdp->freesolid);
+    } else {
+       dl_add_path(dgcdp->gdlp, dashflag, dgcdp->transparency, dgcdp->dmode, 
dgcdp->hiddenLine, vhead, pathp, tsp, NULL, 
dgcdp->gedp->ged_create_vlist_solid_callback, dgcdp->freesolid);
+    }
+}
+
+void
+_ged_cvt_vlblock_to_solids(struct ged *gedp, struct bn_vlblock *vbp, const 
char *name, int copy)
+{
+    size_t i;
+    char shortname[32] = {0};
+    char namebuf[64] = {0};
+
+    bu_strlcpy(shortname, name, sizeof(shortname));
+
+    for (i = 0; i < vbp->nused; i++) {
+       if (BU_LIST_IS_EMPTY(&(vbp->head[i])))
+           continue;
+       snprintf(namebuf, 64, "%s%lx", shortname, vbp->rgb[i]);
+       invent_solid(gedp->ged_gdp->gd_headDisplay, gedp->ged_wdbp->dbip, 
gedp->ged_create_vlist_solid_callback, gedp->ged_free_vlist_callback, namebuf, 
&vbp->head[i], vbp->rgb[i], copy, 1.0, 0, gedp->freesolid, 0);
+    }
+}
+
+#define WIN_EDITOR "\"c:/Program Files/Windows NT/Accessories/wordpad\""
+#define MAC_EDITOR "/Applications/TextEdit.app/Contents/MacOS/TextEdit"
+#define EMACS_EDITOR "emacs"
+#define NANO_EDITOR "nano"
+#define VIM_EDITOR "vim"
+#define VI_EDITOR "vi"
+
+int
+_ged_editit(const char *editstring, const char *filename)
+{
+#ifdef HAVE_UNISTD_H
+    int xpid = 0;
+    int status = 0;
+#endif
+    int pid = 0;
+    char **avtmp = (char **)NULL;
+    const char *terminal = (char *)NULL;
+    const char *terminal_opt = (char *)NULL;
+    const char *editor = (char *)NULL;
+    const char *editor_opt = (char *)NULL;
+    const char *file = (const char *)filename;
+
+#if defined(SIGINT) && defined(SIGQUIT)
+    void (*s2)();
+    void (*s3)();
+#endif
+
+    if (!file) {
+       bu_log("INTERNAL ERROR: editit filename missing\n");
+       return 0;
+    }
+
+    char *editstring_cpy = NULL;
+
+    /* convert the edit string into pieces suitable for arguments to execlp */
+
+    if (editstring != NULL) {
+       editstring_cpy = bu_strdup(editstring);
+       avtmp = (char **)bu_calloc(5, sizeof(char *), "ged_editit: editstring 
args");
+       bu_argv_from_string(avtmp, 4, editstring_cpy);
+
+       if (avtmp[0] && !BU_STR_EQUAL(avtmp[0], "(null)"))
+           terminal = avtmp[0];
+       if (avtmp[1] && !BU_STR_EQUAL(avtmp[1], "(null)"))
+           terminal_opt = avtmp[1];
+       if (avtmp[2] && !BU_STR_EQUAL(avtmp[2], "(null)"))
+           editor = avtmp[2];
+       if (avtmp[3] && !BU_STR_EQUAL(avtmp[3], "(null)"))
+           editor_opt = avtmp[3];
+    } else {
+       editor = getenv("EDITOR");
+
+       /* still unset? try windows */
+       if (!editor || editor[0] == '\0') {
+           if (bu_file_exists(WIN_EDITOR, NULL)) {
+               editor = WIN_EDITOR;
+           }
+       }
+
+       /* still unset? try mac os x */
+       if (!editor || editor[0] == '\0') {
+           if (bu_file_exists(MAC_EDITOR, NULL)) {
+               editor = MAC_EDITOR;
+           }
+       }
+
+       /* still unset? try emacs */
+       if (!editor || editor[0] == '\0') {
+           editor = bu_which(EMACS_EDITOR);
+       }
+
+       /* still unset? try nano */
+       if (!editor || editor[0] == '\0') {
+           editor = bu_which(NANO_EDITOR);
+       }
+
+       /* still unset? try vim */
+       if (!editor || editor[0] == '\0') {
+           editor = bu_which(VIM_EDITOR);
+       }
+
+       /* still unset? As a last resort, go with vi -
+        * vi is part of the POSIX standard, which is as
+        * close as we can get currently to an editor
+        * that should always be present:
+        * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/vi.html */
+       if (!editor || editor[0] == '\0') {
+           editor = bu_which(VI_EDITOR);
+       }
+    }
+
+    if (!editor) {
+       bu_log("INTERNAL ERROR: editit editor missing\n");
+       return 0;
+    }
+
+    /* print a message to let the user know they need to quit their
+     * editor before the application will come back to life.
+     */
+    {
+       int length;
+       struct bu_vls str = BU_VLS_INIT_ZERO;
+       struct bu_vls sep = BU_VLS_INIT_ZERO;
+       char *editor_basename;
+
+       if (terminal && editor_opt) {
+           bu_log("Invoking [%s %s %s] via %s\n\n", editor, editor_opt, file, 
terminal);
+       } else if (terminal) {
+           bu_log("Invoking [%s %s] via %s\n\n", editor, file, terminal);
+       } else if (editor_opt) {
+           bu_log("Invoking [%s %s %s]\n\n", editor, editor_opt, file);
+       } else {
+           bu_log("Invoking [%s %s]\n\n", editor, file);
+       }
+       editor_basename = bu_path_basename(editor, NULL);
+       bu_vls_sprintf(&str, "\nNOTE: You must QUIT %s before %s will respond 
and continue.\n", editor_basename, bu_getprogname());
+       for (length = bu_vls_strlen(&str) - 2; length > 0; length--) {
+           bu_vls_putc(&sep, '*');
+       }
+       bu_log("%s%s%s\n\n", bu_vls_addr(&sep), bu_vls_addr(&str), 
bu_vls_addr(&sep));
+       bu_vls_free(&str);
+       bu_vls_free(&sep);
+       bu_free(editor_basename, "editor_basename free");
+    }
+
+#if defined(SIGINT) && defined(SIGQUIT)
+    s2 = signal(SIGINT, SIG_IGN);
+    s3 = signal(SIGQUIT, SIG_IGN);
+#endif
+
+#ifdef HAVE_UNISTD_H
+    if ((pid = fork()) < 0) {
+       perror("fork");
+       return 0;
+    }
+#endif
+
+    if (pid == 0) {
+       /* Don't call bu_log() here in the child! */
+
+#if defined(SIGINT) && defined(SIGQUIT)
+       /* deja vu */
+       (void)signal(SIGINT, SIG_DFL);
+       (void)signal(SIGQUIT, SIG_DFL);
+#endif
+
+       {
+
+#if defined(_WIN32) && !defined(__CYGWIN__)
+           char buffer[RT_MAXLINE + 1] = {0};
+           STARTUPINFO si = {0};
+           PROCESS_INFORMATION pi = {0};
+           si.cb = sizeof(STARTUPINFO);
+           si.lpReserved = NULL;
+           si.lpReserved2 = NULL;
+           si.cbReserved2 = 0;
+           si.lpDesktop = NULL;
+           si.dwFlags = 0;
+
+           snprintf(buffer, RT_MAXLINE, "%s %s", editor, file);
+
+           CreateProcess(NULL, buffer, NULL, NULL, TRUE, 
NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pi);
+           WaitForSingleObject(pi.hProcess, INFINITE);
+           return 1;
+#else
+           char *editor_basename = bu_path_basename(editor, NULL);
+           if (BU_STR_EQUAL(editor_basename, "TextEdit")) {
+               /* close stdout/stderr so we don't get blather from TextEdit 
about service registration failure */
+               close(fileno(stdout));
+               close(fileno(stderr));
+           }
+           bu_free(editor_basename, "editor_basename free");
+
+           if (!terminal && !editor_opt) {
+               (void)execlp(editor, editor, file, NULL);
+           } else if (!terminal) {
+               (void)execlp(editor, editor, editor_opt, file, NULL);
+           } else if (terminal && !terminal_opt) {
+               (void)execlp(terminal, terminal, editor, file, NULL);
+           } else if (terminal && !editor_opt) {
+               (void)execlp(terminal, terminal, terminal_opt, editor, file, 
NULL);
+           } else {
+               (void)execlp(terminal, terminal, terminal_opt, editor, 
editor_opt, file, NULL);
+           }
+#endif
+           /* should not reach */
+           perror(editor);
+           bu_exit(1, NULL);
+       }
+    }
+
+#ifdef HAVE_UNISTD_H
+    /* wait for the editor to terminate */
+    while ((xpid = wait(&status)) >= 0) {
+       if (xpid == pid) {
+           break;
+       }
+    }
+#endif
+
+#if defined(SIGINT) && defined(SIGQUIT)
+    (void)signal(SIGINT, s2);
+    (void)signal(SIGQUIT, s3);
+#endif
+
+    if (editstring != NULL) {
+       bu_free((void *)avtmp, "ged_editit: avtmp");
+       bu_free(editstring_cpy, "editstring copy");
+    }
+
+    return 1;
+}
+
+void
+_ged_rt_set_eye_model(struct ged *gedp,
+                     vect_t eye_model)
+{
+    if (gedp->ged_gvp->gv_zclip || gedp->ged_gvp->gv_perspective > 0) {
+       vect_t temp;
+
+       VSET(temp, 0.0, 0.0, 1.0);
+       MAT4X3PNT(eye_model, gedp->ged_gvp->gv_view2model, temp);
+    } else {
+       /* not doing zclipping, so back out of geometry */
+       int i;
+       vect_t direction;
+       vect_t extremum[2];
+       double t_in;
+       vect_t diag1;
+       vect_t diag2;
+       point_t ecenter;
+
+       VSET(eye_model, -gedp->ged_gvp->gv_center[MDX],
+            -gedp->ged_gvp->gv_center[MDY], -gedp->ged_gvp->gv_center[MDZ]);
+
+       for (i = 0; i < 3; ++i) {
+           extremum[0][i] = INFINITY;
+           extremum[1][i] = -INFINITY;
+       }
+
+       (void)dl_bounding_sph(gedp->ged_gdp->gd_headDisplay, &(extremum[0]), 
&(extremum[1]), 1);
+
+       VMOVEN(direction, gedp->ged_gvp->gv_rotation + 8, 3);
+       for (i = 0; i < 3; ++i)
+           if (NEAR_ZERO(direction[i], 1e-10))
+               direction[i] = 0.0;
+
+       VSUB2(diag1, extremum[1], extremum[0]);
+       VADD2(ecenter, extremum[1], extremum[0]);
+       VSCALE(ecenter, ecenter, 0.5);
+       VSUB2(diag2, ecenter, eye_model);
+       t_in = MAGNITUDE(diag1) + MAGNITUDE(diag2);
+       VJOIN1(eye_model, eye_model, t_in, direction);
+    }
+}
+
+struct _ged_rt_client_data {
+    struct ged_subprocess *rrtp;
+    struct ged *gedp;
+};
+
+void
+_ged_rt_output_handler(void *clientData, int UNUSED(mask))
+{
+    struct _ged_rt_client_data *drcdp = (struct _ged_rt_client_data 
*)clientData;
+    struct ged_subprocess *run_rtp;
+    int count = 0;
+    int retcode = 0;
+    int read_failed = 0;
+    char line[RT_MAXLINE+1] = {0};
+
+    if (drcdp == (struct _ged_rt_client_data *)NULL ||
+       drcdp->gedp == (struct ged *)NULL ||
+       drcdp->rrtp == (struct ged_subprocess *)NULL)
+       return;
+
+    run_rtp = drcdp->rrtp;
+
+    /* Get data from rt */
+    if (bu_process_read((char *)line, &count, run_rtp->p, BU_PROCESS_STDERR, 
RT_MAXLINE) <= 0) {
+       read_failed = 1;
+    }
+
+    if (read_failed) {
+       int aborted;
+
+       /* Done watching for output, undo subprocess I/O hooks. */
+       if (drcdp->gedp->ged_delete_io_handler) {
+           (*drcdp->gedp->ged_delete_io_handler)(drcdp->gedp->ged_interp, 
run_rtp->chan,
+                   run_rtp->p, BU_PROCESS_STDERR, (void *)drcdp,
+                   _ged_rt_output_handler);
+       }
+       /* Either EOF has been sent or there was a read error.
+        * there is no need to block indefinitely */
+       retcode = bu_process_wait(&aborted, run_rtp->p, 120);
+
+       if (aborted)
+           bu_log("Raytrace aborted.\n");
+       else if (retcode)
+           bu_log("Raytrace failed.\n");
+       else
+           bu_log("Raytrace complete.\n");
+
+       if (drcdp->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0)
+           drcdp->gedp->ged_gdp->gd_rtCmdNotify(aborted);
+
+       /* free run_rtp */
+       BU_LIST_DEQUEUE(&run_rtp->l);
+       BU_PUT(run_rtp, struct ged_subprocess);
+       BU_PUT(drcdp, struct _ged_rt_client_data);
+
+       return;
+    }
+
+    /* for feelgoodedness */
+    line[count] = '\0';
+
+    /* handle (i.e., probably log to stderr) the resulting line */
+    if (drcdp->gedp->ged_output_handler != (void (*)(struct ged *, char *))0)
+       drcdp->gedp->ged_output_handler(drcdp->gedp, line);
+    else
+       bu_vls_printf(drcdp->gedp->ged_result_str, "%s", line);
+}
+
+void
+_ged_rt_write(struct ged *gedp,
+             FILE *fp,
+             vect_t eye_model,
+             int argc,
+             const char **argv)
+{
+    quat_t quat;
+
+    /* Double-precision IEEE floating point only guarantees 15-17
+     * digits of precision; single-precision only 6-9 significant
+     * decimal digits.  Using a %.15e precision specifier makes our
+     * printed value dip into unreliable territory (1+15 digits).
+     * Looking through our history, %.14e seems to be safe as the
+     * value prior to printing quaternions was %.9e, although anything
+     * from 9->14 "should" be safe as it's above our calculation
+     * tolerance and above single-precision capability.
+     */
+    fprintf(fp, "viewsize %.14e;\n", gedp->ged_gvp->gv_size);
+    quat_mat2quat(quat, gedp->ged_gvp->gv_rotation);
+    fprintf(fp, "orientation %.14e %.14e %.14e %.14e;\n", V4ARGS(quat));
+    fprintf(fp, "eye_pt %.14e %.14e %.14e;\n",
+                 eye_model[X], eye_model[Y], eye_model[Z]);
+
+    fprintf(fp, "start 0; clean;\n");
+
+    /* If no objects were specified, activate all objects currently displayed.
+     * Otherwise, simply draw the specified objects. If the caller passed
+     * -1 in argc it means the objects are specified on the command line.
+     * (TODO - we shouldn't be doing that anywhere for this; long command
+     * strings make Windows unhappy.  Once all the callers have been
+     * adjusted to pass the object lists for itemization via pipes below,
+     * remove the -1 case.) */
+    if (argc >= 0) {
+       if (!argc) {
+           struct display_list *gdlp;
+           for (BU_LIST_FOR(gdlp, display_list, 
gedp->ged_gdp->gd_headDisplay)) {
+               if (((struct directory *)gdlp->dl_dp)->d_addr == 
RT_DIR_PHONY_ADDR)
+                   continue;
+               fprintf(fp, "draw %s;\n", bu_vls_addr(&gdlp->dl_path));
+           }
+       } else {
+           int i = 0;
+           while (i < argc) {
+               fprintf(fp, "draw %s;\n", argv[i++]);
+           }
+       }
+
+       fprintf(fp, "prep;\n");
+    }
+
+    dl_bitwise_and_fullpath(gedp->ged_gdp->gd_headDisplay, ~RT_DIR_USED);
+
+    dl_write_animate(gedp->ged_gdp->gd_headDisplay, fp);
+
+    dl_bitwise_and_fullpath(gedp->ged_gdp->gd_headDisplay, ~RT_DIR_USED);
+
+    fprintf(fp, "end;\n");
+}
+
+int
+_ged_run_rt(struct ged *gedp, int cmd_len, const char **gd_rt_cmd, int argc, 
const char **argv)
+{
+    FILE *fp_in;
+    vect_t eye_model;
+    struct ged_subprocess *run_rtp;
+    struct _ged_rt_client_data *drcdp;
+    struct bu_process *p = NULL;
+
+    bu_process_exec(&p, gd_rt_cmd[0], cmd_len, gd_rt_cmd, 0, 0);
+    fp_in = bu_process_open(p, BU_PROCESS_STDIN);
+
+    if (bu_process_pid(p) == -1) {
+       bu_vls_printf(gedp->ged_result_str, "\nunable to successfully launch 
subprocess: ");
+       for (int i = 0; i < cmd_len; i++) {
+           bu_vls_printf(gedp->ged_result_str, "%s ", gd_rt_cmd[i]);
+       }
+       bu_vls_printf(gedp->ged_result_str, "\n");
+       return GED_ERROR;
+    }
+
+    _ged_rt_set_eye_model(gedp, eye_model);
+    _ged_rt_write(gedp, fp_in, eye_model, argc, argv);
+
+    bu_process_close(p, BU_PROCESS_STDIN);
+
+    BU_GET(run_rtp, struct ged_subprocess);
+    BU_LIST_INIT(&run_rtp->l);
+    BU_LIST_APPEND(&gedp->gd_headSubprocess.l, &run_rtp->l);
+
+    run_rtp->p = p;
+    run_rtp->aborted = 0;
+
+    BU_GET(drcdp, struct _ged_rt_client_data);
+    drcdp->gedp = gedp;
+    drcdp->rrtp = run_rtp;
+
+    /* If we know how, set up hooks so the parent process knows to watch for 
output. */
+    if (gedp->ged_create_io_handler) {
+       (*gedp->ged_create_io_handler)(&(run_rtp->chan), p, BU_PROCESS_STDERR, 
gedp->io_mode, (void *)drcdp, _ged_rt_output_handler);
+    }
+    return GED_OK;
+}
+
+struct rt_object_selections *
+ged_get_object_selections(struct ged *gedp, const char *object_name)
+{
+    struct rt_object_selections *obj_selections;
+
+    obj_selections = (struct rt_object_selections 
*)bu_hash_get(gedp->ged_selections, (uint8_t *)object_name, 
strlen(object_name));
+
+    if (!obj_selections) {
+       BU_ALLOC(obj_selections, struct rt_object_selections);
+       obj_selections->sets = bu_hash_create(0);
+       (void)bu_hash_set(gedp->ged_selections, (uint8_t *)object_name, 
strlen(object_name), (void *)obj_selections);
+    }
+
+    return obj_selections;
+}
+
+
+struct rt_selection_set *
+ged_get_selection_set(struct ged *gedp, const char *object_name, const char 
*selection_name)
+{
+    struct rt_object_selections *obj_selections;
+    struct rt_selection_set *set;
+
+    obj_selections = ged_get_object_selections(gedp, object_name);
+    set = (struct rt_selection_set *)bu_hash_get(obj_selections->sets, 
(uint8_t *)selection_name, strlen(selection_name));
+    if (!set) {
+       BU_ALLOC(set, struct rt_selection_set);
+       BU_PTBL_INIT(&set->selections);
+       bu_hash_set(obj_selections->sets, (uint8_t *)selection_name, 
strlen(selection_name), (void *)set);
+    }
+
+    return set;
+}
+
 /*
+ * Add an instance of object 'objp' to combination 'name'.
+ * If the combination does not exist, it is created.
+ * region_flag is 1 (region), or 0 (group).
+ *
+ * Preserves the GIFT semantics.
+ */
+struct directory *
+_ged_combadd(struct ged *gedp,
+            struct directory *objp,
+            char *combname,
+            int region_flag,   /* true if adding region */
+            db_op_t relation,  /* = UNION, SUBTRACT, INTERSECT */
+            int ident,         /* "Region ID" */
+            int air            /* Air code */)
+{
+    int ac = 1;
+    const char *av[2];
+
+    av[0] = objp->d_namep;
+    av[1] = NULL;
+
+    if (_ged_combadd2(gedp, combname, ac, av, region_flag, relation, ident, 
air, NULL, 1) == GED_ERROR)
+       return RT_DIR_NULL;
+
+    /* Done changing stuff - update nref. */
+    db_update_nref(gedp->ged_wdbp->dbip, &rt_uniresource);
+
+    return db_lookup(gedp->ged_wdbp->dbip, combname, LOOKUP_QUIET);
+}
+
+
+/*
+ * Add an instance of object 'objp' to combination 'name'.
+ * If the combination does not exist, it is created.
+ * region_flag is 1 (region), or 0 (group).
+ *
+ * Preserves the GIFT semantics.
+ */
+int
+_ged_combadd2(struct ged *gedp,
+             char *combname,
+             int argc,
+             const char *argv[],
+             int region_flag,  /* true if adding region */
+             db_op_t relation, /* = UNION, SUBTRACT, INTERSECT */
+             int ident,        /* "Region ID" */
+             int air,          /* Air code */
+             matp_t m,         /* Matrix */
+             int validate      /* 1 to check if new members exist, 0 to just 
add them */)
+{
+    struct directory *dp;
+    struct directory *objp;
+    struct rt_db_internal intern;
+    struct rt_comb_internal *comb;
+    union tree *tp;
+    struct rt_tree_array *tree_list;
+    size_t node_count;
+    size_t actual_count;
+    size_t curr_count;
+    int i;
+
+    if (argc < 1)
+       return GED_ERROR;
+
+    /*
+     * Check to see if we have to create a new combination
+     */
+    if ((dp = db_lookup(gedp->ged_wdbp->dbip,  combname, LOOKUP_QUIET)) == 
RT_DIR_NULL) {
+       int flags;
+
+       if (region_flag)
+           flags = RT_DIR_REGION | RT_DIR_COMB;
+       else
+           flags = RT_DIR_COMB;
+
+       RT_DB_INTERNAL_INIT(&intern);
+       intern.idb_major_type = DB5_MAJORTYPE_BRLCAD;
+       intern.idb_type = ID_COMBINATION;
+       intern.idb_meth = &OBJ[ID_COMBINATION];
+
+       GED_DB_DIRADD(gedp, dp, combname, -1, 0, flags, (void 
*)&intern.idb_type, 0);
+
+       BU_ALLOC(comb, struct rt_comb_internal);
+       RT_COMB_INTERNAL_INIT(comb);
+
+       intern.idb_ptr = (void *)comb;
+
+       if (region_flag) {
+           comb->region_flag = 1;
+           comb->region_id = ident;
+           comb->aircode = air;
+           comb->los = gedp->ged_wdbp->wdb_los_default;
+           comb->GIFTmater = gedp->ged_wdbp->wdb_mat_default;
+           bu_vls_printf(gedp->ged_result_str, "Creating region with attrs: 
region_id=%d, ", ident);
+           if (air)
+               bu_vls_printf(gedp->ged_result_str, "air=%d, ", air);
+           bu_vls_printf(gedp->ged_result_str, "los=%d, material_id=%d\n",
+                         gedp->ged_wdbp->wdb_los_default,
+                         gedp->ged_wdbp->wdb_mat_default);
+       } else {
+           comb->region_flag = 0;
+       }
+
+       goto addmembers;
+    } else if (!(dp->d_flags & RT_DIR_COMB)) {
+       bu_vls_printf(gedp->ged_result_str, "%s exists, but is not a 
combination\n", dp->d_namep);
+       return GED_ERROR;
+    }
+
+    /* combination exists, add a new member */
+    GED_DB_GET_INTERNAL(gedp, &intern, dp, (fastf_t *)NULL, &rt_uniresource, 
0);
+
+    comb = (struct rt_comb_internal *)intern.idb_ptr;
+    RT_CK_COMB(comb);
+
+    if (region_flag && !comb->region_flag) {
+       bu_vls_printf(gedp->ged_result_str, "%s: not a region\n", dp->d_namep);
+       return GED_ERROR;
+    }
+
+addmembers:
+    if (comb->tree && db_ck_v4gift_tree(comb->tree) < 0) {
+       db_non_union_push(comb->tree, &rt_uniresource);
+       if (db_ck_v4gift_tree(comb->tree) < 0) {
+           bu_vls_printf(gedp->ged_result_str, "Cannot flatten tree for 
editing\n");
+           rt_db_free_internal(&intern);
+           return GED_ERROR;
+       }
+    }
+
+    /* make space for an extra leaf */
+    curr_count = db_tree_nleaves(comb->tree);
+    node_count = curr_count + argc;
+    tree_list = (struct rt_tree_array *)bu_calloc(node_count, sizeof(struct 
rt_tree_array), "tree list");
+
+    /* flatten tree */
+    if (comb->tree) {
+       actual_count = argc + (struct rt_tree_array 
*)db_flatten_tree(tree_list, comb->tree, OP_UNION, 1, &rt_uniresource) - 
tree_list;
+       BU_ASSERT(actual_count == node_count);
+       comb->tree = TREE_NULL;
+    }
+
+    for (i = 0; i < argc; ++i) {
+       if (validate) {
+           if ((objp = db_lookup(gedp->ged_wdbp->dbip, argv[i], LOOKUP_NOISY)) 
== RT_DIR_NULL) {
+               bu_vls_printf(gedp->ged_result_str, "skip member %s\n", 
argv[i]);
+               continue;
+           }
+       }
+
+       /* insert new member at end */
+       switch (relation) {
+       case DB_OP_INTERSECT:
+           tree_list[curr_count].tl_op = OP_INTERSECT;
+           break;
+       case DB_OP_SUBTRACT:
+           tree_list[curr_count].tl_op = OP_SUBTRACT;
+           break;
+       default:
+           if (relation != DB_OP_UNION) {
+               bu_vls_printf(gedp->ged_result_str, "unrecognized relation 
(assume UNION)\n");
+           }
+           tree_list[curr_count].tl_op = OP_UNION;
+           break;
+       }
+
+       /* make new leaf node, and insert at end of list */
+       BU_GET(tp, union tree);
+       RT_TREE_INIT(tp);
+       tree_list[curr_count].tl_tree = tp;
+       tp->tr_l.tl_op = OP_DB_LEAF;
+       tp->tr_l.tl_name = bu_strdup(argv[i]);
+       if (m) {
+           tp->tr_l.tl_mat = (matp_t)bu_malloc(sizeof(mat_t), "mat copy");
+           MAT_COPY(tp->tr_l.tl_mat, m);
+       } else {
+           tp->tr_l.tl_mat = (matp_t)NULL;
+       }
+
+       ++curr_count;
+    }
+
+    /* rebuild the tree */
+    comb->tree = (union tree *)db_mkgift_tree(tree_list, node_count, 
&rt_uniresource);
+
+    /* and finally, write it out */
+    GED_DB_PUT_INTERNAL(gedp, dp, &intern, &rt_uniresource, 0);
+
+    bu_free((char *)tree_list, "combadd: tree_list");
+
+    /* Done changing stuff - update nref. */
+    db_update_nref(gedp->ged_wdbp->dbip, &rt_uniresource);
+
+    return GED_OK;
+}
+
+void
+_ged_wait_status(struct bu_vls *logstr,
+                int status)
+{
+    int sig = status & 0x7f;
+    int core = status & 0x80;
+    int ret = status >> 8;
+
+    if (status == 0) {
+       bu_vls_printf(logstr, "Normal exit\n");
+       return;
+    }
+
+    bu_vls_printf(logstr, "Abnormal exit x%x", status);
+
+    if (core)
+       bu_vls_printf(logstr, ", core dumped");
+
+    if (sig)
+       bu_vls_printf(logstr, ", terminating signal = %d", sig);
+    else
+       bu_vls_printf(logstr, ", return (exit) code = %d", ret);
+}
+
+struct directory **
+_ged_build_dpp(struct ged *gedp,
+              const char *path) {
+    struct directory *dp;
+    struct directory **dpp;
+    int i;
+    char *begin;
+    char *end;
+    char *newstr;
+    char *list;
+    int ac;
+    const char **av;
+    const char **av_orig = NULL;
+    struct bu_vls vls = BU_VLS_INIT_ZERO;
+
+    /*
+     * First, build an array of the object's path components.
+     * We store the list in av_orig below.
+     */
+    newstr = bu_strdup(path);
+    begin = newstr;
+    while ((end = strchr(begin, '/')) != NULL) {
+       *end = '\0';
+       bu_vls_printf(&vls, "%s ", begin);
+       begin = end + 1;
+    }
+    bu_vls_printf(&vls, "%s ", begin);
+    free((void *)newstr);
+
+    list = bu_vls_addr(&vls);
+
+    if (bu_argv_from_tcl_list(list, &ac, &av_orig) != 0) {
+       bu_vls_printf(gedp->ged_result_str, "-1");
+       bu_vls_free(&vls);
+       return (struct directory **)NULL;
+    }
+
+    /* skip first element if empty */
+    av = av_orig;
+    if (*av[0] == '\0') {
+       --ac;
+       ++av;
+    }
+
+    /* ignore last element if empty */
+    if (*av[ac-1] == '\0')
+       --ac;
+
+    /*
+     * Next, we build an array of directory pointers that
+     * correspond to the object's path.
+     */
+    dpp = (struct directory **)bu_calloc(ac+1, sizeof(struct directory *), 
"_ged_build_dpp: directory pointers");
+    for (i = 0; i < ac; ++i) {
+       if ((dp = db_lookup(gedp->ged_wdbp->dbip, av[i], 0)) != RT_DIR_NULL)
+           dpp[i] = dp;
+       else {
+           /* object is not currently being displayed */
+           bu_vls_printf(gedp->ged_result_str, "-1");
+
+           bu_free((void *)dpp, "_ged_build_dpp: directory pointers");
+           bu_free((char *)av_orig, "free av_orig");
+           bu_vls_free(&vls);
+           return (struct directory **)NULL;
+       }
+    }
+
+    dpp[i] = RT_DIR_NULL;
+
+    bu_free((char *)av_orig, "free av_orig");
+    bu_vls_free(&vls);
+    return dpp;
+}
+
+/*
+ * This routine walks through the directory entry list and mallocs enough
+ * space for pointers to hold:
+ * a) all of the entries if called with an argument of 0, or
+ * b) the number of entries specified by the argument if > 0.
+ */
+struct directory **
+_ged_dir_getspace(struct db_i *dbip,
+                 int num_entries)
+{
+    struct directory *dp;
+    int i;
+    struct directory **dir_basep;
+
+    if (num_entries < 0) {
+       bu_log("dir_getspace: was passed %d, used 0\n",
+              num_entries);
+       num_entries = 0;
+    }
+    if (num_entries == 0) {
+       /* Set num_entries to the number of entries */
+       for (i = 0; i < RT_DBNHASH; i++)
+           for (dp = dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw)
+               num_entries++;
+    }
+
+    /* Allocate and cast num_entries worth of pointers */
+    dir_basep = (struct directory **) bu_malloc((num_entries+1) * 
sizeof(struct directory *),
+                                               "dir_getspace *dir[]");
+    return dir_basep;
+}
+
+
+
+/*
  * Local Variables:
  * mode: C
  * tab-width: 8

Modified: brlcad/branches/gedplugins/src/libged/how/how.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/how/how.c     2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/how/how.c     2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -92,81 +92,7 @@
 }
 
 
-struct directory **
-_ged_build_dpp(struct ged *gedp,
-              const char *path) {
-    struct directory *dp;
-    struct directory **dpp;
-    int i;
-    char *begin;
-    char *end;
-    char *newstr;
-    char *list;
-    int ac;
-    const char **av;
-    const char **av_orig = NULL;
-    struct bu_vls vls = BU_VLS_INIT_ZERO;
 
-    /*
-     * First, build an array of the object's path components.
-     * We store the list in av_orig below.
-     */
-    newstr = bu_strdup(path);
-    begin = newstr;
-    while ((end = strchr(begin, '/')) != NULL) {
-       *end = '\0';
-       bu_vls_printf(&vls, "%s ", begin);
-       begin = end + 1;
-    }
-    bu_vls_printf(&vls, "%s ", begin);
-    free((void *)newstr);
-
-    list = bu_vls_addr(&vls);
-
-    if (bu_argv_from_tcl_list(list, &ac, &av_orig) != 0) {
-       bu_vls_printf(gedp->ged_result_str, "-1");
-       bu_vls_free(&vls);
-       return (struct directory **)NULL;
-    }
-
-    /* skip first element if empty */
-    av = av_orig;
-    if (*av[0] == '\0') {
-       --ac;
-       ++av;
-    }
-
-    /* ignore last element if empty */
-    if (*av[ac-1] == '\0')
-       --ac;
-
-    /*
-     * Next, we build an array of directory pointers that
-     * correspond to the object's path.
-     */
-    dpp = (struct directory **)bu_calloc(ac+1, sizeof(struct directory *), 
"_ged_build_dpp: directory pointers");
-    for (i = 0; i < ac; ++i) {
-       if ((dp = db_lookup(gedp->ged_wdbp->dbip, av[i], 0)) != RT_DIR_NULL)
-           dpp[i] = dp;
-       else {
-           /* object is not currently being displayed */
-           bu_vls_printf(gedp->ged_result_str, "-1");
-
-           bu_free((void *)dpp, "_ged_build_dpp: directory pointers");
-           bu_free((char *)av_orig, "free av_orig");
-           bu_vls_free(&vls);
-           return (struct directory **)NULL;
-       }
-    }
-
-    dpp[i] = RT_DIR_NULL;
-
-    bu_free((char *)av_orig, "free av_orig");
-    bu_vls_free(&vls);
-    return dpp;
-}
-
-
 #ifdef GED_PLUGIN
 #include "../include/plugin.h"
 struct ged_cmd_impl how_cmd_impl = {

Modified: brlcad/branches/gedplugins/src/libged/list/list.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/list/list.c   2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/list/list.c   2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -34,71 +34,6 @@
 
 #include "../ged_private.h"
 
-
-void
-_ged_do_list(struct ged *gedp, struct directory *dp, int verbose)
-{
-    int id;
-    struct rt_db_internal intern;
-
-    RT_CK_DBI(gedp->ged_wdbp->dbip);
-
-    if (dp->d_major_type == DB5_MAJORTYPE_ATTRIBUTE_ONLY) {
-       /* this is the _GLOBAL object */
-       struct bu_attribute_value_set avs;
-       struct bu_attribute_value_pair *avp;
-
-       bu_vls_strcat(gedp->ged_result_str, dp->d_namep);
-       bu_vls_strcat(gedp->ged_result_str, ": global attributes object\n");
-       bu_avs_init_empty(&avs);
-       if (db5_get_attributes(gedp->ged_wdbp->dbip, &avs, dp)) {
-           bu_vls_printf(gedp->ged_result_str, "Cannot get attributes for 
%s\n", dp->d_namep);
-           return;
-       }
-/* !!! left off here*/
-       for (BU_AVS_FOR(avp, &avs)) {
-           if (BU_STR_EQUAL(avp->name, "units")) {
-               double conv;
-               const char *str;
-
-               conv = atof(avp->value);
-               bu_vls_strcat(gedp->ged_result_str, "\tunits: ");
-               if ((str=bu_units_string(conv)) == NULL) {
-                   bu_vls_strcat(gedp->ged_result_str, "Unrecognized units\n");
-               } else {
-                   bu_vls_strcat(gedp->ged_result_str, str);
-                   bu_vls_putc(gedp->ged_result_str, '\n');
-               }
-           } else {
-               bu_vls_putc(gedp->ged_result_str, '\t');
-               bu_vls_strcat(gedp->ged_result_str, avp->name);
-               bu_vls_strcat(gedp->ged_result_str, ": ");
-               bu_vls_strcat(gedp->ged_result_str, avp->value);
-               bu_vls_putc(gedp->ged_result_str, '\n');
-           }
-       }
-    } else {
-
-       if ((id = rt_db_get_internal(&intern, dp, gedp->ged_wdbp->dbip,
-                                    (fastf_t *)NULL, &rt_uniresource)) < 0) {
-           bu_vls_printf(gedp->ged_result_str, "rt_db_get_internal(%s) 
failure\n", dp->d_namep);
-           rt_db_free_internal(&intern);
-           return;
-       }
-
-       bu_vls_printf(gedp->ged_result_str, "%s:  ", dp->d_namep);
-
-       if (!OBJ[id].ft_describe ||
-           OBJ[id].ft_describe(gedp->ged_result_str,
-                               &intern,
-                               verbose,
-                               gedp->ged_wdbp->dbip->dbi_base2local) < 0)
-           bu_vls_printf(gedp->ged_result_str, "%s: describe error\n", 
dp->d_namep);
-       rt_db_free_internal(&intern);
-    }
-}
-
-
 int
 ged_list_core(struct ged *gedp, int argc, const char *argv[])
 {

Modified: brlcad/branches/gedplugins/src/libged/pnts_util.h
===================================================================
--- brlcad/branches/gedplugins/src/libged/pnts_util.h   2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/pnts_util.h   2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -22,6 +22,8 @@
  * utility functionality for simple Point Set (pnts) primitive operations.
  *
  */
+#ifndef LIBGED_PNT_GED_PRIVATE_H
+#define LIBGED_PNT_GED_PRIVATE_H
 
 #include "common.h"
 
@@ -34,6 +36,8 @@
 #include "ged/defines.h"
 #include "./ged_private.h"
 
+__BEGIN_DECLS
+
 GED_EXPORT extern const char *_ged_pnt_default_fmt_str(rt_pnt_type type);
 
 GED_EXPORT extern void _ged_pnt_v_set(void *point, rt_pnt_type type, char key, 
fastf_t val);
@@ -56,6 +60,10 @@
 
 GED_EXPORT extern void _ged_pnts_add(struct rt_pnts_internal *pnts, void 
*point);
 
+__END_DECLS
+
+#endif //LIBGED_PNT_GED_PRIVATE_H
+
 /*
  * Local Variables:
  * tab-width: 8

Modified: brlcad/branches/gedplugins/src/libged/rt/rt.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/rt/rt.c       2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/rt/rt.c       2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -39,226 +39,8 @@
 #include "../ged_private.h"
 
 
-struct _ged_rt_client_data {
-    struct ged_subprocess *rrtp;
-    struct ged *gedp;
-};
 
-
-void
-_ged_rt_write(struct ged *gedp,
-             FILE *fp,
-             vect_t eye_model,
-             int argc,
-             const char **argv)
-{
-    quat_t quat;
-
-    /* Double-precision IEEE floating point only guarantees 15-17
-     * digits of precision; single-precision only 6-9 significant
-     * decimal digits.  Using a %.15e precision specifier makes our
-     * printed value dip into unreliable territory (1+15 digits).
-     * Looking through our history, %.14e seems to be safe as the
-     * value prior to printing quaternions was %.9e, although anything
-     * from 9->14 "should" be safe as it's above our calculation
-     * tolerance and above single-precision capability.
-     */
-    fprintf(fp, "viewsize %.14e;\n", gedp->ged_gvp->gv_size);
-    quat_mat2quat(quat, gedp->ged_gvp->gv_rotation);
-    fprintf(fp, "orientation %.14e %.14e %.14e %.14e;\n", V4ARGS(quat));
-    fprintf(fp, "eye_pt %.14e %.14e %.14e;\n",
-                 eye_model[X], eye_model[Y], eye_model[Z]);
-
-    fprintf(fp, "start 0; clean;\n");
-
-    /* If no objects were specified, activate all objects currently displayed.
-     * Otherwise, simply draw the specified objects. If the caller passed
-     * -1 in argc it means the objects are specified on the command line.
-     * (TODO - we shouldn't be doing that anywhere for this; long command
-     * strings make Windows unhappy.  Once all the callers have been
-     * adjusted to pass the object lists for itemization via pipes below,
-     * remove the -1 case.) */
-    if (argc >= 0) {
-       if (!argc) {
-           struct display_list *gdlp;
-           for (BU_LIST_FOR(gdlp, display_list, 
gedp->ged_gdp->gd_headDisplay)) {
-               if (((struct directory *)gdlp->dl_dp)->d_addr == 
RT_DIR_PHONY_ADDR)
-                   continue;
-               fprintf(fp, "draw %s;\n", bu_vls_addr(&gdlp->dl_path));
-           }
-       } else {
-           int i = 0;
-           while (i < argc) {
-               fprintf(fp, "draw %s;\n", argv[i++]);
-           }
-       }
-
-       fprintf(fp, "prep;\n");
-    }
-
-    dl_bitwise_and_fullpath(gedp->ged_gdp->gd_headDisplay, ~RT_DIR_USED);
-
-    dl_write_animate(gedp->ged_gdp->gd_headDisplay, fp);
-
-    dl_bitwise_and_fullpath(gedp->ged_gdp->gd_headDisplay, ~RT_DIR_USED);
-
-    fprintf(fp, "end;\n");
-}
-
-
-void
-_ged_rt_set_eye_model(struct ged *gedp,
-                     vect_t eye_model)
-{
-    if (gedp->ged_gvp->gv_zclip || gedp->ged_gvp->gv_perspective > 0) {
-       vect_t temp;
-
-       VSET(temp, 0.0, 0.0, 1.0);
-       MAT4X3PNT(eye_model, gedp->ged_gvp->gv_view2model, temp);
-    } else {
-       /* not doing zclipping, so back out of geometry */
-       int i;
-       vect_t direction;
-       vect_t extremum[2];
-       double t_in;
-       vect_t diag1;
-       vect_t diag2;
-       point_t ecenter;
-
-       VSET(eye_model, -gedp->ged_gvp->gv_center[MDX],
-            -gedp->ged_gvp->gv_center[MDY], -gedp->ged_gvp->gv_center[MDZ]);
-
-       for (i = 0; i < 3; ++i) {
-           extremum[0][i] = INFINITY;
-           extremum[1][i] = -INFINITY;
-       }
-
-       (void)dl_bounding_sph(gedp->ged_gdp->gd_headDisplay, &(extremum[0]), 
&(extremum[1]), 1);
-
-       VMOVEN(direction, gedp->ged_gvp->gv_rotation + 8, 3);
-       for (i = 0; i < 3; ++i)
-           if (NEAR_ZERO(direction[i], 1e-10))
-               direction[i] = 0.0;
-
-       VSUB2(diag1, extremum[1], extremum[0]);
-       VADD2(ecenter, extremum[1], extremum[0]);
-       VSCALE(ecenter, ecenter, 0.5);
-       VSUB2(diag2, ecenter, eye_model);
-       t_in = MAGNITUDE(diag1) + MAGNITUDE(diag2);
-       VJOIN1(eye_model, eye_model, t_in, direction);
-    }
-}
-
-
-void
-_ged_rt_output_handler(void *clientData, int UNUSED(mask))
-{
-    struct _ged_rt_client_data *drcdp = (struct _ged_rt_client_data 
*)clientData;
-    struct ged_subprocess *run_rtp;
-    int count = 0;
-    int retcode = 0;
-    int read_failed = 0;
-    char line[RT_MAXLINE+1] = {0};
-
-    if (drcdp == (struct _ged_rt_client_data *)NULL ||
-       drcdp->gedp == (struct ged *)NULL ||
-       drcdp->rrtp == (struct ged_subprocess *)NULL)
-       return;
-
-    run_rtp = drcdp->rrtp;
-
-    /* Get data from rt */
-    if (bu_process_read((char *)line, &count, run_rtp->p, BU_PROCESS_STDERR, 
RT_MAXLINE) <= 0) {
-       read_failed = 1;
-    }
-
-    if (read_failed) {
-       int aborted;
-
-       /* Done watching for output, undo subprocess I/O hooks. */
-       if (drcdp->gedp->ged_delete_io_handler) {
-           (*drcdp->gedp->ged_delete_io_handler)(drcdp->gedp->ged_interp, 
run_rtp->chan,
-                   run_rtp->p, BU_PROCESS_STDERR, (void *)drcdp,
-                   _ged_rt_output_handler);
-       }
-       /* Either EOF has been sent or there was a read error.
-        * there is no need to block indefinitely */
-       retcode = bu_process_wait(&aborted, run_rtp->p, 120);
-
-       if (aborted)
-           bu_log("Raytrace aborted.\n");
-       else if (retcode)
-           bu_log("Raytrace failed.\n");
-       else
-           bu_log("Raytrace complete.\n");
-
-       if (drcdp->gedp->ged_gdp->gd_rtCmdNotify != (void (*)(int))0)
-           drcdp->gedp->ged_gdp->gd_rtCmdNotify(aborted);
-
-       /* free run_rtp */
-       BU_LIST_DEQUEUE(&run_rtp->l);
-       BU_PUT(run_rtp, struct ged_subprocess);
-       BU_PUT(drcdp, struct _ged_rt_client_data);
-
-       return;
-    }
-
-    /* for feelgoodedness */
-    line[count] = '\0';
-
-    /* handle (i.e., probably log to stderr) the resulting line */
-    if (drcdp->gedp->ged_output_handler != (void (*)(struct ged *, char *))0)
-       drcdp->gedp->ged_output_handler(drcdp->gedp, line);
-    else
-       bu_vls_printf(drcdp->gedp->ged_result_str, "%s", line);
-}
-
 int
-_ged_run_rt(struct ged *gedp, int cmd_len, const char **gd_rt_cmd, int argc, 
const char **argv)
-{
-    FILE *fp_in;
-    vect_t eye_model;
-    struct ged_subprocess *run_rtp;
-    struct _ged_rt_client_data *drcdp;
-    struct bu_process *p = NULL;
-
-    bu_process_exec(&p, gd_rt_cmd[0], cmd_len, gd_rt_cmd, 0, 0);
-    fp_in = bu_process_open(p, BU_PROCESS_STDIN);
-
-    if (bu_process_pid(p) == -1) {
-       bu_vls_printf(gedp->ged_result_str, "\nunable to successfully launch 
subprocess: ");
-       for (int i = 0; i < cmd_len; i++) {
-           bu_vls_printf(gedp->ged_result_str, "%s ", gd_rt_cmd[i]);
-       }
-       bu_vls_printf(gedp->ged_result_str, "\n");
-       return GED_ERROR;
-    }
-
-    _ged_rt_set_eye_model(gedp, eye_model);
-    _ged_rt_write(gedp, fp_in, eye_model, argc, argv);
-
-    bu_process_close(p, BU_PROCESS_STDIN);
-
-    BU_GET(run_rtp, struct ged_subprocess);
-    BU_LIST_INIT(&run_rtp->l);
-    BU_LIST_APPEND(&gedp->gd_headSubprocess.l, &run_rtp->l);
-
-    run_rtp->p = p;
-    run_rtp->aborted = 0;
-
-    BU_GET(drcdp, struct _ged_rt_client_data);
-    drcdp->gedp = gedp;
-    drcdp->rrtp = run_rtp;
-
-    /* If we know how, set up hooks so the parent process knows to watch for 
output. */
-    if (gedp->ged_create_io_handler) {
-       (*gedp->ged_create_io_handler)(&(run_rtp->chan), p, BU_PROCESS_STDERR, 
gedp->io_mode, (void *)drcdp, _ged_rt_output_handler);
-    }
-    return GED_OK;
-}
-
-
-int
 ged_rt_core(struct ged *gedp, int argc, const char *argv[])
 {
     char **vp;

Modified: brlcad/branches/gedplugins/src/libged/rtcheck/rtcheck.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/rtcheck/rtcheck.c     2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/rtcheck/rtcheck.c     2020-07-22 
01:27:01 UTC (rev 76402)
@@ -50,30 +50,6 @@
     int draw_read_failed;
 };
 
-void
-_ged_wait_status(struct bu_vls *logstr,
-                int status)
-{
-    int sig = status & 0x7f;
-    int core = status & 0x80;
-    int ret = status >> 8;
-
-    if (status == 0) {
-       bu_vls_printf(logstr, "Normal exit\n");
-       return;
-    }
-
-    bu_vls_printf(logstr, "Abnormal exit x%x", status);
-
-    if (core)
-       bu_vls_printf(logstr, ", core dumped");
-
-    if (sig)
-       bu_vls_printf(logstr, ", terminating signal = %d", sig);
-    else
-       bu_vls_printf(logstr, ", return (exit) code = %d", ret);
-}
-
 static void rtcheck_output_handler(void *clientData, int mask);
 static void rtcheck_vector_handler(void *clientData, int mask);
 

Modified: brlcad/branches/gedplugins/src/libged/select/select.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/select/select.c       2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/select/select.c       2020-07-22 
01:27:01 UTC (rev 76402)
@@ -274,39 +274,6 @@
     }
 }
 
-struct rt_object_selections *
-ged_get_object_selections(struct ged *gedp, const char *object_name)
-{
-    struct rt_object_selections *obj_selections;
-
-    obj_selections = (struct rt_object_selections 
*)bu_hash_get(gedp->ged_selections, (uint8_t *)object_name, 
strlen(object_name));
-
-    if (!obj_selections) {
-       BU_ALLOC(obj_selections, struct rt_object_selections);
-       obj_selections->sets = bu_hash_create(0);
-       (void)bu_hash_set(gedp->ged_selections, (uint8_t *)object_name, 
strlen(object_name), (void *)obj_selections);
-    }
-
-    return obj_selections;
-}
-
-struct rt_selection_set *
-ged_get_selection_set(struct ged *gedp, const char *object_name, const char 
*selection_name)
-{
-    struct rt_object_selections *obj_selections;
-    struct rt_selection_set *set;
-
-    obj_selections = ged_get_object_selections(gedp, object_name);
-    set = (struct rt_selection_set *)bu_hash_get(obj_selections->sets, 
(uint8_t *)selection_name, strlen(selection_name));
-    if (!set) {
-       BU_ALLOC(set, struct rt_selection_set);
-       BU_PTBL_INIT(&set->selections);
-       bu_hash_set(obj_selections->sets, (uint8_t *)selection_name, 
strlen(selection_name), (void *)set);
-    }
-
-    return set;
-}
-
 #ifdef GED_PLUGIN
 #include "../include/plugin.h"
 struct ged_cmd_impl select_cmd_impl = {

Modified: brlcad/branches/gedplugins/src/libged/tops/tops.c
===================================================================
--- brlcad/branches/gedplugins/src/libged/tops/tops.c   2020-07-22 00:38:30 UTC 
(rev 76401)
+++ brlcad/branches/gedplugins/src/libged/tops/tops.c   2020-07-22 01:27:01 UTC 
(rev 76402)
@@ -130,39 +130,7 @@
 }
 
 
-/*
- * This routine walks through the directory entry list and mallocs enough
- * space for pointers to hold:
- * a) all of the entries if called with an argument of 0, or
- * b) the number of entries specified by the argument if > 0.
- */
-struct directory **
-_ged_dir_getspace(struct db_i *dbip,
-                 int num_entries)
-{
-    struct directory *dp;
-    int i;
-    struct directory **dir_basep;
 
-    if (num_entries < 0) {
-       bu_log("dir_getspace: was passed %d, used 0\n",
-              num_entries);
-       num_entries = 0;
-    }
-    if (num_entries == 0) {
-       /* Set num_entries to the number of entries */
-       for (i = 0; i < RT_DBNHASH; i++)
-           for (dp = dbip->dbi_Head[i]; dp != RT_DIR_NULL; dp = dp->d_forw)
-               num_entries++;
-    }
-
-    /* Allocate and cast num_entries worth of pointers */
-    dir_basep = (struct directory **) bu_malloc((num_entries+1) * 
sizeof(struct directory *),
-                                               "dir_getspace *dir[]");
-    return dir_basep;
-}
-
-
 #ifdef GED_PLUGIN
 #include "../include/plugin.h"
 struct ged_cmd_impl tops_cmd_impl = {

Modified: brlcad/branches/gedplugins/src/libged/view/CMakeLists.txt
===================================================================
--- brlcad/branches/gedplugins/src/libged/view/CMakeLists.txt   2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/view/CMakeLists.txt   2020-07-22 
01:27:01 UTC (rev 76402)
@@ -9,6 +9,7 @@
 set(VIEW_SRCS
   aet.c
   #data_lines.c
+  center.cpp
   eye.c
   quat.c
   size.c

Modified: brlcad/branches/gedplugins/src/libged/view/center.cpp
===================================================================
--- brlcad/branches/gedplugins/src/libged/view/center.cpp       2020-07-22 
00:38:30 UTC (rev 76401)
+++ brlcad/branches/gedplugins/src/libged/view/center.cpp       2020-07-22 
01:27:01 UTC (rev 76402)
@@ -35,10 +35,10 @@
 #include <string.h>
 
 #include "../ged_private.h"
+#include "./ged_view.h"
 
-
 int
-ged_center(struct ged *gedp, int argc, const char *argv[])
+ged_center_core(struct ged *gedp, int argc, const char *argv[])
 {
     point_t center;
     static const char *usage = "[-v] | [x y z]";

This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
brlcad-commits@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to