dg_obj.c

Go to the documentation of this file.
00001 /*                        D G _ O B J . C
00002  * BRL-CAD
00003  *
00004  * Copyright (c) 1997-2006 United States Government as represented by
00005  * the U.S. Army Research Laboratory.
00006  *
00007  * This library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU Lesser General Public License
00009  * as published by the Free Software Foundation; either version 2 of
00010  * the License, or (at your option) any later version.
00011  *
00012  * This library is distributed in the hope that it will be useful, but
00013  * WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015  * Library General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU Lesser General Public
00018  * License along with this file; see the file named COPYING for more
00019  * information.
00020  */
00021 
00022 /** @addtogroup librt */
00023 /*@{*/
00024 /** @file dg_obj.c
00025  * A drawable geometry object contains methods and attributes
00026  * for preparing geometry that is ready (i.e. vlists) for
00027  * display. Much of this code was extracted from MGED and modified
00028  * to work herein.
00029  *
00030  * Source -
00031  *      SLAD CAD Team
00032  *      The U. S. Army Research Laboratory
00033  *      Aberdeen Proving Ground, Maryland  21005
00034  *
00035  * Authors -
00036  *      Robert G. Parker
00037  *
00038  *  Source -
00039  *      The U. S. Army Research Laboratory
00040  *      Aberdeen Proving Ground, Maryland  21005-5068  USA
00041  */
00042 
00043 #include "common.h"
00044 
00045 #include <stdlib.h>
00046 #include <stdio.h>
00047 #ifdef HAVE_STRING_H
00048 #  include <string.h>
00049 #else
00050 #  include <strings.h>
00051 #endif
00052 #include <fcntl.h>
00053 #include <math.h>
00054 #include <signal.h>
00055 #ifdef HAVE_SYS_TYPES_H
00056 #  include <sys/types.h>
00057 #endif
00058 #ifdef HAVE_SYS_WAIT_H
00059 #  include <sys/wait.h>
00060 #endif
00061 #ifdef HAVE_UNISTD_H
00062 #  include <unistd.h>
00063 #endif
00064 
00065 #include "machine.h"
00066 #include "tcl.h"
00067 #include "cmd.h"                        /* includes bu.h */
00068 #include "vmath.h"
00069 #include "bn.h"
00070 #include "mater.h"
00071 #include "raytrace.h"
00072 #include "rtgeom.h"
00073 #include "solid.h"
00074 #include "plot3.h"
00075 
00076 
00077 struct dg_client_data {
00078         struct dg_obj           *dgop;
00079         Tcl_Interp              *interp;
00080         int                     wireframe_color_override;
00081         int                     wireframe_color[3];
00082         int                     draw_nmg_only;
00083         int                     nmg_triangulate;
00084         int                     draw_wireframes;
00085         int                     draw_normals;
00086         int                     draw_solid_lines_only;
00087         int                     draw_no_surfaces;
00088         int                     shade_per_vertex_normals;
00089         int                     draw_edge_uses;
00090         int                     fastpath_count;                 /* statistics */
00091         int                     do_not_draw_nmg_solids_during_debugging;
00092         struct bn_vlblock       *draw_edge_uses_vbp;
00093         int                     shaded_mode_override;
00094         fastf_t                 transparency;
00095         int                     dmode;
00096 };
00097 
00098 struct dg_rt_client_data {
00099     struct run_rt       *rrtp;
00100     struct dg_obj       *dgop;
00101     Tcl_Interp          *interp;
00102 };
00103 
00104 #define DGO_WIREFRAME 0
00105 #define DGO_SHADED_MODE_BOTS 1
00106 #define DGO_SHADED_MODE_ALL 2
00107 #define DGO_BOOL_EVAL 3
00108 static union tree *
00109 dgo_bot_check_region_end(register struct db_tree_state *tsp,
00110                          struct db_full_path    *pathp,
00111                          union tree             *curtree,
00112                          genptr_t               client_data);
00113 static union tree *
00114 dgo_bot_check_leaf(struct db_tree_state         *tsp,
00115                    struct db_full_path          *pathp,
00116                    struct rt_db_internal        *ip,
00117                    genptr_t                     client_data);
00118 
00119 int dgo_shaded_mode_cmd();
00120 static int dgo_how_tcl();
00121 static int dgo_set_outputHandler_tcl();
00122 static int dgo_set_uplotOutputMode_tcl();
00123 static int dgo_set_transparency_tcl();
00124 static int dgo_shaded_mode_tcl();
00125 
00126 #include "./debug.h"
00127 
00128 #define DGO_CHECK_WDBP_NULL(_dgop,_interp) \
00129         if (_dgop->dgo_wdbp == RT_WDB_NULL) \
00130         { \
00131                 Tcl_AppendResult(_interp, "Not associated with a database!\n", (char *)NULL); \
00132                 return TCL_ERROR; \
00133         }
00134 
00135 /*
00136  *  It is expected that entries on this mater list will be sorted
00137  *  in strictly ascending order, with no overlaps (ie, monotonicly
00138  *  increasing).
00139  */
00140 extern struct mater *rt_material_head;  /* now defined in librt/mater.c */
00141 
00142 /* declared in vdraw.c */
00143 extern struct bu_cmdtab vdraw_cmds[];
00144 
00145 /* declared in qray.c */
00146 extern int      dgo_qray_cmd(struct dg_obj *dgop, Tcl_Interp *interp, int argc, char **argv);
00147 extern void     dgo_init_qray(struct dg_obj *dgop);
00148 extern void     dgo_free_qray(struct dg_obj *dgop);
00149 
00150 int dgo_cmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00151 
00152 static int dgo_open_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00153 static int dgo_headSolid_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00154 static int dgo_illum_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00155 static int dgo_label_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00156 static int dgo_draw_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00157 static int dgo_ev_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00158 static int dgo_erase_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00159 static int dgo_erase_all_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00160 static int dgo_who_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00161 static int dgo_rt_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00162 static int dgo_rtabort_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00163 static int dgo_vdraw_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00164 static int dgo_overlay_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00165 static int dgo_get_autoview_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00166 static int dgo_get_eyemodel_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00167 static int dgo_zap_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00168 static int dgo_blast_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00169 static int dgo_assoc_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00170 static int dgo_rtcheck_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00171 static int dgo_observer_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00172 static int dgo_report_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00173 extern int dgo_E_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00174 static int dgo_autoview_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00175 static int dgo_qray_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00176 static int dgo_nirt_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00177 static int dgo_vnirt_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv);
00178 
00179 static union tree *dgo_wireframe_region_end(register struct db_tree_state *tsp, struct db_full_path *pathp, union tree *curtree, genptr_t client_data);
00180 static union tree *dgo_wireframe_leaf(struct db_tree_state *tsp, struct db_full_path *pathp, struct rt_db_internal *ip, genptr_t client_data);
00181 static int dgo_drawtrees(struct dg_obj *dgop, Tcl_Interp *interp, int argc, char **argv, int kind, struct dg_client_data *_dgcdp);
00182 int dgo_invent_solid(struct dg_obj *dgop, Tcl_Interp *interp, char *name, struct bu_list *vhead, long int rgb, int copy, fastf_t transparency, int dmode);
00183 static void dgo_bound_solid(Tcl_Interp *interp, register struct solid *sp);
00184 void dgo_drawH_part2(int dashflag, struct bu_list *vhead, struct db_full_path *pathp, struct db_tree_state *tsp, struct solid *existing_sp, struct dg_client_data *dgcdp);
00185 void dgo_eraseobjpath(struct dg_obj *dgop, Tcl_Interp *interp, int argc, char **argv, int noisy, int all);
00186 static void dgo_eraseobjall(struct dg_obj *dgop, Tcl_Interp *interp, register struct directory **dpp);
00187 static void dgo_eraseobj(struct dg_obj *dgop, Tcl_Interp *interp, register struct directory **dpp);
00188 void dgo_color_soltab(struct solid *hsp);
00189 static int dgo_run_rt(struct dg_obj *dgop, struct view_obj *vop);
00190 static void dgo_rt_write(struct dg_obj *dgop, struct view_obj *vop, FILE *fp, fastf_t *eye_model);
00191 static void dgo_rt_set_eye_model(struct dg_obj *dgop, struct view_obj *vop, fastf_t *eye_model);
00192 void dgo_cvt_vlblock_to_solids(struct dg_obj *dgop, Tcl_Interp *interp, struct bn_vlblock *vbp, char *name, int copy);
00193 int dgo_build_tops(Tcl_Interp *interp, struct solid *hsp, char **start, register char **end);
00194 void dgo_pr_wait_status(Tcl_Interp *interp, int status);
00195 
00196 static void dgo_print_schain(struct dg_obj *dgop, Tcl_Interp *interp, int lvl);
00197 static void dgo_print_schain_vlcmds(struct dg_obj *dgop, Tcl_Interp *interp);
00198 
00199 struct dg_obj HeadDGObj;        /* head of drawable geometry object list */
00200 static struct solid FreeSolid;          /* head of free solid list */
00201 
00202 
00203 static struct bu_cmdtab dgo_cmds[] = {
00204         {"assoc",               dgo_assoc_tcl},
00205         {"autoview",            dgo_autoview_tcl},
00206         {"blast",               dgo_blast_tcl},
00207         {"clear",               dgo_zap_tcl},
00208 #if 0
00209         {"close",               dgo_close_tcl},
00210 #endif
00211         {"draw",                dgo_draw_tcl},
00212         {"E",                   dgo_E_tcl},
00213         {"erase",               dgo_erase_tcl},
00214         {"erase_all",           dgo_erase_all_tcl},
00215         {"ev",                  dgo_ev_tcl},
00216         {"get_autoview",        dgo_get_autoview_tcl},
00217         {"get_eyemodel",        dgo_get_eyemodel_tcl},
00218         {"headSolid",           dgo_headSolid_tcl},
00219         {"how",                 dgo_how_tcl},
00220         {"illum",               dgo_illum_tcl},
00221         {"label",               dgo_label_tcl},
00222         {"nirt",                dgo_nirt_tcl},
00223         {"observer",            dgo_observer_tcl},
00224         {"overlay",             dgo_overlay_tcl},
00225         {"qray",                dgo_qray_tcl},
00226         {"report",              dgo_report_tcl},
00227         {"rt",                  dgo_rt_tcl},
00228         {"rtabort",             dgo_rtabort_tcl},
00229         {"rtcheck",             dgo_rtcheck_tcl},
00230         {"rtedge",              dgo_rt_tcl},
00231         {"set_outputHandler",   dgo_set_outputHandler_tcl},
00232         {"set_uplotOutputMode", dgo_set_uplotOutputMode_tcl},
00233         {"set_transparency",    dgo_set_transparency_tcl},
00234         {"shaded_mode",         dgo_shaded_mode_tcl},
00235 #if 0
00236         {"tol",                 dgo_tol_tcl},
00237 #endif
00238         {"vdraw",               dgo_vdraw_tcl},
00239         {"vnirt",               dgo_vnirt_tcl},
00240         {"who",                 dgo_who_tcl},
00241         {"zap",                 dgo_zap_tcl},
00242         {(char *)0,             (int (*)())0}
00243 };
00244 
00245 /*
00246  *                      D G O _ C M D
00247  *
00248  * Generic interface for drawable geometry objects.
00249  * Usage:
00250  *        procname cmd ?args?
00251  *
00252  * Returns: result of dbo command.
00253  */
00254 int
00255 dgo_cmd(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00256 {
00257         return bu_cmd(clientData, interp, argc, argv, dgo_cmds, 1);
00258 }
00259 
00260 int
00261 Dgo_Init(Tcl_Interp *interp)
00262 {
00263         BU_LIST_INIT(&HeadDGObj.l);
00264         BU_LIST_INIT(&FreeSolid.l);
00265 
00266         (void)Tcl_CreateCommand(interp, "dg_open", (Tcl_CmdProc *)dgo_open_tcl, (ClientData)NULL, (Tcl_CmdDeleteProc *)NULL);
00267 
00268         return TCL_OK;
00269 }
00270 
00271 /*
00272  * Called by Tcl when the object is destroyed.
00273  */
00274 void
00275 dgo_deleteProc(ClientData clientData)
00276 {
00277         struct dg_obj *dgop = (struct dg_obj *)clientData;
00278 
00279         /* free observers */
00280         bu_observer_free(&dgop->dgo_observers);
00281 
00282         /*
00283          * XXX Do something for the case where the drawable geometry
00284          * XXX object is deleted and the object has forked rt processes.
00285          * XXX This will create a memory leak.
00286          */
00287 
00288 
00289         bu_vls_free(&dgop->dgo_name);
00290         dgo_free_qray(dgop);
00291 
00292         BU_LIST_DEQUEUE(&dgop->l);
00293         bu_free((genptr_t)dgop, "dgo_deleteProc: dgop");
00294 }
00295 
00296 #if 0
00297 /*
00298  * Close a drawable geometry object.
00299  *
00300  * USAGE:
00301  *        procname close
00302  */
00303 static int
00304 dgo_close_tcl(clientData, interp, argc, argv)
00305      ClientData clientData;
00306      Tcl_Interp *interp;
00307      int     argc;
00308      char    **argv;
00309 {
00310         struct bu_vls vls;
00311         struct dg_obj *dgop = (struct dg_obj *)clientData;
00312 
00313         if (argc != 2) {
00314                 bu_vls_init(&vls);
00315                 bu_vls_printf(&vls, "helplib dgo_close");
00316                 Tcl_Eval(interp, bu_vls_addr(&vls));
00317                 bu_vls_free(&vls);
00318                 return TCL_ERROR;
00319         }
00320 
00321         /* Among other things, this will call dgo_deleteProc. */
00322         Tcl_DeleteCommand(interp, bu_vls_addr(&dgop->dgo_name));
00323 
00324         return TCL_OK;
00325 }
00326 #endif
00327 
00328 /*
00329  * Create an command/object named "oname" in "interp".
00330  */
00331 struct dg_obj *
00332 dgo_open_cmd(char               *oname,
00333              struct rt_wdb      *wdbp)
00334 {
00335         struct dg_obj *dgop;
00336 
00337         BU_GETSTRUCT(dgop,dg_obj);
00338 
00339         /* initialize dg_obj */
00340         bu_vls_init(&dgop->dgo_name);
00341         bu_vls_strcpy(&dgop->dgo_name, oname);
00342         dgop->dgo_wdbp = wdbp;
00343         BU_LIST_INIT(&dgop->dgo_headSolid);
00344         BU_LIST_INIT(&dgop->dgo_headVDraw);
00345         BU_LIST_INIT(&dgop->dgo_observers.l);
00346         BU_LIST_INIT(&dgop->dgo_headRunRt.l);
00347         dgop->dgo_freeSolids = &FreeSolid;
00348         dgop->dgo_uplotOutputMode = PL_OUTPUT_MODE_BINARY;
00349 
00350         dgo_init_qray(dgop);
00351 
00352         /* append to list of dg_obj's */
00353         BU_LIST_APPEND(&HeadDGObj.l,&dgop->l);
00354 
00355         return dgop;
00356 }
00357 
00358 /*
00359  * Open/create a drawable geometry object that's associated with the
00360  * database object "rt_wdb".
00361  *
00362  * USAGE:
00363  *        dgo_open [name rt_wdb]
00364  */
00365 static int
00366 dgo_open_tcl(ClientData clientData,
00367              Tcl_Interp *interp,
00368              int        argc,
00369              char       **argv)
00370 {
00371         struct dg_obj *dgop;
00372         struct rt_wdb *wdbp;
00373         struct bu_vls vls;
00374 
00375         if (argc == 1) {
00376                 /* get list of drawable geometry objects */
00377                 for (BU_LIST_FOR(dgop, dg_obj, &HeadDGObj.l))
00378                         Tcl_AppendResult(interp, bu_vls_addr(&dgop->dgo_name), " ", (char *)NULL);
00379 
00380                 return TCL_OK;
00381         }
00382 
00383         if (argc != 3) {
00384                 bu_vls_init(&vls);
00385                 bu_vls_printf(&vls, "helplib dgo_open");
00386                 Tcl_Eval(interp, bu_vls_addr(&vls));
00387                 bu_vls_free(&vls);
00388                 return TCL_ERROR;
00389         }
00390 
00391         /* search for database object */
00392         for (BU_LIST_FOR(wdbp, rt_wdb, &rt_g.rtg_headwdb.l)) {
00393                 if (strcmp(bu_vls_addr(&wdbp->wdb_name), argv[2]) == 0)
00394                         break;
00395         }
00396 
00397         if (BU_LIST_IS_HEAD(wdbp, &rt_g.rtg_headwdb.l))
00398                 wdbp = RT_WDB_NULL;
00399 
00400         /* first, delete any commands by this name */
00401         (void)Tcl_DeleteCommand(interp, argv[1]);
00402 
00403         dgop = dgo_open_cmd(argv[1], wdbp);
00404         (void)Tcl_CreateCommand(interp,
00405                                 bu_vls_addr(&dgop->dgo_name),
00406                                 (Tcl_CmdProc *)dgo_cmd,
00407                                 (ClientData)dgop,
00408                                 dgo_deleteProc);
00409 
00410         /* Return new function name as result */
00411         Tcl_ResetResult(interp);
00412         Tcl_AppendResult(interp, bu_vls_addr(&dgop->dgo_name), (char *)NULL);
00413 
00414         return TCL_OK;
00415 }
00416 
00417 /****************** Drawable Geometry Object Methods ********************/
00418 
00419 #if 0
00420 /* skeleton functions for dg_obj methods */
00421 int
00422 dgo__cmd(struct dg_obj  *dgop,
00423          Tcl_Interp     *interp,
00424          int            argc,
00425          char           **argv)
00426 {
00427 }
00428 
00429 /*
00430  * Usage:
00431  *        procname
00432  */
00433 static int
00434 dgo__tcl(ClientData     clientData,
00435          Tcl_Interp     *interp,
00436          int            argc,
00437          char           **argv)
00438 {
00439         struct dg_obj *dgop = (struct dg_obj *)clientData;
00440 
00441         return dgo__cmd(dgop, interp, argc-1, argv+1);
00442 }
00443 #endif
00444 
00445 /*
00446  *
00447  * Usage:
00448  *        procname headSolid
00449  *
00450  * Returns: database object's headSolid.
00451  */
00452 static int
00453 dgo_headSolid_tcl(ClientData    clientData,
00454                   Tcl_Interp    *interp,
00455                   int           argc,
00456                   char          **argv)
00457 {
00458         struct dg_obj *dgop = (struct dg_obj *)clientData;
00459         struct bu_vls vls;
00460 
00461         bu_vls_init(&vls);
00462 
00463         if (argc != 2) {
00464                 bu_vls_printf(&vls, "helplib_alias dgo_headSolid %s", argv[0]);
00465                 Tcl_Eval(interp, bu_vls_addr(&vls));
00466                 bu_vls_free(&vls);
00467                 return TCL_ERROR;
00468         }
00469 
00470         bu_vls_printf(&vls, "%lu", (unsigned long)&dgop->dgo_headSolid);
00471         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
00472         bu_vls_free(&vls);
00473         return TCL_OK;
00474 }
00475 
00476 int
00477 dgo_illum_cmd(struct dg_obj     *dgop,
00478               Tcl_Interp        *interp,
00479               int               argc,
00480               char              **argv)
00481 {
00482         register struct solid *sp;
00483         struct bu_vls vls;
00484         int found = 0;
00485         int illum = 1;
00486 
00487         if (argc == 3) {
00488                 if (argv[1][0] == '-' && argv[1][1] == 'n')
00489                         illum = 0;
00490                 else
00491                         goto bad;
00492 
00493                 --argc;
00494                 ++argv;
00495         }
00496 
00497         if (argc != 2)
00498                 goto bad;
00499 
00500         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
00501                 register int i;
00502 
00503                 for (i = 0; i < sp->s_fullpath.fp_len; ++i) {
00504                         if (*argv[1] == *DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_namep &&
00505                             strcmp(argv[1], DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_namep) == 0) {
00506                                 found = 1;
00507                                 if (illum)
00508                                         sp->s_iflag = UP;
00509                                 else
00510                                         sp->s_iflag = DOWN;
00511                         }
00512                 }
00513         }
00514 
00515         if (!found) {
00516                 bu_vls_init(&vls);
00517                 bu_vls_printf(&vls, "illum: %s not found", argv[1]);
00518                 Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
00519                 bu_vls_free(&vls);
00520                 return TCL_ERROR;
00521         }
00522 
00523         return TCL_OK;
00524 
00525 bad:
00526         bu_vls_init(&vls);
00527         bu_vls_printf(&vls, "helplib_alias dgo_illum %s", argv[0]);
00528         Tcl_Eval(interp, bu_vls_addr(&vls));
00529         bu_vls_free(&vls);
00530         return TCL_ERROR;
00531 }
00532 
00533 /*
00534  * Illuminate/highlight database object
00535  *
00536  * Usage:
00537  *        procname illum [-n] obj
00538  *
00539  */
00540 static int
00541 dgo_illum_tcl(ClientData        clientData,
00542               Tcl_Interp        *interp,
00543               int               argc,
00544               char              **argv)
00545 {
00546         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00547         int             ret;
00548 
00549         DGO_CHECK_WDBP_NULL(dgop,interp);
00550 
00551         if ((ret = dgo_illum_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
00552                 dgo_notify(dgop, interp);
00553 
00554         return ret;
00555 }
00556 
00557 int
00558 dgo_label_cmd(struct dg_obj     *dgop,
00559               Tcl_Interp        *interp,
00560               int               argc,
00561               char              **argv)
00562 {
00563         /* not yet implemented */
00564 
00565         return TCL_OK;
00566 }
00567 
00568 /*
00569  * Label database objects.
00570  *
00571  * Usage:
00572  *        procname label [-n] obj
00573  *
00574  */
00575 static int
00576 dgo_label_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00577 {
00578         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00579 
00580         DGO_CHECK_WDBP_NULL(dgop,interp);
00581 
00582         return dgo_label_cmd(dgop, interp, argc-1, argv+1);
00583 }
00584 
00585 int
00586 dgo_draw_cmd(struct dg_obj      *dgop,
00587              Tcl_Interp         *interp,
00588              int                argc,
00589              char               **argv,
00590              int                kind)
00591 {
00592         if (argc < 2) {
00593                 struct bu_vls vls;
00594 
00595                 bu_vls_init(&vls);
00596 
00597                 switch (kind) {
00598                 default:
00599                 case 1:
00600                         bu_vls_printf(&vls, "helplib_alias dgo_draw %s", argv[0]);
00601                         break;
00602                 case 2:
00603                         bu_vls_printf(&vls, "helplib_alias dgo_E %s", argv[0]);
00604                         break;
00605                 case 3:
00606                         bu_vls_printf(&vls, "helplib_alias dgo_ev %s", argv[0]);
00607                         break;
00608                 }
00609 
00610                 Tcl_Eval(interp, bu_vls_addr(&vls));
00611                 bu_vls_free(&vls);
00612 
00613                 return TCL_ERROR;
00614         }
00615 
00616         /* skip past cmd */
00617         --argc;
00618         ++argv;
00619 
00620         /*  First, delete any mention of these objects.
00621          *  Silently skip any leading options (which start with minus signs).
00622          */
00623         dgo_eraseobjpath(dgop, interp, argc, argv, LOOKUP_QUIET, 0);
00624 
00625         dgo_drawtrees(dgop, interp, argc, argv, kind, (struct dg_client_data *)0);
00626 
00627         dgo_color_soltab((struct solid *)&dgop->dgo_headSolid);
00628 
00629         return TCL_OK;
00630 }
00631 
00632 /*
00633  * Prepare database objects for drawing.
00634  *
00635  * Usage:
00636  *        procname draw|ev [args]
00637  *
00638  */
00639 static int
00640 dgo_draw_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00641 {
00642         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00643         int             ret;
00644 
00645         DGO_CHECK_WDBP_NULL(dgop,interp);
00646 
00647         if ((ret = dgo_draw_cmd(dgop, interp, argc-1, argv+1, 1)) == TCL_OK)
00648                 dgo_notify(dgop, interp);
00649 
00650         return ret;
00651 }
00652 
00653 /*
00654  * Prepare database objects for drawing.
00655  *
00656  * Usage:
00657  *        procname ev [args]
00658  *
00659  */
00660 static int
00661 dgo_ev_tcl(ClientData   clientData,
00662            Tcl_Interp   *interp,
00663            int          argc,
00664            char         **argv)
00665 {
00666         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00667         int             ret;
00668 
00669         DGO_CHECK_WDBP_NULL(dgop,interp);
00670 
00671         if ((ret = dgo_draw_cmd(dgop, interp, argc-1, argv+1, 3)) == TCL_OK)
00672                 dgo_notify(dgop, interp);
00673 
00674         return ret;
00675 }
00676 
00677 int
00678 dgo_erase_cmd(struct dg_obj     *dgop,
00679               Tcl_Interp        *interp,
00680               int               argc,
00681               char              **argv)
00682 {
00683 
00684         if (argc < 2) {
00685                 struct bu_vls vls;
00686 
00687                 bu_vls_init(&vls);
00688                 bu_vls_printf(&vls, "helplib_alias dgo_erase %s", argv[0]);
00689                 Tcl_Eval(interp, bu_vls_addr(&vls));
00690                 bu_vls_free(&vls);
00691                 return TCL_ERROR;
00692         }
00693 
00694         dgo_eraseobjpath(dgop, interp, argc-1, argv+1, LOOKUP_NOISY, 0);
00695 
00696         return TCL_OK;
00697 }
00698 
00699 /*
00700  * Erase database objects.
00701  *
00702  * Usage:
00703  *        procname erase object(s)
00704  *
00705  */
00706 static int
00707 dgo_erase_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00708 {
00709         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00710         int             ret;
00711 
00712         DGO_CHECK_WDBP_NULL(dgop,interp);
00713 
00714         if ((ret = dgo_erase_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
00715                 dgo_notify(dgop, interp);
00716 
00717         return ret;
00718 }
00719 
00720 int
00721 dgo_erase_all_cmd(struct dg_obj *dgop,
00722                   Tcl_Interp    *interp,
00723                   int           argc,
00724                   char          **argv)
00725 {
00726         if (argc < 2) {
00727                 struct bu_vls vls;
00728 
00729                 bu_vls_init(&vls);
00730                 bu_vls_printf(&vls, "helplib_alias dgo_erase_all %s", argv[0]);
00731                 Tcl_Eval(interp, bu_vls_addr(&vls));
00732                 bu_vls_free(&vls);
00733                 return TCL_ERROR;
00734         }
00735 
00736         dgo_eraseobjpath(dgop, interp, argc-1, argv+1, LOOKUP_NOISY, 1);
00737 
00738         return TCL_OK;
00739 }
00740 
00741 /*
00742  * Usage:
00743  *        procname erase_all object(s)
00744  */
00745 static int
00746 dgo_erase_all_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00747 {
00748         struct dg_obj   *dgop = (struct dg_obj *)clientData;
00749         int             ret;
00750 
00751         DGO_CHECK_WDBP_NULL(dgop,interp);
00752 
00753         if ((ret = dgo_erase_all_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
00754                 dgo_notify(dgop, interp);
00755 
00756         return ret;
00757 }
00758 
00759 struct directory **
00760 dgo_build_dpp(struct dg_obj     *dgop,
00761               Tcl_Interp        *interp,
00762               char              *path) {
00763         register struct directory *dp;
00764         struct directory **dpp;
00765         int i;
00766         char *begin;
00767         char *end;
00768         char *newstr;
00769         char *list;
00770         int ac;
00771         const char **av;
00772         const char **av_orig = NULL;
00773         struct bu_vls vls;
00774 
00775         bu_vls_init(&vls);
00776 
00777         /*
00778          * First, build an array of the object's path components.
00779          * We store the list in av_orig below.
00780          */
00781         newstr = strdup(path);
00782         begin = newstr;
00783         while ((end = strchr(begin, '/')) != NULL) {
00784           *end = '\0';
00785           bu_vls_printf(&vls, "%s ", begin);
00786           begin = end + 1;
00787         }
00788         bu_vls_printf(&vls, "%s ", begin);
00789         free((void *)newstr);
00790 
00791         list = bu_vls_addr(&vls);
00792 
00793         if (Tcl_SplitList((Tcl_Interp *)interp, list, &ac, &av_orig) != TCL_OK) {
00794           Tcl_AppendResult(interp, "-1", (char *)NULL);
00795           bu_vls_free(&vls);
00796           return (struct directory **)NULL;
00797         }
00798 
00799         /* skip first element if empty */
00800         av = av_orig;
00801         if (*av[0] == '\0') {
00802           --ac;
00803           ++av;
00804         }
00805 
00806         /* ignore last element if empty */
00807         if (*av[ac-1] == '\0')
00808           --ac;
00809 
00810         /*
00811          * Next, we build an array of directory pointers that
00812          * correspond to the object's path.
00813          */
00814         dpp = bu_calloc(ac+1, sizeof(struct directory *), "dgo_build_dpp: directory pointers");
00815         for (i = 0; i < ac; ++i) {
00816           if ((dp = db_lookup(dgop->dgo_wdbp->dbip, av[i], 0)) != DIR_NULL)
00817             dpp[i] = dp;
00818           else {
00819             /* object is not currently being displayed */
00820             Tcl_AppendResult(interp, "-1", (char *)NULL);
00821 
00822             bu_free((genptr_t)dpp, "dgo_build_dpp: directory pointers");
00823             Tcl_Free((char *)av_orig);
00824             bu_vls_free(&vls);
00825             return (struct directory **)NULL;
00826           }
00827         }
00828 
00829         dpp[i] = DIR_NULL;
00830 
00831         Tcl_Free((char *)av_orig);
00832         bu_vls_free(&vls);
00833         return dpp;
00834 }
00835 
00836 int
00837 dgo_how_cmd(struct dg_obj       *dgop,
00838             Tcl_Interp          *interp,
00839             int                 argc,
00840             char                **argv)
00841 {
00842         register struct solid *sp;
00843         struct bu_vls vls;
00844         int i;
00845         struct directory **dpp;
00846         register struct directory **tmp_dpp;
00847         int both = 0;
00848 
00849         bu_vls_init(&vls);
00850 
00851         if (argc < 2 || 3 < argc) {
00852                 bu_vls_printf(&vls, "helplib_alias dgo_how %s", argv[0]);
00853                 Tcl_Eval(interp, bu_vls_addr(&vls));
00854                 bu_vls_free(&vls);
00855                 return TCL_ERROR;
00856         }
00857 
00858         if (argc == 3 &&
00859             argv[1][0] == '-' &&
00860             argv[1][1] == 'b') {
00861             both = 1;
00862 
00863             if ((dpp = dgo_build_dpp(dgop, interp, argv[2])) == NULL)
00864                 goto good;
00865         } else {
00866             if ((dpp = dgo_build_dpp(dgop, interp, argv[1])) == NULL)
00867                 goto good;
00868         }
00869 
00870         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
00871           for (i = 0, tmp_dpp = dpp;
00872                i < sp->s_fullpath.fp_len && *tmp_dpp != DIR_NULL;
00873                ++i, ++tmp_dpp) {
00874             if (sp->s_fullpath.fp_names[i] != *tmp_dpp)
00875               break;
00876           }
00877 
00878           if (*tmp_dpp != DIR_NULL)
00879             continue;
00880 
00881           /* found a match */
00882           if (both)
00883               bu_vls_printf(&vls, "%d %g", sp->s_dmode, sp->s_transparency);
00884           else
00885               bu_vls_printf(&vls, "%d", sp->s_dmode);
00886 
00887           Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
00888           goto good;
00889         }
00890 
00891         /* match NOT found */
00892         Tcl_AppendResult(interp, "-1", (char *)NULL);
00893 
00894  good:
00895         if (dpp != (struct directory **)NULL)
00896           bu_free((genptr_t)dpp, "dgo_how_cmd: directory pointers");
00897         bu_vls_free(&vls);
00898 
00899         return TCL_OK;
00900 }
00901 
00902 /*
00903  * Returns "how" an object is being displayed.
00904  *
00905  * Usage:
00906  *        procname how obj
00907  */
00908 static int
00909 dgo_how_tcl(clientData, interp, argc, argv)
00910      ClientData clientData;
00911      Tcl_Interp *interp;
00912      int     argc;
00913      char    **argv;
00914 {
00915         struct dg_obj *dgop = (struct dg_obj *)clientData;
00916 
00917         DGO_CHECK_WDBP_NULL(dgop,interp);
00918         return dgo_how_cmd(dgop, interp, argc-1, argv+1);
00919 }
00920 
00921 int
00922 dgo_who_cmd(struct dg_obj       *dgop,
00923             Tcl_Interp          *interp,
00924             int                 argc,
00925             char                **argv)
00926 {
00927         register struct solid *sp;
00928         int skip_real, skip_phony;
00929 
00930         if (argc < 1 || 2 < argc) {
00931                 struct bu_vls vls;
00932 
00933                 bu_vls_init(&vls);
00934                 bu_vls_printf(&vls, "helplib_alias dgo_who %s", argv[0]);
00935                 Tcl_Eval(interp, bu_vls_addr(&vls));
00936                 bu_vls_free(&vls);
00937                 return TCL_ERROR;
00938         }
00939 
00940         skip_real = 0;
00941         skip_phony = 1;
00942         if (argc == 2) {
00943                 switch (argv[1][0]) {
00944                 case 'b':
00945                         skip_real = 0;
00946                         skip_phony = 0;
00947                         break;
00948                 case 'p':
00949                         skip_real = 1;
00950                         skip_phony = 0;
00951                         break;
00952                 case 'r':
00953                         skip_real = 0;
00954                         skip_phony = 1;
00955                         break;
00956                 default:
00957                         Tcl_AppendResult(interp, "dgo_who: argument not understood\n", (char *)NULL);
00958                         return TCL_ERROR;
00959                 }
00960         }
00961 
00962 
00963         /* Find all unique top-level entries.
00964          *  Mark ones already done with s_flag == UP
00965          */
00966         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid)
00967                 sp->s_flag = DOWN;
00968         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
00969                 register struct solid *forw;    /* XXX */
00970 
00971                 if (sp->s_flag == UP)
00972                         continue;
00973                 if (FIRST_SOLID(sp)->d_addr == RT_DIR_PHONY_ADDR) {
00974                         if (skip_phony) continue;
00975                 } else {
00976                         if (skip_real) continue;
00977                 }
00978                 Tcl_AppendResult(interp, FIRST_SOLID(sp)->d_namep, " ", (char *)NULL);
00979                 sp->s_flag = UP;
00980                 FOR_REST_OF_SOLIDS(forw, sp, &dgop->dgo_headSolid){
00981                         if (FIRST_SOLID(forw) == FIRST_SOLID(sp))
00982                                 forw->s_flag = UP;
00983                 }
00984         }
00985         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid)
00986                 sp->s_flag = DOWN;
00987 
00988         return TCL_OK;
00989 }
00990 
00991 /*
00992  * List the objects currently being drawn.
00993  *
00994  * Usage:
00995  *        procname who [r(eal)|p(hony)|b(oth)]
00996  */
00997 static int
00998 dgo_who_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
00999 {
01000         struct dg_obj *dgop = (struct dg_obj *)clientData;
01001 
01002         DGO_CHECK_WDBP_NULL(dgop,interp);
01003         return dgo_who_cmd(dgop, interp, argc-1, argv+1);
01004 }
01005 
01006 static void
01007 dgo_overlay(struct dg_obj *dgop, Tcl_Interp *interp, FILE *fp, char *name, double char_size)
01008 {
01009         int ret;
01010         struct rt_vlblock *vbp;
01011 
01012         vbp = rt_vlblock_init();
01013         ret = rt_uplot_to_vlist(vbp, fp, char_size, dgop->dgo_uplotOutputMode);
01014         fclose(fp);
01015 
01016         if (ret < 0) {
01017                 rt_vlblock_free(vbp);
01018                 return;
01019         }
01020 
01021         dgo_cvt_vlblock_to_solids(dgop, interp, vbp, name, 0);
01022         rt_vlblock_free(vbp);
01023 }
01024 
01025 int
01026 dgo_overlay_cmd(struct dg_obj   *dgop,
01027                 Tcl_Interp      *interp,
01028                 int             argc,
01029                 char            **argv)
01030 {
01031         FILE    *fp;
01032         double  char_size;
01033         char    *name;
01034 
01035         if (argc < 3 || 4 < argc) {
01036                 struct bu_vls vls;
01037 
01038                 bu_vls_init(&vls);
01039                 bu_vls_printf(&vls, "helplib_alias dgo_overlay %s", argv[0]);
01040                 Tcl_Eval(interp, bu_vls_addr(&vls));
01041                 bu_vls_free(&vls);
01042 
01043                 return TCL_ERROR;
01044         }
01045 
01046         if (sscanf(argv[2], "%lf", &char_size) != 1) {
01047                 Tcl_AppendResult(interp, "dgo_overlay: bad character size - ",
01048                                  argv[2], "\n", (char *)NULL);
01049                 return TCL_ERROR;
01050         }
01051 
01052         if (argc == 3)
01053                 name = "_PLOT_OVERLAY_";
01054         else
01055                 name = argv[3];
01056 
01057 #if defined(_WIN32) && !defined(__CYGWIN__)
01058 #  define PL_MODE "rb"
01059 #else
01060 #  define PL_MODE "r"
01061 #endif
01062         if ((fp = fopen(argv[1], PL_MODE)) == NULL) {
01063                 Tcl_AppendResult(interp, "dgo_overlay: failed to open file - ",
01064                                  argv[1], "\n", (char *)NULL);
01065 
01066                 return TCL_ERROR;
01067         }
01068 
01069         dgo_overlay(dgop, interp, fp, name, char_size);
01070         return TCL_OK;
01071 }
01072 
01073 /*
01074  * Usage:
01075  *        procname overlay file.plot char_size [name]
01076  */
01077 static int
01078 dgo_overlay_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
01079 {
01080         struct dg_obj   *dgop = (struct dg_obj *)clientData;
01081         int             ret;
01082 
01083         DGO_CHECK_WDBP_NULL(dgop,interp);
01084 
01085         if ((ret = dgo_overlay_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
01086                 dgo_notify(dgop, interp);
01087 
01088         return ret;
01089 }
01090 
01091 void
01092 dgo_autoview(struct dg_obj      *dgop,
01093              struct view_obj    *vop,
01094              Tcl_Interp         *interp)
01095 {
01096         register struct solid   *sp;
01097         vect_t          min, max;
01098         vect_t          minus, plus;
01099         vect_t          center;
01100         vect_t          radial;
01101 
01102         VSETALL(min,  INFINITY);
01103         VSETALL(max, -INFINITY);
01104 
01105         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
01106                 minus[X] = sp->s_center[X] - sp->s_size;
01107                 minus[Y] = sp->s_center[Y] - sp->s_size;
01108                 minus[Z] = sp->s_center[Z] - sp->s_size;
01109                 VMIN(min, minus);
01110                 plus[X] = sp->s_center[X] + sp->s_size;
01111                 plus[Y] = sp->s_center[Y] + sp->s_size;
01112                 plus[Z] = sp->s_center[Z] + sp->s_size;
01113                 VMAX(max, plus);
01114         }
01115 
01116         if (BU_LIST_IS_EMPTY(&dgop->dgo_headSolid)) {
01117                 /* Nothing is in view */
01118                 VSETALL(center, 0.0);
01119                 VSETALL(radial, 1000.0);        /* 1 meter */
01120         } else {
01121                 VADD2SCALE(center, max, min, 0.5);
01122                 VSUB2(radial, max, center);
01123         }
01124 
01125         if (VNEAR_ZERO(radial , SQRT_SMALL_FASTF))
01126                 VSETALL(radial , 1.0);
01127 
01128         MAT_IDN(vop->vo_center);
01129         MAT_DELTAS(vop->vo_center, -center[X], -center[Y], -center[Z]);
01130         vop->vo_scale = radial[X];
01131         V_MAX(vop->vo_scale, radial[Y]);
01132         V_MAX(vop->vo_scale, radial[Z]);
01133 
01134         vop->vo_size = 2.0 * vop->vo_scale;
01135         vop->vo_invSize = 1.0 / vop->vo_size;
01136         vo_update(vop, interp, 1);
01137 }
01138 
01139 int
01140 dgo_autoview_cmd(struct dg_obj          *dgop,
01141                  struct view_obj        *vop,
01142                  Tcl_Interp             *interp,
01143                  int                    argc,
01144                  char                   **argv)
01145 {
01146         if (argc != 2) {
01147                 struct bu_vls vls;
01148 
01149                 bu_vls_init(&vls);
01150                 bu_vls_printf(&vls, "helplib_alias dgo_autoview %s", argv[0]);
01151                 Tcl_Eval(interp, bu_vls_addr(&vls));
01152                 bu_vls_free(&vls);
01153                 return TCL_ERROR;
01154         }
01155 
01156         DGO_CHECK_WDBP_NULL(dgop,interp);
01157         dgo_autoview(dgop, vop, interp);
01158 
01159         return TCL_OK;
01160 }
01161 
01162 /*
01163  * Usage:
01164  *        procname autoview view_obj
01165  */
01166 static int
01167 dgo_autoview_tcl(ClientData     clientData,
01168                  Tcl_Interp     *interp,
01169                  int            argc,
01170                  char           **argv)
01171 {
01172         struct dg_obj *dgop = (struct dg_obj *)clientData;
01173         struct view_obj *vop;
01174 
01175         if (argc != 3) {
01176                 struct bu_vls vls;
01177 
01178                 bu_vls_init(&vls);
01179                 bu_vls_printf(&vls, "helplib_alias dgo_autoview %s", argv[0]);
01180                 Tcl_Eval(interp, bu_vls_addr(&vls));
01181                 bu_vls_free(&vls);
01182                 return TCL_ERROR;
01183         }
01184 
01185 #if 0
01186         DGO_CHECK_WDBP_NULL(dgop,interp);
01187 #endif
01188 
01189         /* search for view object */
01190         for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
01191                 if (strcmp(bu_vls_addr(&vop->vo_name), argv[2]) == 0)
01192                         break;
01193         }
01194 
01195         if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
01196                 Tcl_AppendResult(interp, "dgo_autoview: bad view object - ", argv[2],
01197                                  "\n", (char *)NULL);
01198                 return TCL_ERROR;
01199         }
01200 
01201         return dgo_autoview_cmd(dgop, vop, interp, argc-1, argv+1);
01202 }
01203 
01204 int
01205 dgo_get_autoview_cmd(struct dg_obj      *dgop,
01206                      Tcl_Interp         *interp,
01207                      int                argc,
01208                      char               **argv)
01209 {
01210         struct bu_vls vls;
01211         register struct solid   *sp;
01212         vect_t          min, max;
01213         vect_t          minus, plus;
01214         vect_t          center;
01215         vect_t          radial;
01216         int pflag = 0;
01217         register int    c;
01218 
01219         if (argc < 1 || 2 < argc) {
01220                 struct bu_vls vls;
01221 
01222                 bu_vls_init(&vls);
01223                 bu_vls_printf(&vls, "helplib_alias dgo_get_autoview %s", argv[0]);
01224                 Tcl_Eval(interp, bu_vls_addr(&vls));
01225                 bu_vls_free(&vls);
01226                 return TCL_ERROR;
01227         }
01228 
01229         /* Parse options. */
01230         bu_optind = 1;
01231         while ((c = bu_getopt(argc, argv, "p")) != EOF) {
01232             switch (c) {
01233             case 'p':
01234                 pflag = 1;
01235                 break;
01236             default: {
01237                 struct bu_vls vls;
01238 
01239                 bu_vls_init(&vls);
01240                 bu_vls_printf(&vls, "helplib_alias dgo_get_autoview %s", argv[0]);
01241                 Tcl_Eval(interp, bu_vls_addr(&vls));
01242                 bu_vls_free(&vls);
01243                 return TCL_ERROR;
01244             }
01245             }
01246         }
01247         argc -= bu_optind;
01248         argv += bu_optind;
01249 
01250         DGO_CHECK_WDBP_NULL(dgop,interp);
01251 
01252         VSETALL(min,  INFINITY);
01253         VSETALL(max, -INFINITY);
01254 
01255         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
01256             /* Skip psuedo-solids unless pflag is set */
01257             if (!pflag &&
01258                 sp->s_fullpath.fp_names != (struct directory **)0 &&
01259                 sp->s_fullpath.fp_names[0] != (struct directory *)0 &&
01260                 sp->s_fullpath.fp_names[0]->d_addr == RT_DIR_PHONY_ADDR)
01261                 continue;
01262 
01263             minus[X] = sp->s_center[X] - sp->s_size;
01264             minus[Y] = sp->s_center[Y] - sp->s_size;
01265             minus[Z] = sp->s_center[Z] - sp->s_size;
01266             VMIN(min, minus);
01267             plus[X] = sp->s_center[X] + sp->s_size;
01268             plus[Y] = sp->s_center[Y] + sp->s_size;
01269             plus[Z] = sp->s_center[Z] + sp->s_size;
01270             VMAX(max, plus);
01271         }
01272 
01273         if (BU_LIST_IS_EMPTY(&dgop->dgo_headSolid)) {
01274                 /* Nothing is in view */
01275                 VSETALL(center, 0.0);
01276                 VSETALL(radial, 1000.0);        /* 1 meter */
01277         } else {
01278                 VADD2SCALE(center, max, min, 0.5);
01279                 VSUB2(radial, max, center);
01280         }
01281 
01282         if (VNEAR_ZERO(radial , SQRT_SMALL_FASTF))
01283                 VSETALL(radial , 1.0);
01284 
01285         VSCALE(center, center, dgop->dgo_wdbp->dbip->dbi_base2local);
01286         radial[X] *= dgop->dgo_wdbp->dbip->dbi_base2local;
01287 
01288         bu_vls_init(&vls);
01289         bu_vls_printf(&vls, "center {%g %g %g} size %g", V3ARGS(center), radial[X] * 2.0);
01290         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01291         bu_vls_free(&vls);
01292 
01293         return TCL_OK;
01294 }
01295 
01296 /*
01297  * Usage:
01298  *        procname get_autoview
01299  */
01300 static int
01301 dgo_get_autoview_tcl(ClientData clientData,
01302                      Tcl_Interp *interp,
01303                      int        argc,
01304                      char       **argv)
01305 {
01306     struct dg_obj *dgop = (struct dg_obj *)clientData;
01307 
01308     return dgo_get_autoview_cmd(dgop, interp, argc-1, argv+1);
01309 }
01310 
01311 /*
01312  * support for get_eyemodel
01313  */
01314 int
01315 dgo_get_eyemodel_cmd(struct dg_obj      *dgop,
01316                      Tcl_Interp         *interp,
01317                      int                argc,
01318                      char               **argv)
01319 {
01320   struct bu_vls vls;
01321   struct view_obj * vop;
01322   quat_t                quat;
01323   vect_t                eye_model;
01324 
01325   if (argc != 2) {
01326     struct bu_vls vls;
01327 
01328     bu_vls_init(&vls);
01329     bu_vls_printf(&vls, "helplib_alias dgo_get_eyemodel %s", argv[0]);
01330     Tcl_Eval(interp, bu_vls_addr(&vls));
01331     bu_vls_free(&vls);
01332     return TCL_ERROR;
01333   }
01334 
01335   /*
01336    * Retrieve the view object
01337    */
01338   for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
01339     if (strcmp(bu_vls_addr(&vop->vo_name), argv[1]) == 0)
01340       break;
01341   }
01342 
01343   if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
01344     Tcl_AppendResult(interp,
01345                      "dgo_get_eyemodel: bad view object - ",
01346                      argv[2],
01347                      "\n", (char *)NULL);
01348     return TCL_ERROR;
01349   }
01350 
01351   dgo_rt_set_eye_model(dgop, vop, eye_model);
01352 
01353   bu_vls_init(&vls);
01354 
01355   quat_mat2quat(quat, vop->vo_rotation );
01356 
01357   bu_vls_printf(&vls, "viewsize %.15e;\n", vop->vo_size);
01358   bu_vls_printf(&vls, "orientation %.15e %.15e %.15e %.15e;\n",
01359                 V4ARGS(quat));
01360   bu_vls_printf(&vls, "eye_pt %.15e %.15e %.15e;\n",
01361                 eye_model[X], eye_model[Y], eye_model[Z] );
01362   Tcl_AppendResult(interp, bu_vls_addr(&vls), NULL);
01363   bu_vls_free(&vls);
01364   return TCL_OK;
01365 }
01366 
01367 /*
01368  * Usage:
01369  *        procname get_eyemodel
01370  */
01371 static int
01372 dgo_get_eyemodel_tcl(ClientData clientData,
01373                      Tcl_Interp *interp,
01374                      int        argc,
01375                      char       **argv)
01376 {
01377         struct dg_obj *dgop = (struct dg_obj *)clientData;
01378         return dgo_get_eyemodel_cmd(dgop, interp, argc-1, argv+1);
01379 }
01380 
01381 int
01382 dgo_rt_cmd(struct dg_obj        *dgop,
01383            struct view_obj      *vop,
01384            Tcl_Interp           *interp,
01385            int                  argc,
01386            char                 **argv)
01387 {
01388         register char **vp;
01389         register int i;
01390         char    pstring[32];
01391 
01392         if (argc < 1 || MAXARGS < argc) {
01393                 struct bu_vls vls;
01394 
01395                 bu_vls_init(&vls);
01396                 bu_vls_printf(&vls, "helplib_alias dgo_%s %s", argv[0], argv[0]);
01397                 Tcl_Eval(interp, bu_vls_addr(&vls));
01398                 bu_vls_free(&vls);
01399                 return TCL_ERROR;
01400         }
01401 
01402         vp = &dgop->dgo_rt_cmd[0];
01403         *vp++ = argv[0];
01404         *vp++ = "-M";
01405 
01406         if (vop->vo_perspective > 0) {
01407                 (void)sprintf(pstring, "-p%g", vop->vo_perspective);
01408                 *vp++ = pstring;
01409         }
01410 
01411         for (i=1; i < argc; i++) {
01412                 if (argv[i][0] == '-' && argv[i][1] == '-' &&
01413                     argv[i][2] == '\0') {
01414                         ++i;
01415                         break;
01416                 }
01417                 *vp++ = argv[i];
01418         }
01419         /* XXX why is this different for win32 only? */
01420 #ifdef _WIN32
01421         {
01422             char buf[512];
01423 
01424             sprintf(buf, "\"%s\"", dgop->dgo_wdbp->dbip->dbi_filename);
01425             *vp++ = buf;
01426         }
01427 #else
01428         *vp++ = dgop->dgo_wdbp->dbip->dbi_filename;
01429 #endif
01430 
01431         /*
01432          * Now that we've grabbed all the options, if no args remain,
01433          * append the names of all stuff currently displayed.
01434          * Otherwise, simply append the remaining args.
01435          */
01436         if (i == argc) {
01437                 dgop->dgo_rt_cmd_len = vp - dgop->dgo_rt_cmd;
01438                 dgop->dgo_rt_cmd_len += dgo_build_tops(interp,
01439                                                        (struct solid *)&dgop->dgo_headSolid,
01440                                                        vp,
01441                                                        &dgop->dgo_rt_cmd[MAXARGS]);
01442         } else {
01443                 while (i < argc)
01444                         *vp++ = argv[i++];
01445                 *vp = 0;
01446                 vp = &dgop->dgo_rt_cmd[0];
01447                 while (*vp)
01448                         Tcl_AppendResult(interp, *vp++, " ", (char *)NULL);
01449 
01450                 Tcl_AppendResult(interp, "\n", (char *)NULL);
01451         }
01452         (void)dgo_run_rt(dgop, vop);
01453 
01454         return TCL_OK;
01455 }
01456 
01457 /*
01458  * Usage:
01459  *        procname rt view_obj arg(s)
01460  */
01461 static int
01462 dgo_rt_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
01463 {
01464         struct dg_obj   *dgop = (struct dg_obj *)clientData;
01465         struct view_obj *vop;
01466 
01467         if (argc < 3 || MAXARGS < argc) {
01468                 struct bu_vls vls;
01469 
01470                 bu_vls_init(&vls);
01471                 bu_vls_printf(&vls, "helplib_alias dgo_%s %s", argv[0], argv[0]);
01472                 Tcl_Eval(interp, bu_vls_addr(&vls));
01473                 bu_vls_free(&vls);
01474                 return TCL_ERROR;
01475         }
01476 
01477         DGO_CHECK_WDBP_NULL(dgop,interp);
01478 
01479         /* search for view object */
01480         for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
01481                 if (strcmp(bu_vls_addr(&vop->vo_name), argv[2]) == 0)
01482                         break;
01483         }
01484 
01485         if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
01486                 Tcl_AppendResult(interp, "dgo_rt: bad view object - ", argv[2],
01487                                  "\n", (char *)NULL);
01488                 return TCL_ERROR;
01489         }
01490 
01491         /* copy command name into argv[2], could be rt or some other rt-style command  */
01492         argv[2] = argv[1];
01493         return dgo_rt_cmd(dgop, vop, interp, argc-2, argv+2);
01494 }
01495 
01496 int
01497 dgo_vdraw_cmd(struct dg_obj     *dgop,
01498               Tcl_Interp        *interp,
01499               int               argc,
01500               char              **argv)
01501 {
01502         return bu_cmd((ClientData)dgop, interp, argc-1, argv+1, vdraw_cmds, 0);
01503 }
01504 
01505 /*
01506  * Usage:
01507  *        procname vdraw cmd arg(s)
01508  */
01509 static int
01510 dgo_vdraw_tcl(ClientData        clientData,
01511               Tcl_Interp        *interp,
01512               int               argc,
01513               char              **argv)
01514 {
01515         struct dg_obj *dgop = (struct dg_obj *)clientData;
01516 
01517         DGO_CHECK_WDBP_NULL(dgop,interp);
01518 
01519         return dgo_vdraw_cmd(dgop, interp, argc-1, argv+1);
01520 }
01521 
01522 void
01523 dgo_zap_cmd(struct dg_obj       *dgop,
01524             Tcl_Interp          *interp)
01525 {
01526         register struct solid *sp;
01527         register struct solid *nsp;
01528         struct directory *dp;
01529 
01530         sp = BU_LIST_NEXT(solid, &dgop->dgo_headSolid);
01531         while (BU_LIST_NOT_HEAD(sp, &dgop->dgo_headSolid)) {
01532                 dp = FIRST_SOLID(sp);
01533                 RT_CK_DIR(dp);
01534                 if (dp->d_addr == RT_DIR_PHONY_ADDR) {
01535                         if (db_dirdelete(dgop->dgo_wdbp->dbip, dp) < 0) {
01536                           Tcl_AppendResult(interp, "dgo_zap: db_dirdelete failed\n", (char *)NULL);
01537                         }
01538                 }
01539 
01540                 nsp = BU_LIST_PNEXT(solid, sp);
01541                 BU_LIST_DEQUEUE(&sp->l);
01542                 FREE_SOLID(sp,&FreeSolid.l);
01543                 sp = nsp;
01544         }
01545 }
01546 
01547 /*
01548  * Usage:
01549  *        procname clear|zap
01550  */
01551 static int
01552 dgo_zap_tcl(ClientData  clientData,
01553             Tcl_Interp  *interp,
01554             int         argc,
01555             char        **argv)
01556 {
01557         struct dg_obj   *dgop = (struct dg_obj *)clientData;
01558 
01559         DGO_CHECK_WDBP_NULL(dgop,interp);
01560 
01561         if (argc != 2) {
01562                 struct bu_vls vls;
01563 
01564                 bu_vls_init(&vls);
01565                 bu_vls_printf(&vls, "helplib_alias dgo_%s %s", argv[1], argv[1]);
01566                 Tcl_Eval(interp, bu_vls_addr(&vls));
01567                 bu_vls_free(&vls);
01568                 return TCL_ERROR;
01569         }
01570 
01571         dgo_zap_cmd(dgop, interp);
01572         dgo_notify(dgop, interp);
01573 
01574         return TCL_OK;
01575 }
01576 
01577 int
01578 dgo_blast_cmd(struct dg_obj     *dgop,
01579               Tcl_Interp        *interp,
01580               int               argc,
01581               char              **argv)
01582 {
01583         /* First, clear the screen. */
01584         dgo_zap_cmd(dgop, interp);
01585 
01586         /* Now, draw the new object(s). */
01587         return dgo_draw_cmd(dgop, interp, argc, argv, 1);
01588 }
01589 
01590 /*
01591  * Usage:
01592  *        procname blast object(s)
01593  */
01594 static int
01595 dgo_blast_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
01596 {
01597         struct dg_obj   *dgop = (struct dg_obj *)clientData;
01598         int             ret;
01599 
01600         DGO_CHECK_WDBP_NULL(dgop,interp);
01601 
01602         if (argc < 3) {
01603                 struct bu_vls vls;
01604 
01605                 bu_vls_init(&vls);
01606                 bu_vls_printf(&vls, "helplib_alias dgo_blast %s", argv[0]);
01607                 Tcl_Eval(interp, bu_vls_addr(&vls));
01608                 bu_vls_free(&vls);
01609 
01610                 return TCL_ERROR;
01611         }
01612 
01613         if ((ret = dgo_blast_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
01614                 dgo_notify(dgop, interp);
01615 
01616         return ret;
01617 }
01618 
01619 #if 0
01620 /*
01621  * Usage:
01622  *        procname tol [abs|rel|norm|dist|perp [#]]
01623  *
01624  *  abs #       sets absolute tolerance.  # > 0.0
01625  *  rel #       sets relative tolerance.  0.0 < # < 1.0
01626  *  norm #      sets normal tolerance, in degrees.
01627  *  dist #      sets calculational distance tolerance
01628  *  perp #      sets calculational normal tolerance.
01629  *
01630  */
01631 static int
01632 dgo_tol_tcl(clientData, interp, argc, argv)
01633      ClientData clientData;
01634      Tcl_Interp *interp;
01635      int        argc;
01636      char       **argv;
01637 {
01638         struct dg_obj *dgop = (struct dg_obj *)clientData;
01639         struct bu_vls vls;
01640         double  f;
01641 
01642         DGO_CHECK_WDBP_NULL(dgop,interp);
01643 
01644         if (argc < 2 || 4 < argc){
01645                 bu_vls_init(&vls);
01646                 bu_vls_printf(&vls, "helplib_alias dgo_tol %s", argv[0]);
01647                 Tcl_Eval(interp, bu_vls_addr(&vls));
01648                 bu_vls_free(&vls);
01649                 return TCL_ERROR;
01650         }
01651 
01652         /* print all tolerance settings */
01653         if (argc == 2) {
01654                 Tcl_AppendResult(interp, "Current tolerance settings are:\n", (char *)NULL);
01655                 Tcl_AppendResult(interp, "Tesselation tolerances:\n", (char *)NULL );
01656 
01657                 if (dgop->dgo_ttol.abs > 0.0) {
01658                         bu_vls_init(&vls);
01659                         bu_vls_printf(&vls, "\tabs %g mm\n", dgop->dgo_ttol.abs);
01660                         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01661                         bu_vls_free(&vls);
01662                 } else {
01663                         Tcl_AppendResult(interp, "\tabs None\n", (char *)NULL);
01664                 }
01665 
01666                 if (dgop->dgo_ttol.rel > 0.0) {
01667                         bu_vls_init(&vls);
01668                         bu_vls_printf(&vls, "\trel %g (%g%%)\n",
01669                                       dgop->dgo_ttol.rel, dgop->dgo_ttol.rel * 100.0 );
01670                         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01671                         bu_vls_free(&vls);
01672                 } else {
01673                         Tcl_AppendResult(interp, "\trel None\n", (char *)NULL);
01674                 }
01675 
01676                 if (dgop->dgo_ttol.norm > 0.0) {
01677                         int     deg, min;
01678                         double  sec;
01679 
01680                         bu_vls_init(&vls);
01681                         sec = dgop->dgo_ttol.norm * bn_radtodeg;
01682                         deg = (int)(sec);
01683                         sec = (sec - (double)deg) * 60;
01684                         min = (int)(sec);
01685                         sec = (sec - (double)min) * 60;
01686 
01687                         bu_vls_printf(&vls, "\tnorm %g degrees (%d deg %d min %g sec)\n",
01688                                       dgop->dgo_ttol.norm * bn_radtodeg, deg, min, sec);
01689                         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01690                         bu_vls_free(&vls);
01691                 } else {
01692                         Tcl_AppendResult(interp, "\tnorm None\n", (char *)NULL);
01693                 }
01694 
01695                 bu_vls_init(&vls);
01696                 bu_vls_printf(&vls,"Calculational tolerances:\n");
01697                 bu_vls_printf(&vls,
01698                               "\tdistance = %g mm\n\tperpendicularity = %g (cosine of %g degrees)\n",
01699                               dgop->dgo_tol.dist, dgop->dgo_tol.perp,
01700                               acos(dgop->dgo_tol.perp)*bn_radtodeg);
01701                 Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01702                 bu_vls_free(&vls);
01703 
01704                 return TCL_OK;
01705         }
01706 
01707         /* get the specified tolerance */
01708         if (argc == 3) {
01709                 int status = TCL_OK;
01710 
01711                 bu_vls_init(&vls);
01712 
01713                 switch (argv[2][0]) {
01714                 case 'a':
01715                         if (dgop->dgo_ttol.abs > 0.0)
01716                                 bu_vls_printf(&vls, "%g", dgop->dgo_ttol.abs);
01717                         else
01718                                 bu_vls_printf(&vls, "None");
01719                         break;
01720                 case 'r':
01721                         if (dgop->dgo_ttol.rel > 0.0)
01722                                 bu_vls_printf(&vls, "%g", dgop->dgo_ttol.rel);
01723                         else
01724                                 bu_vls_printf(&vls, "None");
01725                         break;
01726                 case 'n':
01727                         if (dgop->dgo_ttol.norm > 0.0)
01728                                 bu_vls_printf(&vls, "%g", dgop->dgo_ttol.norm);
01729                         else
01730                                 bu_vls_printf(&vls, "None");
01731                         break;
01732                 case 'd':
01733                         bu_vls_printf(&vls, "%g", dgop->dgo_tol.dist);
01734                         break;
01735                 case 'p':
01736                         bu_vls_printf(&vls, "%g", dgop->dgo_tol.perp);
01737                         break;
01738                 default:
01739                         bu_vls_printf(&vls, "unrecognized tolerance type - %s\n", argv[2]);
01740                         status = TCL_ERROR;
01741                         break;
01742                 }
01743 
01744                 Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01745                 bu_vls_free(&vls);
01746                 return status;
01747         }
01748 
01749         /* set the specified tolerance */
01750         if (sscanf(argv[3], "%lf", &f) != 1) {
01751                 bu_vls_init(&vls);
01752                 bu_vls_printf(&vls, "bad tolerance - %s\n", argv[3]);
01753                 Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01754                 bu_vls_free(&vls);
01755 
01756                 return TCL_ERROR;
01757         }
01758 
01759         switch (argv[2][0]) {
01760         case 'a':
01761                 /* Absolute tol */
01762                 if (f <= 0.0)
01763                         dgop->dgo_ttol.abs = 0.0;
01764                 else
01765                         dgop->dgo_ttol.abs = f;
01766                 break;
01767         case 'r':
01768                 if (f < 0.0 || f >= 1.0) {
01769                            Tcl_AppendResult(interp,
01770                                             "relative tolerance must be between 0 and 1, not changed\n",
01771                                             (char *)NULL);
01772                            return TCL_ERROR;
01773                 }
01774                 /* Note that a value of 0.0 will disable relative tolerance */
01775                 dgop->dgo_ttol.rel = f;
01776                 break;
01777         case 'n':
01778                 /* Normal tolerance, in degrees */
01779                 if (f < 0.0 || f > 90.0) {
01780                         Tcl_AppendResult(interp,
01781                                          "Normal tolerance must be in positive degrees, < 90.0\n",
01782                                          (char *)NULL);
01783                         return TCL_ERROR;
01784                 }
01785                 /* Note that a value of 0.0 or 360.0 will disable this tol */
01786                 dgop->dgo_ttol.norm = f * bn_degtorad;
01787                 break;
01788         case 'd':
01789                 /* Calculational distance tolerance */
01790                 if (f < 0.0) {
01791                         Tcl_AppendResult(interp,
01792                                          "Calculational distance tolerance must be positive\n",
01793                                          (char *)NULL);
01794                         return TCL_ERROR;
01795                 }
01796                 dgop->dgo_tol.dist = f;
01797                 dgop->dgo_tol.dist_sq = dgop->dgo_tol.dist * dgop->dgo_tol.dist;
01798                 break;
01799         case 'p':
01800                 /* Calculational perpendicularity tolerance */
01801                 if (f < 0.0 || f > 1.0) {
01802                         Tcl_AppendResult(interp,
01803                                          "Calculational perpendicular tolerance must be from 0 to 1\n",
01804                                          (char *)NULL);
01805                         return TCL_ERROR;
01806                 }
01807                 dgop->dgo_tol.perp = f;
01808                 dgop->dgo_tol.para = 1.0 - f;
01809                 break;
01810         default:
01811                 bu_vls_init(&vls);
01812                 bu_vls_printf(&vls, "unrecognized tolerance type - %s\n", argv[2]);
01813                 Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
01814                 bu_vls_free(&vls);
01815 
01816                 return TCL_ERROR;
01817         }
01818 
01819         return TCL_OK;
01820 }
01821 #endif
01822 
01823 struct rtcheck {
01824 #ifdef _WIN32
01825         HANDLE                  fd;
01826         HANDLE                  hProcess;
01827         DWORD                   pid;
01828 #ifdef TCL_OK
01829         Tcl_Channel             chan;
01830 #else
01831         genptr_t chan;
01832 #endif
01833 #else
01834         int                     fd;
01835         int                     pid;
01836 #endif
01837         FILE                    *fp;
01838         struct bn_vlblock       *vbp;
01839         struct bu_list          *vhead;
01840         double                  csize;
01841         struct dg_obj           *dgop;
01842         Tcl_Interp              *interp;
01843 };
01844 
01845 struct rtcheck_output {
01846 #ifdef _WIN32
01847     HANDLE              fd;
01848     Tcl_Channel         chan;
01849 #else
01850     int                 fd;
01851 #endif
01852     struct dg_obj       *dgop;
01853     Tcl_Interp          *interp;
01854 };
01855 
01856 
01857 /*
01858  *                      D G O _ W A I T _ S T A T U S
01859  *
01860  *  Interpret the status return of a wait() system call,
01861  *  for the edification of the watching luser.
01862  *  Warning:  This may be somewhat system specific, most especially
01863  *  on non-UNIX machines.
01864  */
01865 static void
01866 dgo_wait_status(Tcl_Interp *interp, int status)
01867 {
01868         int     sig = status & 0x7f;
01869         int     core = status & 0x80;
01870         int     ret = status >> 8;
01871         struct bu_vls tmp_vls;
01872 
01873         if (status == 0) {
01874                 Tcl_AppendResult(interp, "Normal exit\n", (char *)NULL);
01875                 return;
01876         }
01877 
01878         bu_vls_init(&tmp_vls);
01879         bu_vls_printf(&tmp_vls, "Abnormal exit x%x", status);
01880 
01881         if (core)
01882                 bu_vls_printf(&tmp_vls, ", core dumped");
01883 
01884         if (sig)
01885                 bu_vls_printf(&tmp_vls, ", terminating signal = %d", sig);
01886         else
01887                 bu_vls_printf(&tmp_vls, ", return (exit) code = %d", ret);
01888 
01889         Tcl_AppendResult(interp, bu_vls_addr(&tmp_vls), "\n", (char *)NULL);
01890         bu_vls_free(&tmp_vls);
01891 }
01892 
01893 #ifndef _WIN32
01894 static void
01895 dgo_rtcheck_vector_handler(ClientData clientData, int mask)
01896 {
01897         int value;
01898         struct solid *sp;
01899         struct rtcheck *rtcp = (struct rtcheck *)clientData;
01900 
01901         /* Get vector output from rtcheck */
01902         if ((value = getc(rtcp->fp)) == EOF) {
01903                 int retcode;
01904                 int rpid;
01905 
01906                 Tcl_DeleteFileHandler(rtcp->fd);
01907                 fclose(rtcp->fp);
01908 
01909                 FOR_ALL_SOLIDS(sp, &rtcp->dgop->dgo_headSolid)
01910                         sp->s_flag = DOWN;
01911 
01912                 /* Add overlay */
01913                 dgo_cvt_vlblock_to_solids(rtcp->dgop, rtcp->interp, rtcp->vbp, "OVERLAPS", 0);
01914                 rt_vlblock_free(rtcp->vbp);
01915 
01916                 /* wait for the forked process */
01917                 while ((rpid = wait(&retcode)) != rtcp->pid && rpid != -1)
01918                         dgo_wait_status(rtcp->interp, retcode);
01919 
01920                 dgo_notify(rtcp->dgop, rtcp->interp);
01921 
01922                 /* free rtcp */
01923                 bu_free((genptr_t)rtcp, "dgo_rtcheck_vector_handler: rtcp");
01924 
01925                 return;
01926         }
01927 
01928         (void)rt_process_uplot_value(&rtcp->vhead,
01929                                      rtcp->vbp,
01930                                      rtcp->fp,
01931                                      value,
01932                                      rtcp->csize,
01933                                      rtcp->dgop->dgo_uplotOutputMode);
01934 }
01935 
01936 static void
01937 dgo_rtcheck_output_handler(ClientData clientData, int mask)
01938 {
01939     int count;
01940     char line[RT_MAXLINE] = {0};
01941     struct rtcheck_output *rtcop = (struct rtcheck_output *)clientData;
01942 
01943     /* Get textual output from rtcheck */
01944     count = read((int)rtcop->fd, line, RT_MAXLINE);
01945     if (count <= 0) {
01946         if (count < 0) {
01947             perror("READ ERROR");
01948         }
01949         Tcl_DeleteFileHandler(rtcop->fd);
01950         close(rtcop->fd);
01951 
01952         bu_free((genptr_t)rtcop, "dgo_rtcheck_output_handler: rtcop");
01953         return;
01954     }
01955 
01956     line[count] = '\0';
01957     if (rtcop->dgop->dgo_outputHandler != NULL) {
01958         struct bu_vls vls;
01959 
01960         bu_vls_init(&vls);
01961         bu_vls_printf(&vls, "%s \"%s\"", rtcop->dgop->dgo_outputHandler, line);
01962         Tcl_Eval(rtcop->interp, bu_vls_addr(&vls));
01963         bu_vls_free(&vls);
01964     } else
01965     bu_log("%s", line);
01966 }
01967 
01968 #else
01969 
01970 void
01971 dgo_rtcheck_vector_handler(ClientData clientData, int mask)
01972 {
01973         int value;
01974         struct solid *sp;
01975         struct rtcheck *rtcp = (struct rtcheck *)clientData;
01976 
01977         /* Get vector output from rtcheck */
01978         if (feof(rtcp->fp)) {
01979                 Tcl_DeleteChannelHandler(rtcp->chan,
01980                                          dgo_rtcheck_vector_handler,
01981                                          (ClientData)rtcp);
01982                 Tcl_Close(rtcp->interp, rtcp->chan);
01983                 fclose(rtcp->fp);
01984                 CloseHandle(rtcp->fd);
01985 
01986                 FOR_ALL_SOLIDS(sp, &rtcp->dgop->dgo_headSolid)
01987                         sp->s_flag = DOWN;
01988 
01989                 /* Add overlay */
01990                 dgo_cvt_vlblock_to_solids(rtcp->dgop, rtcp->interp, rtcp->vbp, "OVERLAPS", 0);
01991                 rt_vlblock_free(rtcp->vbp);
01992 
01993                 /* wait for the forked process */
01994                 WaitForSingleObject( rtcp->hProcess, INFINITE );
01995 
01996 /*              while ((rpid = wait(&retcode)) != rtcp->pid && rpid != -1)
01997                         dgo_wait_status(rtcp->interp, retcode);*/
01998 
01999                 dgo_notify(rtcp->dgop, rtcp->interp);
02000 
02001                 /* free rtcp */
02002                 bu_free((genptr_t)rtcp, "dgo_rtcheck_vector_handler: rtcp");
02003 
02004                 return;
02005         }
02006 
02007         value = getc(rtcp->fp);
02008         (void)rt_process_uplot_value(&rtcp->vhead,
02009                                      rtcp->vbp,
02010                                      rtcp->fp,
02011                                      value,
02012                                      rtcp->csize,
02013                                      rtcp->dgop->dgo_uplotOutputMode);
02014 }
02015 
02016 void
02017 dgo_rtcheck_output_handler(ClientData clientData, int mask)
02018 {
02019     int count;
02020     char line[RT_MAXLINE];
02021     struct rtcheck_output *rtcop = (struct rtcheck_output *)clientData;
02022 
02023     /* Get textual output from rtcheck */
02024     if (Tcl_Eof(rtcop->chan) ||
02025         (!ReadFile(rtcop->fd, line, RT_MAXLINE,&count,0))) {
02026 
02027         Tcl_DeleteChannelHandler(rtcop->chan,
02028                                  dgo_rtcheck_output_handler,
02029                                  (ClientData)rtcop);
02030 #if 1
02031         Tcl_Close(rtcop->interp, rtcop->chan);
02032 #endif
02033         CloseHandle(rtcop->fd);
02034 
02035         bu_free((genptr_t)rtcop, "dgo_rtcheck_output_handler: rtcop");
02036         return;
02037     }
02038 
02039     line[count] = '\0';
02040     if (rtcop->dgop->dgo_outputHandler != NULL) {
02041         struct bu_vls vls;
02042 
02043         bu_vls_init(&vls);
02044         bu_vls_printf(&vls, "%s \"%s\"", rtcop->dgop->dgo_outputHandler, line);
02045         Tcl_Eval(rtcop->interp, bu_vls_addr(&vls));
02046         bu_vls_free(&vls);
02047     } else
02048         bu_log("%s", line);
02049 }
02050 
02051 #endif
02052 
02053 int
02054 dgo_rtcheck_cmd(struct dg_obj   *dgop,
02055                 struct view_obj *vop,
02056                 Tcl_Interp      *interp,
02057                 int             argc,
02058                 char            **argv)
02059 {
02060         register char **vp;
02061         register int i;
02062 #ifndef _WIN32
02063         int     pid;
02064         int     i_pipe[2];      /* object reads results for building vectors */
02065         int     o_pipe[2];      /* object writes view parameters */
02066         int     e_pipe[2];      /* object reads textual results */
02067 #else
02068         HANDLE  i_pipe[2],pipe_iDup;    /* MGED reads results for building vectors */
02069         HANDLE  o_pipe[2],pipe_oDup;    /* MGED writes view parameters */
02070         HANDLE  e_pipe[2],pipe_eDup;    /* MGED reads textual results */
02071         STARTUPINFO si;
02072         PROCESS_INFORMATION pi;
02073         SECURITY_ATTRIBUTES sa;
02074         char line[2048];
02075         char name[256];
02076 #endif
02077         FILE    *fp;
02078         struct rtcheck *rtcp;
02079         struct rtcheck_output *rtcop;
02080         vect_t temp;
02081         vect_t eye_model;
02082 
02083 #ifndef _WIN32
02084         vp = &dgop->dgo_rt_cmd[0];
02085         *vp++ = argv[0];
02086         *vp++ = "-M";
02087         for (i=1; i < argc; i++)
02088                 *vp++ = argv[i];
02089         *vp++ = dgop->dgo_wdbp->dbip->dbi_filename;
02090 
02091         /*
02092          * Now that we've grabbed all the options, if no args remain,
02093          * append the names of all stuff currently displayed.
02094          * Otherwise, simply append the remaining args.
02095          */
02096         if (i == argc) {
02097                 dgop->dgo_rt_cmd_len = vp - dgop->dgo_rt_cmd;
02098                 dgop->dgo_rt_cmd_len += dgo_build_tops(interp,
02099                                                        (struct solid *)&dgop->dgo_headSolid,
02100                                                        vp,
02101                                                        &dgop->dgo_rt_cmd[MAXARGS]);
02102         } else {
02103                 while (i < argc)
02104                         *vp++ = argv[i++];
02105                 *vp = 0;
02106                 vp = &dgop->dgo_rt_cmd[0];
02107                 while (*vp)
02108                         Tcl_AppendResult(interp, *vp++, " ", (char *)NULL);
02109 
02110                 Tcl_AppendResult(interp, "\n", (char *)NULL);
02111         }
02112 
02113         (void)pipe(i_pipe);
02114         (void)pipe(o_pipe);
02115         (void)pipe(e_pipe);
02116 
02117         if ((pid = fork()) == 0) {
02118                 /* Redirect stdin, stdout and stderr */
02119                 (void)close(0);
02120                 (void)dup(o_pipe[0]);
02121                 (void)close(1);
02122                 (void)dup(i_pipe[1]);
02123                 (void)close(2);
02124                 (void)dup(e_pipe[1]);
02125 
02126                 /* close pipes */
02127                 (void)close(i_pipe[0]);
02128                 (void)close(i_pipe[1]);
02129                 (void)close(o_pipe[0]);
02130                 (void)close(o_pipe[1]);
02131                 (void)close(e_pipe[0]);
02132                 (void)close(e_pipe[1]);
02133 
02134                 for (i=3; i < 20; i++)
02135                         (void)close(i);
02136 
02137                 (void)execvp(dgop->dgo_rt_cmd[0], dgop->dgo_rt_cmd);
02138                 perror(dgop->dgo_rt_cmd[0]);
02139                 exit(16);
02140         }
02141 
02142         /* As parent, send view information down pipe */
02143         (void)close(o_pipe[0]);
02144         fp = fdopen(o_pipe[1], "w");
02145 #if 1
02146         VSET(temp, 0.0, 0.0, 1.0);
02147         MAT4X3PNT(eye_model, vop->vo_view2model, temp);
02148 #else
02149         dgo_rt_set_eye_model(dgop, vop, eye_model);
02150 #endif
02151         dgo_rt_write(dgop, vop, fp, eye_model);
02152 
02153         (void)fclose(fp);
02154 
02155         /* close write end of pipes */
02156         (void)close(i_pipe[1]);
02157         (void)close(e_pipe[1]);
02158 
02159         BU_GETSTRUCT(rtcp, rtcheck);
02160 
02161         /* initialize the rtcheck struct */
02162         rtcp->fd = i_pipe[0];
02163         rtcp->fp = fdopen(i_pipe[0], "r");
02164         rtcp->pid = pid;
02165         rtcp->vbp = rt_vlblock_init();
02166         rtcp->vhead = rt_vlblock_find(rtcp->vbp, 0xFF, 0xFF, 0x00);
02167         rtcp->csize = vop->vo_scale * 0.01;
02168         rtcp->dgop = dgop;
02169         rtcp->interp = interp;
02170 
02171         /* register file handlers */
02172         Tcl_CreateFileHandler(i_pipe[0], TCL_READABLE,
02173                               dgo_rtcheck_vector_handler, (ClientData)rtcp);
02174 
02175         BU_GETSTRUCT(rtcop, rtcheck_output);
02176         rtcop->fd = e_pipe[0];
02177         rtcop->dgop = dgop;
02178         rtcop->interp = interp;
02179         Tcl_CreateFileHandler(rtcop->fd,
02180                               TCL_READABLE,
02181                               dgo_rtcheck_output_handler,
02182                               (ClientData)rtcop);
02183 
02184         return TCL_OK;
02185 #else
02186         /* _WIN32 */
02187         vp = &dgop->dgo_rt_cmd[0];
02188         *vp++ = "rtcheck";
02189         *vp++ = "-M";
02190         for (i=1; i < argc; i++)
02191                 *vp++ = argv[i];
02192 
02193         {
02194             char buf[512];
02195 
02196             sprintf(buf, "\"%s\"", dgop->dgo_wdbp->dbip->dbi_filename);
02197             *vp++ = buf;
02198         }
02199 
02200         /*
02201          * Now that we've grabbed all the options, if no args remain,
02202          * append the names of all stuff currently displayed.
02203          * Otherwise, simply append the remaining args.
02204          */
02205         if (i == argc) {
02206                 dgop->dgo_rt_cmd_len = vp - dgop->dgo_rt_cmd;
02207                 dgop->dgo_rt_cmd_len += dgo_build_tops(interp,
02208                                                        (struct solid *)&dgop->dgo_headSolid,
02209                                                        vp,
02210                                                        &dgop->dgo_rt_cmd[MAXARGS]);
02211         } else {
02212                 while (i < argc)
02213                         *vp++ = argv[i++];
02214                 *vp = 0;
02215                 vp = &dgop->dgo_rt_cmd[0];
02216                 while (*vp)
02217                         Tcl_AppendResult(interp, *vp++, " ", (char *)NULL);
02218 
02219                 Tcl_AppendResult(interp, "\n", (char *)NULL);
02220         }
02221 
02222 
02223         memset((void *)&si, 0, sizeof(STARTUPINFO));
02224         memset((void *)&pi, 0, sizeof(PROCESS_INFORMATION));
02225         memset((void *)&sa, 0, sizeof(SECURITY_ATTRIBUTES));
02226 
02227         sa.nLength = sizeof(SECURITY_ATTRIBUTES);
02228         sa.bInheritHandle = TRUE;
02229         sa.lpSecurityDescriptor = NULL;
02230 
02231         /* Create a pipe for the child process's STDERR. */
02232         CreatePipe( &e_pipe[0], &e_pipe[1], &sa, 0);
02233 
02234         /* Create noninheritable read handle and close the inheritable read handle. */
02235         DuplicateHandle( GetCurrentProcess(), e_pipe[0],
02236                          GetCurrentProcess(),  &pipe_eDup,
02237                          0,  FALSE,
02238                          DUPLICATE_SAME_ACCESS );
02239         CloseHandle( e_pipe[0]);
02240 
02241         /* Create a pipe for the child process's STDOUT. */
02242         CreatePipe( &o_pipe[0], &o_pipe[1], &sa, 0);
02243 
02244         /* Create noninheritable write handle and close the inheritable writehandle. */
02245         DuplicateHandle( GetCurrentProcess(), o_pipe[1],
02246                          GetCurrentProcess(),  &pipe_oDup ,
02247                          0,  FALSE,
02248                          DUPLICATE_SAME_ACCESS );
02249         CloseHandle( o_pipe[1]);
02250 
02251         /* Create a pipe for the child process's STDIN. */
02252         CreatePipe(&i_pipe[0], &i_pipe[1], &sa, 0);
02253 
02254         /* Duplicate the read handle to the pipe so it is not inherited. */
02255         DuplicateHandle(GetCurrentProcess(), i_pipe[0],
02256                         GetCurrentProcess(), &pipe_iDup,
02257                         0, FALSE,                  /* not inherited */
02258                         DUPLICATE_SAME_ACCESS );
02259         CloseHandle(i_pipe[0]);
02260 
02261 
02262         si.cb = sizeof(STARTUPINFO);
02263         si.lpReserved = NULL;
02264         si.lpReserved2 = NULL;
02265         si.cbReserved2 = 0;
02266         si.lpDesktop = NULL;
02267         si.dwFlags = STARTF_USESTDHANDLES | STARTF_USESHOWWINDOW;
02268         si.hStdInput   = o_pipe[0];
02269         si.hStdOutput  = i_pipe[1];
02270         si.hStdError   = e_pipe[1];
02271         si.wShowWindow = SW_HIDE;
02272 
02273         sprintf(line,"%s ",dgop->dgo_rt_cmd[0]);
02274         for (i=1; i < dgop->dgo_rt_cmd_len; i++) {
02275             sprintf(name,"%s ",dgop->dgo_rt_cmd[i]);
02276             strcat(line,name);
02277         }
02278 
02279         CreateProcess(NULL, line, NULL, NULL, TRUE,
02280                       DETACHED_PROCESS, NULL, NULL,
02281                       &si, &pi);
02282 
02283         /* close read end of pipe */
02284         CloseHandle(o_pipe[0]);
02285 
02286         /* close write end of pipes */
02287         (void)CloseHandle(i_pipe[1]);
02288         (void)CloseHandle(e_pipe[1]);
02289 
02290         /* As parent, send view information down pipe */
02291         fp = _fdopen(_open_osfhandle((HFILE)pipe_oDup,_O_TEXT), "wb");
02292         _setmode(_fileno(fp), _O_BINARY);
02293 
02294 #if 1
02295         VSET(temp, 0.0, 0.0, 1.0);
02296         MAT4X3PNT(eye_model, vop->vo_view2model, temp);
02297 #else
02298         dgo_rt_set_eye_model(dgop, vop, eye_model);
02299 #endif
02300         dgo_rt_write(dgop, vop, fp, eye_model);
02301         (void)fclose(fp);
02302 
02303         BU_GETSTRUCT(rtcp, rtcheck);
02304 
02305         /* initialize the rtcheck struct */
02306         rtcp->fd = pipe_iDup;
02307         rtcp->fp = _fdopen( _open_osfhandle((HFILE)pipe_iDup,_O_TEXT), "rb" );
02308         _setmode(_fileno(rtcp->fp), _O_BINARY);
02309         rtcp->hProcess = pi.hProcess;
02310         rtcp->pid = pi.dwProcessId;
02311         rtcp->vbp = rt_vlblock_init();
02312         rtcp->vhead = rt_vlblock_find(rtcp->vbp, 0xFF, 0xFF, 0x00);
02313         rtcp->csize = vop->vo_scale * 0.01;
02314         rtcp->dgop = dgop;
02315         rtcp->interp = interp;
02316 
02317         rtcp->chan = Tcl_MakeFileChannel(pipe_iDup,TCL_READABLE);
02318         Tcl_CreateChannelHandler(rtcp->chan,TCL_READABLE,
02319                                  dgo_rtcheck_vector_handler,
02320                                  (ClientData)rtcp);
02321 
02322         BU_GETSTRUCT(rtcop, rtcheck_output);
02323         rtcop->fd = pipe_eDup;
02324         rtcop->chan = Tcl_MakeFileChannel(pipe_eDup,TCL_READABLE);
02325         rtcop->dgop = dgop;
02326         rtcop->interp = interp;
02327         Tcl_CreateChannelHandler(rtcop->chan,
02328                                  TCL_READABLE,
02329                                  dgo_rtcheck_output_handler,
02330                                  (ClientData)rtcop);
02331         return TCL_OK;
02332 
02333 
02334 #endif
02335 }
02336 
02337 /*
02338  * Usage:
02339  *        procname rtcheck view_obj [args]
02340  */
02341 static int
02342 dgo_rtcheck_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
02343 {
02344         struct dg_obj *dgop = (struct dg_obj *)clientData;
02345         struct view_obj *vop;
02346 
02347         DGO_CHECK_WDBP_NULL(dgop,interp);
02348 
02349         if (argc < 3 || MAXARGS < argc) {
02350                 struct bu_vls vls;
02351 
02352                 bu_vls_init(&vls);
02353                 bu_vls_printf(&vls, "helplib_alias dgo_rtcheck %s", argv[0]);
02354                 Tcl_Eval(interp, bu_vls_addr(&vls));
02355                 bu_vls_free(&vls);
02356 
02357                 return TCL_ERROR;
02358         }
02359 
02360         /* search for view object */
02361         for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
02362                 if (strcmp(bu_vls_addr(&vop->vo_name), argv[2]) == 0)
02363                         break;
02364         }
02365 
02366         if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
02367                 Tcl_AppendResult(interp, "dgo_rtcheck: bad view object - ", argv[2],
02368                                  "\n", (char *)NULL);
02369                 return TCL_ERROR;
02370         }
02371 
02372         return dgo_rtcheck_cmd(dgop, vop, interp, argc-2, argv+2);
02373 }
02374 
02375 /*
02376  * Associate this drawable geometry object with a database object.
02377  *
02378  * Usage:
02379  *        procname assoc [wdb_obj]
02380  */
02381 static int
02382 dgo_assoc_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
02383 {
02384         struct dg_obj *dgop = (struct dg_obj *)clientData;
02385         struct rt_wdb *wdbp;
02386         struct bu_vls vls;
02387 
02388         /* Get associated database object */
02389         if (argc == 2) {
02390                 if (dgop->dgo_wdbp == RT_WDB_NULL)
02391                         Tcl_AppendResult(interp, (char *)NULL);
02392                 else
02393                         Tcl_AppendResult(interp, bu_vls_addr(&dgop->dgo_wdbp->wdb_name), (char *)NULL);
02394                 return TCL_OK;
02395         }
02396 
02397         /* Set associated database object */
02398         if (argc == 3) {
02399                 /* search for database object */
02400                 for (BU_LIST_FOR(wdbp, rt_wdb, &rt_g.rtg_headwdb.l)) {
02401                         if (strcmp(bu_vls_addr(&wdbp->wdb_name), argv[2]) == 0)
02402                                 break;
02403                 }
02404 
02405                 if (BU_LIST_IS_HEAD(wdbp, &rt_g.rtg_headwdb.l))
02406                         wdbp = RT_WDB_NULL;
02407 
02408                 if (dgop->dgo_wdbp != RT_WDB_NULL)
02409                         dgo_zap_cmd(dgop, interp);
02410 
02411                 dgop->dgo_wdbp = wdbp;
02412                 dgo_notify(dgop, interp);
02413 
02414                 return TCL_OK;
02415         }
02416 
02417         /* return help message */
02418         bu_vls_init(&vls);
02419         bu_vls_printf(&vls, "helplib_alias dgo_assoc %s", argv[0]);
02420         Tcl_Eval(interp, bu_vls_addr(&vls));
02421         bu_vls_free(&vls);
02422 
02423         return TCL_ERROR;
02424 }
02425 
02426 int
02427 dgo_observer_cmd(struct dg_obj  *dgop,
02428                  Tcl_Interp     *interp,
02429                  int            argc,
02430                  char           **argv) {
02431     if (argc < 2) {
02432         struct bu_vls vls;
02433 
02434         /* return help message */
02435         bu_vls_init(&vls);
02436         bu_vls_printf(&vls, "helplib_alias dgo_observer %s", argv[0]);
02437         Tcl_Eval(interp, bu_vls_addr(&vls));
02438         bu_vls_free(&vls);
02439         return TCL_ERROR;
02440     }
02441 
02442     return bu_cmd((ClientData)&dgop->dgo_observers,
02443                   interp, argc-1, argv+1, bu_observer_cmds, 0);
02444 }
02445 
02446 /*
02447  * Attach/detach observers to/from list.
02448  *
02449  * Usage:
02450  *        procname observer cmd [args]
02451  *
02452  */
02453 static int
02454 dgo_observer_tcl(ClientData     clientData,
02455                  Tcl_Interp     *interp,
02456                  int            argc,
02457                  char           **argv) {
02458     struct dg_obj *dgop = (struct dg_obj *)clientData;
02459 
02460     return dgo_observer_cmd(dgop, interp, argc-1, argv+1);
02461 }
02462 
02463 int
02464 dgo_report_cmd(struct dg_obj    *dgop,
02465                Tcl_Interp       *interp,
02466                int              argc,
02467                char             **argv)
02468 {
02469         int             lvl = 0;
02470 
02471         if (argc < 1 || 2 < argc) {
02472                 struct bu_vls vls;
02473 
02474                 bu_vls_init(&vls);
02475                 bu_vls_printf(&vls, "helplib_alias dgo_report %s", argv[0]);
02476                 Tcl_Eval(interp, bu_vls_addr(&vls));
02477                 bu_vls_free(&vls);
02478                 return TCL_ERROR;
02479         }
02480 
02481         if (argc == 2)
02482                 lvl = atoi(argv[1]);
02483 
02484         if (lvl <= 3)
02485                 dgo_print_schain(dgop, interp, lvl);
02486         else
02487                 dgo_print_schain_vlcmds(dgop, interp);
02488 
02489         return TCL_OK;
02490 }
02491 
02492 /*
02493  *  Report information about solid table, and per-solid VLS
02494  */
02495 static int
02496 dgo_report_tcl(ClientData clientData, Tcl_Interp *interp, int argc, char **argv)
02497 {
02498         struct dg_obj   *dgop = (struct dg_obj *)clientData;
02499 
02500         DGO_CHECK_WDBP_NULL(dgop,interp);
02501 
02502         return dgo_report_cmd(dgop, interp, argc-1, argv+1);
02503 }
02504 
02505 
02506 #ifndef _WIN32
02507 int
02508 dgo_rtabort_cmd(struct dg_obj   *dgop,
02509                 Tcl_Interp      *interp,
02510                 int             argc,
02511                 char            **argv)
02512 {
02513         struct run_rt   *rrp;
02514 
02515         for (BU_LIST_FOR(rrp, run_rt, &dgop->dgo_headRunRt.l)) {
02516                 kill(rrp->pid, SIGKILL);
02517                 rrp->aborted = 1;
02518         }
02519 
02520         return TCL_OK;
02521 }
02522 #else
02523 int
02524 dgo_rtabort_cmd(struct dg_obj   *dgop,
02525                 Tcl_Interp      *interp,
02526                 int             argc,
02527                 char            **argv)
02528 {
02529         struct run_rt *rrp;
02530         HANDLE hProcess;
02531 
02532         for (BU_LIST_FOR(rrp, run_rt, &dgop->dgo_headRunRt.l)) {
02533                 hProcess= OpenProcess(PROCESS_ALL_ACCESS, TRUE,rrp->pid);
02534                 if(hProcess != NULL)
02535                         TerminateProcess(hProcess, 0);
02536                 rrp->aborted = 1;
02537         }
02538 
02539         return TCL_OK;
02540 }
02541 #endif
02542 
02543 static int
02544 dgo_rtabort_tcl(ClientData clientData,
02545                  Tcl_Interp *interp,
02546                  int argc,
02547                  char **argv)
02548 {
02549         struct dg_obj   *dgop = (struct dg_obj *)clientData;
02550 
02551         return dgo_rtabort_cmd(dgop, interp, argc-1, argv+1);
02552 }
02553 
02554 static int
02555 dgo_qray_tcl(ClientData clientData,
02556              Tcl_Interp *interp,
02557              int        argc,
02558              char       **argv)
02559 {
02560         struct dg_obj *dgop = (struct dg_obj *)clientData;
02561 
02562         DGO_CHECK_WDBP_NULL(dgop,interp);
02563         return dgo_qray_cmd(dgop, interp, argc-1, argv+1);
02564 }
02565 
02566 static int
02567 dgo_nirt_tcl(ClientData clientData,
02568              Tcl_Interp *interp,
02569              int        argc,
02570              char       **argv)
02571 {
02572         struct dg_obj   *dgop = (struct dg_obj *)clientData;
02573         struct view_obj *vop;
02574 
02575         if (argc < 3 || MAXARGS < argc) {
02576                 struct bu_vls vls;
02577 
02578                 bu_vls_init(&vls);
02579                 bu_vls_printf(&vls, "helplib_alias dgo_nirt %s", argv[0]);
02580                 Tcl_Eval(interp, bu_vls_addr(&vls));
02581                 bu_vls_free(&vls);
02582                 return TCL_ERROR;
02583         }
02584 
02585         DGO_CHECK_WDBP_NULL(dgop,interp);
02586 
02587         /* search for view object */
02588         for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
02589                 if (strcmp(bu_vls_addr(&vop->vo_name), argv[2]) == 0)
02590                         break;
02591         }
02592 
02593         if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
02594                 Tcl_AppendResult(interp, "dgo_nirt: bad view object - ", argv[2],
02595                                  "\n", (char *)NULL);
02596                 return TCL_ERROR;
02597         }
02598 
02599         return dgo_nirt_cmd(dgop, vop, interp, argc-2, argv+2);
02600 }
02601 
02602 static int
02603 dgo_vnirt_tcl(ClientData        clientData,
02604               Tcl_Interp        *interp,
02605               int               argc,
02606               char              **argv)
02607 {
02608         struct dg_obj   *dgop = (struct dg_obj *)clientData;
02609         struct view_obj *vop;
02610 
02611         if (argc < 5 || MAXARGS < argc) {
02612                 struct bu_vls vls;
02613 
02614                 bu_vls_init(&vls);
02615                 bu_vls_printf(&vls, "helplib_alias dgo_vnirt %s", argv[0]);
02616                 Tcl_Eval(interp, bu_vls_addr(&vls));
02617                 bu_vls_free(&vls);
02618                 return TCL_ERROR;
02619         }
02620 
02621         DGO_CHECK_WDBP_NULL(dgop,interp);
02622 
02623         /* search for view object */
02624         for (BU_LIST_FOR(vop, view_obj, &HeadViewObj.l)) {
02625                 if (strcmp(bu_vls_addr(&vop->vo_name), argv[2]) == 0)
02626                         break;
02627         }
02628 
02629         if (BU_LIST_IS_HEAD(vop, &HeadViewObj.l)) {
02630                 Tcl_AppendResult(interp, "dgo_vnirt: bad view object - ", argv[2],
02631                                  "\n", (char *)NULL);
02632                 return TCL_ERROR;
02633         }
02634 
02635         return dgo_vnirt_cmd(dgop, vop, interp, argc-2, argv+2);
02636 }
02637 
02638 int
02639 dgo_set_outputHandler_cmd(struct dg_obj *dgop,
02640                           Tcl_Interp    *interp,
02641                           int           argc,
02642                           char          **argv)
02643 {
02644     if (argc < 1 || 2 < argc) {
02645         struct bu_vls vls;
02646 
02647         bu_vls_init(&vls);
02648         bu_vls_printf(&vls, "helplib_alias dgo_set_outputHandler %s", argv[0]);
02649         Tcl_Eval(interp, bu_vls_addr(&vls));
02650         bu_vls_free(&vls);
02651 
02652         return TCL_ERROR;
02653     }
02654 
02655     /* Get the output handler script */
02656     if (argc == 1) {
02657         Tcl_DString ds;
02658 
02659         Tcl_DStringInit(&ds);
02660         if (dgop->dgo_outputHandler != NULL)
02661             Tcl_DStringAppend(&ds, dgop->dgo_outputHandler, -1);
02662         Tcl_DStringResult(interp, &ds);
02663 
02664         return TCL_OK;
02665     }
02666 
02667     /* We're now going to set the output handler script */
02668     /* First, we zap any previous script */
02669     if (dgop->dgo_outputHandler != NULL) {
02670         bu_free((genptr_t)dgop->dgo_outputHandler, "dgo_set_outputHandler: zap");
02671         dgop->dgo_outputHandler = NULL;
02672     }
02673 
02674     if (argv[1] != NULL && argv[1][0] != '\0')
02675         dgop->dgo_outputHandler = bu_strdup(argv[1]);
02676 
02677     return TCL_OK;
02678 }
02679 
02680 /*
02681  * Sets/gets the output handler.
02682  *
02683  * Usage:
02684  *        procname set_outputHandler [script]
02685  */
02686 static int
02687 dgo_set_outputHandler_tcl(ClientData    clientData,
02688                           Tcl_Interp    *interp,
02689                           int           argc,
02690                           char          **argv)
02691 {
02692     struct dg_obj *dgop = (struct dg_obj *)clientData;
02693 
02694     return dgo_set_outputHandler_cmd(dgop, interp, argc-1, argv+1);
02695 }
02696 
02697 int
02698 dgo_set_uplotOutputMode_cmd(struct dg_obj       *dgop,
02699                            Tcl_Interp           *interp,
02700                            int                  argc,
02701                            char                 **argv)
02702 {
02703     if (argc < 1 || 2 < argc) {
02704         struct bu_vls vls;
02705 
02706         bu_vls_init(&vls);
02707         bu_vls_printf(&vls, "helplib_alias dgo_set_plOutputMode %s", argv[0]);
02708         Tcl_Eval(interp, bu_vls_addr(&vls));
02709         bu_vls_free(&vls);
02710 
02711         return TCL_ERROR;
02712     }
02713 
02714     /* Get the plot output mode */
02715     if (argc == 1) {
02716         Tcl_DString ds;
02717 
02718         Tcl_DStringInit(&ds);
02719         if (dgop->dgo_uplotOutputMode == PL_OUTPUT_MODE_BINARY)
02720             Tcl_DStringAppend(&ds, "binary", -1);
02721         else
02722             Tcl_DStringAppend(&ds, "text", -1);
02723         Tcl_DStringResult(interp, &ds);
02724 
02725         return TCL_OK;
02726     }
02727 
02728     if (argv[1][0] == 'b' &&
02729         !strcmp("binary", argv[1]))
02730         dgop->dgo_uplotOutputMode = PL_OUTPUT_MODE_BINARY;
02731     else if (argv[1][0] == 't' &&
02732              !strcmp("text", argv[1]))
02733         dgop->dgo_uplotOutputMode = PL_OUTPUT_MODE_TEXT;
02734     else {
02735         struct bu_vls vls;
02736 
02737         bu_vls_init(&vls);
02738         bu_vls_printf(&vls, "helplib_alias dgo_set_plOutputMode %s", argv[0]);
02739         Tcl_Eval(interp, bu_vls_addr(&vls));
02740         bu_vls_free(&vls);
02741 
02742         return TCL_ERROR;
02743     }
02744 
02745     return TCL_OK;
02746 }
02747 
02748 /*
02749  * Sets/gets the plot output mode.
02750  *
02751  * Usage:
02752  *        procname set_uplotOutput mode [omode]
02753  */
02754 static int
02755 dgo_set_uplotOutputMode_tcl(ClientData  clientData,
02756                            Tcl_Interp   *interp,
02757                            int          argc,
02758                            char         **argv)
02759 {
02760     struct dg_obj *dgop = (struct dg_obj *)clientData;
02761 
02762     return dgo_set_uplotOutputMode_cmd(dgop, interp, argc-1, argv+1);
02763 }
02764 
02765 int
02766 dgo_set_transparency_cmd(struct dg_obj  *dgop,
02767                          Tcl_Interp     *interp,
02768                          int            argc,
02769                          char           **argv)
02770 {
02771         register struct solid *sp;
02772         int i;
02773         struct directory **dpp;
02774         register struct directory **tmp_dpp;
02775         fastf_t transparency;
02776 
02777 
02778         if (argc != 3) {
02779                 struct bu_vls vls;
02780 
02781                 bu_vls_init(&vls);
02782                 bu_vls_printf(&vls, "helplib_alias dgo_set_transparency %s", argv[0]);
02783                 Tcl_Eval(interp, bu_vls_addr(&vls));
02784                 bu_vls_free(&vls);
02785 
02786                 return TCL_ERROR;
02787         }
02788 
02789         if (sscanf(argv[2], "%lf", &transparency) != 1) {
02790                 Tcl_AppendResult(interp, "dgo_set_transparency: bad transparency - ",
02791                                  argv[2], "\n", (char *)NULL);
02792                 return TCL_ERROR;
02793         }
02794 
02795         if ((dpp = dgo_build_dpp(dgop, interp, argv[1])) == NULL) {
02796           return TCL_OK;
02797         }
02798 
02799         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
02800           for (i = 0, tmp_dpp = dpp;
02801                i < sp->s_fullpath.fp_len && *tmp_dpp != DIR_NULL;
02802                ++i, ++tmp_dpp) {
02803             if (sp->s_fullpath.fp_names[i] != *tmp_dpp)
02804               break;
02805           }
02806 
02807           if (*tmp_dpp != DIR_NULL)
02808             continue;
02809 
02810           /* found a match */
02811           sp->s_transparency = transparency;
02812         }
02813 
02814         if (dpp != (struct directory **)NULL)
02815             bu_free((genptr_t)dpp, "dgo_set_transparency_cmd: directory pointers");
02816 
02817         return TCL_OK;
02818 }
02819 
02820 /*
02821  * Sets the transparency of obj.
02822  *
02823  * Usage:
02824  *        procname set_transparency obj t
02825  */
02826 static int
02827 dgo_set_transparency_tcl(ClientData     clientData,
02828                          Tcl_Interp     *interp,
02829                          int            argc,
02830                          char           **argv)
02831 {
02832         struct dg_obj *dgop = (struct dg_obj *)clientData;
02833         int ret;
02834 
02835         if ((ret = dgo_set_transparency_cmd(dgop, interp, argc-1, argv+1)) == TCL_OK)
02836                 dgo_notify(dgop, interp);
02837 
02838         return ret;
02839 }
02840 
02841 int
02842 dgo_shaded_mode_cmd(struct dg_obj       *dgop,
02843                     Tcl_Interp          *interp,
02844                     int                 argc,
02845                     char                **argv)
02846 {
02847   struct bu_vls vls;
02848 
02849   /* get shaded mode */
02850   if (argc == 1) {
02851     bu_vls_init(&vls);
02852     bu_vls_printf(&vls, "%d", dgop->dgo_shaded_mode);
02853     Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)0);
02854     bu_vls_free(&vls);
02855     return TCL_OK;
02856   }
02857 
02858   /* set shaded mode */
02859   if (argc == 2) {
02860     int shaded_mode;
02861 
02862     if (sscanf(argv[1], "%d", &shaded_mode) != 1)
02863       goto bad;
02864 
02865     if (shaded_mode < 0 || 2 < shaded_mode)
02866       goto bad;
02867 
02868     dgop->dgo_shaded_mode = shaded_mode;
02869     return TCL_OK;
02870   }
02871 
02872  bad:
02873   bu_vls_init(&vls);
02874   bu_vls_printf(&vls, "helplib_alias dgo_shaded_mode %s", argv[0]);
02875   Tcl_Eval(interp, bu_vls_addr(&vls));
02876   bu_vls_free(&vls);
02877   return TCL_ERROR;
02878 }
02879 
02880 /*
02881  * Usage:
02882  *        procname shaded_mode [m]
02883  */
02884 static int
02885 dgo_shaded_mode_tcl(ClientData  clientData,
02886                     Tcl_Interp  *interp,
02887                     int         argc,
02888                     char        **argv)
02889 {
02890         struct dg_obj *dgop = (struct dg_obj *)clientData;
02891 
02892         return dgo_shaded_mode_cmd(dgop, interp, argc-1, argv+1);
02893 }
02894 
02895 #if 0
02896 /* skeleton functions for dg_obj methods */
02897 int
02898 dgo__cmd(struct dg_obj  *dgop,
02899          Tcl_Interp     *interp,
02900          int            argc,
02901          char           **argv)
02902 {
02903 }
02904 
02905 /*
02906  * Usage:
02907  *        procname
02908  */
02909 static int
02910 dgo__tcl(ClientData     clientData,
02911          Tcl_Interp     *interp,
02912          int            argc,
02913          char           **argv)
02914 {
02915         struct dg_obj *dgop = (struct dg_obj *)clientData;
02916 
02917         return dgo__cmd(dgop, interp, argc-1, argv+1);
02918 }
02919 #endif
02920 
02921 /****************** Utility Routines ********************/
02922 
02923 static union tree *
02924 dgo_wireframe_region_end(register struct db_tree_state *tsp, struct db_full_path *pathp, union tree *curtree, genptr_t client_data)
02925 {
02926         return (curtree);
02927 }
02928 
02929 /*
02930  *                      D G O _ W I R E F R A M E _ L E A F
02931  *
02932  *  This routine must be prepared to run in parallel.
02933  */
02934 static union tree *
02935 dgo_wireframe_leaf(struct db_tree_state *tsp, struct db_full_path *pathp, struct rt_db_internal *ip, genptr_t client_data)
02936 {
02937         union tree      *curtree;
02938         int             dashflag;               /* draw with dashed lines */
02939         struct bu_list  vhead;
02940         struct dg_client_data *dgcdp = (struct dg_client_data *)client_data;
02941 
02942         RT_CK_TESS_TOL(tsp->ts_ttol);
02943         BN_CK_TOL(tsp->ts_tol);
02944         RT_CK_RESOURCE(tsp->ts_resp);
02945 
02946         BU_LIST_INIT(&vhead);
02947 
02948         if (RT_G_DEBUG&DEBUG_TREEWALK) {
02949                 char    *sofar = db_path_to_string(pathp);
02950 
02951                 Tcl_AppendResult(dgcdp->interp, "dgo_wireframe_leaf(",
02952                                  ip->idb_meth->ft_name,
02953                                  ") path='", sofar, "'\n", (char *)NULL);
02954                 bu_free((genptr_t)sofar, "path string");
02955         }
02956 
02957         if (dgcdp->draw_solid_lines_only)
02958                 dashflag = 0;
02959         else
02960                 dashflag = (tsp->ts_sofar & (TS_SOFAR_MINUS|TS_SOFAR_INTER));
02961 
02962         RT_CK_DB_INTERNAL(ip);
02963 
02964         if (ip->idb_meth->ft_plot(&vhead, ip,
02965                                    tsp->ts_ttol,
02966                                    tsp->ts_tol) < 0) {
02967                 Tcl_AppendResult(dgcdp->interp, DB_FULL_PATH_CUR_DIR(pathp)->d_namep,
02968                                  ": plot failure\n", (char *)NULL);
02969                 return (TREE_NULL);             /* ERROR */
02970         }
02971 
02972         /*
02973          * XXX HACK CTJ - dgo_drawH_part2 sets the default color of a
02974          * solid by looking in tps->ts_mater.ma_color, for pseudo
02975          * solids, this needs to be something different and drawH
02976          * has no idea or need to know what type of solid this is.
02977          */
02978         if (ip->idb_type == ID_GRIP) {
02979                 int r,g,b;
02980                 r= tsp->ts_mater.ma_color[0];
02981                 g= tsp->ts_mater.ma_color[1];
02982                 b= tsp->ts_mater.ma_color[2];
02983                 tsp->ts_mater.ma_color[0] = 0;
02984                 tsp->ts_mater.ma_color[1] = 128;
02985                 tsp->ts_mater.ma_color[2] = 128;
02986                 dgo_drawH_part2(dashflag, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
02987                 tsp->ts_mater.ma_color[0] = r;
02988                 tsp->ts_mater.ma_color[1] = g;
02989                 tsp->ts_mater.ma_color[2] = b;
02990         } else {
02991                 dgo_drawH_part2(dashflag, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
02992         }
02993 
02994         /* Indicate success by returning something other than TREE_NULL */
02995         RT_GET_TREE(curtree, tsp->ts_resp);
02996         curtree->magic = RT_TREE_MAGIC;
02997         curtree->tr_op = OP_NOP;
02998 
02999         return (curtree);
03000 }
03001 
03002 /*
03003  *                      D G O _ N M G _ R E G I O N _ S T A R T
03004  *
03005  *  When performing "ev" on a region, consider whether to process
03006  *  the whole subtree recursively.
03007  *  Normally, say "yes" to all regions by returning 0.
03008  *
03009  *  Check for special case:  a region of one solid, which can be
03010  *  directly drawn as polygons without going through NMGs.
03011  *  If we draw it here, then return -1 to signal caller to ignore
03012  *  further processing of this region.
03013  *  A hack to view polygonal models (converted from FASTGEN) more rapidly.
03014  */
03015 static int
03016 dgo_nmg_region_start(struct db_tree_state *tsp, struct db_full_path *pathp, const struct rt_comb_internal *combp, genptr_t client_data)
03017 {
03018         union tree              *tp;
03019         struct directory        *dp;
03020         struct rt_db_internal   intern;
03021         mat_t                   xform;
03022         matp_t                  matp;
03023         struct bu_list          vhead;
03024         struct dg_client_data *dgcdp = (struct dg_client_data *)client_data;
03025 
03026         if (RT_G_DEBUG&DEBUG_TREEWALK) {
03027                 char    *sofar = db_path_to_string(pathp);
03028                 bu_log("dgo_nmg_region_start(%s)\n", sofar);
03029                 bu_free((genptr_t)sofar, "path string");
03030                 rt_pr_tree( combp->tree, 1 );
03031                 db_pr_tree_state(tsp);
03032         }
03033 
03034         RT_CK_DBI(tsp->ts_dbip);
03035         RT_CK_RESOURCE(tsp->ts_resp);
03036 
03037         BU_LIST_INIT(&vhead);
03038 
03039         RT_CK_COMB(combp);
03040         tp = combp->tree;
03041         if (!tp)
03042                 return( -1 );
03043         RT_CK_TREE(tp);
03044         if (tp->tr_l.tl_op != OP_DB_LEAF)
03045                 return 0;       /* proceed as usual */
03046 
03047         /* The subtree is a single node.  It may be a combination, though */
03048 
03049         /* Fetch by name, check to see if it's an easy type */
03050         dp = db_lookup( tsp->ts_dbip, tp->tr_l.tl_name, LOOKUP_NOISY );
03051         if (!dp)
03052                 return 0;       /* proceed as usual */
03053         if (tsp->ts_mat) {
03054                 if (tp->tr_l.tl_mat) {
03055                         matp = xform;
03056                         bn_mat_mul(xform, tsp->ts_mat, tp->tr_l.tl_mat);
03057                 } else {
03058                         matp = tsp->ts_mat;
03059                 }
03060         } else {
03061                 if (tp->tr_l.tl_mat) {
03062                         matp = tp->tr_l.tl_mat;
03063                 } else {
03064                         matp = (matp_t)NULL;
03065                 }
03066         }
03067         if (rt_db_get_internal(&intern, dp, tsp->ts_dbip, matp, &rt_uniresource) < 0)
03068                 return 0;       /* proceed as usual */
03069 
03070         switch (intern.idb_type) {
03071         case ID_POLY:
03072                 {
03073                         if (RT_G_DEBUG&DEBUG_TREEWALK) {
03074                                 bu_log("fastpath draw ID_POLY %s\n", dp->d_namep);
03075                         }
03076                         if (dgcdp->draw_wireframes) {
03077                                 (void)rt_pg_plot( &vhead, &intern, tsp->ts_ttol, tsp->ts_tol );
03078                         } else {
03079                                 (void)rt_pg_plot_poly( &vhead, &intern, tsp->ts_ttol, tsp->ts_tol );
03080                         }
03081                 }
03082                 goto out;
03083         case ID_BOT:
03084                 {
03085                         if (RT_G_DEBUG&DEBUG_TREEWALK) {
03086                                 bu_log("fastpath draw ID_BOT %s\n", dp->d_namep);
03087                         }
03088                         if (dgcdp->draw_wireframes) {
03089                                 (void)rt_bot_plot( &vhead, &intern, tsp->ts_ttol, tsp->ts_tol );
03090                         } else {
03091                                 (void)rt_bot_plot_poly( &vhead, &intern, tsp->ts_ttol, tsp->ts_tol );
03092                         }
03093                 }
03094                 goto out;
03095         case ID_COMBINATION:
03096         default:
03097                 break;
03098         }
03099         rt_db_free_internal(&intern, tsp->ts_resp);
03100         return 0;
03101 
03102 out:
03103         /* Successful fastpath drawing of this solid */
03104         db_add_node_to_full_path(pathp, dp);
03105         dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
03106         DB_FULL_PATH_POP(pathp);
03107         rt_db_free_internal(&intern, tsp->ts_resp);
03108         dgcdp->fastpath_count++;
03109         return -1;      /* SKIP THIS REGION */
03110 }
03111 
03112 /*
03113  *                      D G O _ N M G _ R E G I O N _ E N D
03114  *
03115  *  This routine must be prepared to run in parallel.
03116  */
03117 static union tree *
03118 dgo_nmg_region_end(register struct db_tree_state *tsp, struct db_full_path *pathp, union tree *curtree, genptr_t client_data)
03119 {
03120         struct nmgregion        *r;
03121         struct bu_list          vhead;
03122         int                     failed;
03123         struct dg_client_data *dgcdp = (struct dg_client_data *)client_data;
03124 
03125         RT_CK_TESS_TOL(tsp->ts_ttol);
03126         BN_CK_TOL(tsp->ts_tol);
03127         NMG_CK_MODEL(*tsp->ts_m);
03128         RT_CK_RESOURCE(tsp->ts_resp);
03129 
03130         BU_LIST_INIT( &vhead );
03131 
03132         if(RT_G_DEBUG&DEBUG_TREEWALK)  {
03133           char  *sofar = db_path_to_string(pathp);
03134 
03135           Tcl_AppendResult(dgcdp->interp, "dgo_nmg_region_end() path='", sofar,
03136                            "'\n", (char *)NULL);
03137           bu_free((genptr_t)sofar, "path string");
03138         } else {
03139           char  *sofar = db_path_to_string(pathp);
03140 
03141           bu_log( "%s:\n", sofar );
03142           bu_free((genptr_t)sofar, "path string");
03143         }
03144 
03145         if( curtree->tr_op == OP_NOP )  return  curtree;
03146 
03147         if ( !dgcdp->draw_nmg_only ) {
03148                 if( BU_SETJUMP )
03149                 {
03150                         char  *sofar = db_path_to_string(pathp);
03151 
03152                         BU_UNSETJUMP;
03153 
03154                         Tcl_AppendResult(dgcdp->interp, "WARNING: Boolean evaluation of ", sofar,
03155                                 " failed!!!\n", (char *)NULL );
03156                         bu_free((genptr_t)sofar, "path string");
03157                         if( curtree )
03158                                 db_free_tree( curtree, tsp->ts_resp );
03159                         return (union tree *)NULL;
03160                 }
03161                 failed = nmg_boolean( curtree, *tsp->ts_m, tsp->ts_tol, tsp->ts_resp );
03162                 BU_UNSETJUMP;
03163                 if( failed )  {
03164                         db_free_tree( curtree, tsp->ts_resp );
03165                         return (union tree *)NULL;
03166                 }
03167         }
03168         else if( curtree->tr_op != OP_NMG_TESS )
03169         {
03170           Tcl_AppendResult(dgcdp->interp, "Cannot use '-d' option when Boolean evaluation is required\n", (char *)NULL);
03171           db_free_tree( curtree, tsp->ts_resp );
03172           return (union tree *)NULL;
03173         }
03174         r = curtree->tr_d.td_r;
03175         NMG_CK_REGION(r);
03176 
03177         if( dgcdp->do_not_draw_nmg_solids_during_debugging && r )  {
03178                 db_free_tree( curtree, tsp->ts_resp );
03179                 return (union tree *)NULL;
03180         }
03181 
03182         if (dgcdp->nmg_triangulate) {
03183                 if (BU_SETJUMP) {
03184                         char  *sofar = db_path_to_string(pathp);
03185 
03186                         BU_UNSETJUMP;
03187 
03188                         Tcl_AppendResult(dgcdp->interp, "WARNING: Triangulation of ", sofar,
03189                                 " failed!!!\n", (char *)NULL );
03190                         bu_free((genptr_t)sofar, "path string");
03191                         if( curtree )
03192                                 db_free_tree( curtree, tsp->ts_resp );
03193                         return (union tree *)NULL;
03194                 }
03195                 nmg_triangulate_model(*tsp->ts_m, tsp->ts_tol);
03196                 BU_UNSETJUMP;
03197         }
03198 
03199         if( r != 0 )  {
03200                 int     style;
03201                 /* Convert NMG to vlist */
03202                 NMG_CK_REGION(r);
03203 
03204                 if (dgcdp->draw_wireframes) {
03205                         /* Draw in vector form */
03206                         style = NMG_VLIST_STYLE_VECTOR;
03207                 } else {
03208                         /* Default -- draw polygons */
03209                         style = NMG_VLIST_STYLE_POLYGON;
03210                 }
03211                 if (dgcdp->draw_normals) {
03212                         style |= NMG_VLIST_STYLE_VISUALIZE_NORMALS;
03213                 }
03214                 if (dgcdp->shade_per_vertex_normals) {
03215                         style |= NMG_VLIST_STYLE_USE_VU_NORMALS;
03216                 }
03217                 if (dgcdp->draw_no_surfaces) {
03218                         style |= NMG_VLIST_STYLE_NO_SURFACES;
03219                 }
03220                 nmg_r_to_vlist(&vhead, r, style);
03221 
03222                 dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
03223 
03224                 if (dgcdp->draw_edge_uses) {
03225                         nmg_vlblock_r(dgcdp->draw_edge_uses_vbp, r, 1);
03226                 }
03227                 /* NMG region is no longer necessary, only vlist remains */
03228                 db_free_tree( curtree, tsp->ts_resp );
03229                 return (union tree *)NULL;
03230         }
03231 
03232         /* Return tree -- it needs to be freed (by caller) */
03233         return curtree;
03234 }
03235 
03236 /*
03237  *                      D G O _ D R A W T R E E S
03238  *
03239  *  This routine is the drawable geometry object's analog of rt_gettrees().
03240  *  Add a set of tree hierarchies to the active set.
03241  *  Note that argv[0] should be ignored, it has the command name in it.
03242  *
03243  *  Kind =
03244  *      1       regular wireframes
03245  *      2       big-E
03246  *      3       NMG polygons
03247  *
03248  *  Returns -
03249  *      0       Ordinarily
03250  *      -1      On major error
03251  */
03252 static int
03253 dgo_drawtrees(struct dg_obj *dgop, Tcl_Interp *interp, int argc, char **argv, int kind, struct dg_client_data *_dgcdp)
03254 {
03255   int           ret = 0;
03256   register int  c;
03257   int           ncpu = 1;
03258   int           dgo_nmg_use_tnurbs = 0;
03259   int           dgo_enable_fastpath = 0;
03260   struct model  *dgo_nmg_model;
03261   struct dg_client_data *dgcdp;
03262   RT_CHECK_DBI(dgop->dgo_wdbp->dbip);
03263 
03264   if (argc <= 0)
03265     return(-1); /* FAIL */
03266 
03267   /* options are already parsed into _dgcdp */
03268   if (_dgcdp != (struct dg_client_data *)0) {
03269     BU_GETSTRUCT(dgcdp, dg_client_data);
03270     *dgcdp = *_dgcdp;            /* struct copy */
03271   } else {
03272 
03273     BU_GETSTRUCT(dgcdp, dg_client_data);
03274     dgcdp->dgop = dgop;
03275     dgcdp->interp = interp;
03276 
03277     /* Initial values for options, must be reset each time */
03278     dgcdp->draw_nmg_only = 0;   /* no booleans */
03279     dgcdp->nmg_triangulate = 1;
03280     dgcdp->draw_wireframes = 0;
03281     dgcdp->draw_normals = 0;
03282     dgcdp->draw_solid_lines_only = 0;
03283     dgcdp->draw_no_surfaces = 0;
03284     dgcdp->shade_per_vertex_normals = 0;
03285     dgcdp->draw_edge_uses = 0;
03286     dgcdp->wireframe_color_override = 0;
03287     dgcdp->fastpath_count = 0;
03288 
03289     /* default color - red */
03290     dgcdp->wireframe_color[0] = 255;
03291     dgcdp->wireframe_color[1] = 0;
03292     dgcdp->wireframe_color[2] = 0;
03293 
03294     /* default transparency - opaque */
03295     dgcdp->transparency = 1.0;
03296 
03297     /* -1 indicates flag not set */
03298     dgcdp->shaded_mode_override = -1;
03299 
03300     dgo_enable_fastpath = 0;
03301 
03302     /* Parse options. */
03303     bu_optind = 0;              /* re-init bu_getopt() */
03304     while ((c = bu_getopt(argc,argv,"dfm:nqstuvwx:C:STP:")) != EOF) {
03305       switch (c) {
03306         case 'u':
03307           dgcdp->draw_edge_uses = 1;
03308           break;
03309         case 's':
03310           dgcdp->draw_solid_lines_only = 1;
03311           break;
03312         case 't':
03313           dgo_nmg_use_tnurbs = 1;
03314           break;
03315         case 'v':
03316           dgcdp->shade_per_vertex_normals = 1;
03317           break;
03318         case 'w':
03319           dgcdp->draw_wireframes = 1;
03320           break;
03321         case 'S':
03322           dgcdp->draw_no_surfaces = 1;
03323           break;
03324         case 'T':
03325           dgcdp->nmg_triangulate = 0;
03326           break;
03327         case 'n':
03328           dgcdp->draw_normals = 1;
03329           break;
03330         case 'P':
03331           ncpu = atoi(bu_optarg);
03332           break;
03333         case 'q':
03334           dgcdp->do_not_draw_nmg_solids_during_debugging = 1;
03335           break;
03336         case 'd':
03337           dgcdp->draw_nmg_only = 1;
03338           break;
03339         case 'f':
03340           dgo_enable_fastpath = 1;
03341           break;
03342         case 'C':
03343           {
03344             int         r,g,b;
03345             register char       *cp = bu_optarg;
03346 
03347             r = atoi(cp);
03348             while( (*cp >= '0' && *cp <= '9') )  cp++;
03349             while( *cp && (*cp < '0' || *cp > '9') ) cp++;
03350             g = atoi(cp);
03351             while( (*cp >= '0' && *cp <= '9') )  cp++;
03352             while( *cp && (*cp < '0' || *cp > '9') ) cp++;
03353             b = atoi(cp);
03354 
03355             if( r < 0 || r > 255 )  r = 255;
03356             if( g < 0 || g > 255 )  g = 255;
03357             if( b < 0 || b > 255 )  b = 255;
03358 
03359             dgcdp->wireframe_color_override = 1;
03360             dgcdp->wireframe_color[0] = r;
03361             dgcdp->wireframe_color[1] = g;
03362             dgcdp->wireframe_color[2] = b;
03363           }
03364           break;
03365         case 'm':
03366           /* clamp it to [-infinity,2] */
03367           dgcdp->shaded_mode_override = atoi(bu_optarg);
03368           if (2 < dgcdp->shaded_mode_override)
03369             dgcdp->shaded_mode_override = 2;
03370 
03371           break;
03372         case 'x':
03373           dgcdp->transparency = atof(bu_optarg);
03374 
03375           /* clamp it to [0,1] */
03376           if (dgcdp->transparency < 0.0)
03377             dgcdp->transparency = 0.0;
03378 
03379           if (1.0 < dgcdp->transparency)
03380             dgcdp->transparency = 1.0;
03381 
03382           break;
03383         default:
03384           {
03385             struct bu_vls vls;
03386 
03387             bu_vls_init(&vls);
03388             bu_vls_printf(&vls, "helplib %s", argv[0]);
03389             Tcl_Eval(interp, bu_vls_addr(&vls));
03390             bu_vls_free(&vls);
03391             bu_free((genptr_t)dgcdp, "dgo_drawtrees: dgcdp");
03392 
03393             return TCL_ERROR;
03394           }
03395       }
03396     }
03397     argc -= bu_optind;
03398     argv += bu_optind;
03399 
03400     switch (kind) {
03401       case 1:
03402         if (dgop->dgo_shaded_mode && dgcdp->shaded_mode_override < 0) {
03403           dgcdp->dmode = dgop->dgo_shaded_mode;
03404         } else if (0 <= dgcdp->shaded_mode_override)
03405           dgcdp->dmode = dgcdp->shaded_mode_override;
03406         else
03407           dgcdp->dmode = DGO_WIREFRAME;
03408 
03409         break;
03410       case 2:
03411       case 3:
03412         dgcdp->dmode = DGO_BOOL_EVAL;
03413         break;
03414     }
03415 
03416   }
03417 
03418   switch (kind) {
03419     default:
03420       Tcl_AppendResult(interp, "ERROR, bad kind\n", (char *)NULL);
03421       bu_free((genptr_t)dgcdp, "dgo_drawtrees: dgcdp");
03422       return(-1);
03423     case 1:             /* Wireframes */
03424       /*
03425        * If asking for wireframe and in shaded_mode and no shaded mode override,
03426        * or asking for wireframe and shaded mode is being overridden with a value
03427        * greater than 0, then draw shaded polygons for each object's primitives if possible.
03428        *
03429        * Note -
03430        * If shaded_mode is DGO_SHADED_MODE_BOTS, only BOTS and polysolids
03431        * will be shaded. The rest is drawn as wireframe.
03432        * If shaded_mode is DGO_SHADED_MODE_ALL, everything except pipe solids
03433        * are drawn as shaded polygons.
03434        */
03435       if (DGO_SHADED_MODE_BOTS <= dgcdp->dmode && dgcdp->dmode <= DGO_SHADED_MODE_ALL) {
03436         int  i;
03437         int  ac = 1;
03438         char *av[2];
03439 #if 0
03440         struct directory *dp;
03441 #endif
03442 
03443         av[1] = (char *)0;
03444 
03445         for (i = 0; i < argc; ++i) {
03446 #if 0
03447           if ((dp = db_lookup(dgop->dgo_wdbp->dbip, argv[i], LOOKUP_NOISY)) == DIR_NULL)
03448             continue;
03449 #endif
03450 
03451           av[0] = argv[i];
03452 
03453           ret = db_walk_tree(dgop->dgo_wdbp->dbip,
03454                              ac,
03455                              (const char **)av,
03456                              ncpu,
03457                              &dgop->dgo_wdbp->wdb_initial_tree_state,
03458                              0,
03459                              dgo_bot_check_region_end,
03460                              dgo_bot_check_leaf,
03461                              (genptr_t)dgcdp);
03462         }
03463       } else
03464         ret = db_walk_tree(dgop->dgo_wdbp->dbip,
03465                            argc,
03466                            (const char **)argv,
03467                            ncpu,
03468                            &dgop->dgo_wdbp->wdb_initial_tree_state,
03469                            0,                   /* take all regions */
03470                            dgo_wireframe_region_end,
03471                            dgo_wireframe_leaf,
03472                            (genptr_t)dgcdp);
03473       break;
03474     case 2:             /* Big-E */
03475       Tcl_AppendResult(interp, "drawtrees:  can't do big-E here\n", (char *)NULL);
03476       bu_free((genptr_t)dgcdp, "dgo_drawtrees: dgcdp");
03477       return (-1);
03478     case 3:
03479       {
03480         /* NMG */
03481         dgo_nmg_model = nmg_mm();
03482         dgop->dgo_wdbp->wdb_initial_tree_state.ts_m = &dgo_nmg_model;
03483         if (dgcdp->draw_edge_uses) {
03484           Tcl_AppendResult(interp, "Doing the edgeuse thang (-u)\n", (char *)NULL);
03485           dgcdp->draw_edge_uses_vbp = rt_vlblock_init();
03486         }
03487 
03488         ret = db_walk_tree(dgop->dgo_wdbp->dbip, argc, (const char **)argv,
03489                            ncpu,
03490                            &dgop->dgo_wdbp->wdb_initial_tree_state,
03491                            dgo_enable_fastpath ? dgo_nmg_region_start : 0,
03492                            dgo_nmg_region_end,
03493                            dgo_nmg_use_tnurbs ? nmg_booltree_leaf_tnurb : nmg_booltree_leaf_tess,
03494                            (genptr_t)dgcdp);
03495 
03496         if (dgcdp->draw_edge_uses) {
03497           dgo_cvt_vlblock_to_solids(dgop, interp, dgcdp->draw_edge_uses_vbp, "_EDGEUSES_", 0);
03498           rt_vlblock_free(dgcdp->draw_edge_uses_vbp);
03499           dgcdp->draw_edge_uses_vbp = (struct bn_vlblock *)NULL;
03500         }
03501 
03502         /* Destroy NMG */
03503         nmg_km(dgo_nmg_model);
03504         break;
03505       }
03506   }
03507   if (dgcdp->fastpath_count) {
03508     bu_log("%d region%s rendered through polygon fastpath\n",
03509            dgcdp->fastpath_count, dgcdp->fastpath_count==1?"":"s");
03510   }
03511 
03512   bu_free((genptr_t)dgcdp, "dgo_drawtrees: dgcdp");
03513 
03514   if (ret < 0)
03515     return (-1);
03516 
03517   return (0);   /* OK */
03518 }
03519 
03520 
03521 /*
03522  *                      C V T _ V L B L O C K _ T O _ S O L I D S
03523  */
03524 void
03525 dgo_cvt_vlblock_to_solids(struct dg_obj *dgop, Tcl_Interp *interp, struct bn_vlblock *vbp, char *name, int copy)
03526 {
03527         int             i;
03528         char            shortname[32];
03529         char            namebuf[64];
03530 
03531         strncpy(shortname, name, 16-6);
03532         shortname[16-6] = '\0';
03533 
03534         for( i=0; i < vbp->nused; i++ )  {
03535                 if (BU_LIST_IS_EMPTY(&(vbp->head[i])))
03536                         continue;
03537 
03538                 sprintf(namebuf, "%s%lx",
03539                         shortname, vbp->rgb[i]);
03540                 dgo_invent_solid(dgop, interp, namebuf, &vbp->head[i], vbp->rgb[i], copy, 0.0, 0);
03541         }
03542 }
03543 
03544 /*
03545  *                      I N V E N T _ S O L I D
03546  *
03547  *  Invent a solid by adding a fake entry in the database table,
03548  *  adding an entry to the solid table, and populating it with
03549  *  the given vector list.
03550  *
03551  *  This parallels much of the code in dodraw.c
03552  */
03553 int
03554 dgo_invent_solid(struct dg_obj  *dgop,
03555                  Tcl_Interp     *interp,
03556                  char           *name,
03557                  struct bu_list *vhead,
03558                  long int       rgb,
03559                  int            copy,
03560                  fastf_t        transparency,
03561                  int            dmode)
03562 {
03563         register struct directory       *dp;
03564         struct directory                *dpp[2] = {DIR_NULL, DIR_NULL};
03565         register struct solid           *sp;
03566         unsigned char                   type='0';
03567 
03568         if (dgop->dgo_wdbp->dbip == DBI_NULL)
03569                 return 0;
03570 
03571         if ((dp = db_lookup(dgop->dgo_wdbp->dbip, name, LOOKUP_QUIET)) != DIR_NULL) {
03572                 if (dp->d_addr != RT_DIR_PHONY_ADDR) {
03573                         Tcl_AppendResult(interp, "dgo_invent_solid(", name,
03574                                          ") would clobber existing database entry, ignored\n", (char *)NULL);
03575                         return (-1);
03576                 }
03577 
03578                 /*
03579                  * Name exists from some other overlay,
03580                  * zap any associated solids
03581                  */
03582                 dpp[0] = dp;
03583                 dgo_eraseobjall(dgop, interp, dpp);
03584         }
03585         /* Need to enter phony name in directory structure */
03586         dp = db_diradd(dgop->dgo_wdbp->dbip,  name, RT_DIR_PHONY_ADDR, 0, DIR_SOLID, (genptr_t)&type);
03587 
03588         /* Obtain a fresh solid structure, and fill it in */
03589         GET_SOLID(sp,&FreeSolid.l);
03590 
03591         if (copy) {
03592                 BU_LIST_INIT( &(sp->s_vlist) );
03593                 rt_vlist_copy( &(sp->s_vlist), vhead );
03594         } else {
03595                 /* For efficiency, just swipe the vlist */
03596                 BU_LIST_APPEND_LIST( &(sp->s_vlist), vhead );
03597                 BU_LIST_INIT(vhead);
03598         }
03599         dgo_bound_solid(interp, sp);
03600 
03601         /* set path information -- this is a top level node */
03602         db_add_node_to_full_path( &sp->s_fullpath, dp );
03603 
03604         sp->s_iflag = DOWN;
03605         sp->s_soldash = 0;
03606         sp->s_Eflag = 1;                /* Can't be solid edited! */
03607         sp->s_color[0] = sp->s_basecolor[0] = (rgb>>16) & 0xFF;
03608         sp->s_color[1] = sp->s_basecolor[1] = (rgb>> 8) & 0xFF;
03609         sp->s_color[2] = sp->s_basecolor[2] = (rgb    ) & 0xFF;
03610         sp->s_regionid = 0;
03611         sp->s_dlist = BU_LIST_LAST(solid, &dgop->dgo_headSolid)->s_dlist + 1;
03612 
03613         sp->s_uflag = 0;
03614         sp->s_dflag = 0;
03615         sp->s_cflag = 0;
03616         sp->s_wflag = 0;
03617 
03618         sp->s_transparency = transparency;
03619         sp->s_dmode = dmode;
03620 
03621         /* Solid successfully drawn, add to linked list of solid structs */
03622         BU_LIST_APPEND(dgop->dgo_headSolid.back, &sp->l);
03623 
03624         return (0);             /* OK */
03625 }
03626 
03627 /*
03628  *  Compute the min, max, and center points of the solid.
03629  *  Also finds s_vlen;
03630  * XXX Should split out a separate bn_vlist_rpp() routine, for librt/vlist.c
03631  */
03632 static void
03633 dgo_bound_solid(Tcl_Interp *interp, register struct solid *sp)
03634 {
03635         register struct bn_vlist        *vp;
03636         register double                 xmax, ymax, zmax;
03637         register double                 xmin, ymin, zmin;
03638 
03639         xmax = ymax = zmax = -INFINITY;
03640         xmin = ymin = zmin =  INFINITY;
03641         sp->s_vlen = 0;
03642         for (BU_LIST_FOR(vp, bn_vlist, &(sp->s_vlist))) {
03643                 register int    j;
03644                 register int    nused = vp->nused;
03645                 register int    *cmd = vp->cmd;
03646                 register point_t *pt = vp->pt;
03647                 for (j = 0; j < nused; j++,cmd++,pt++) {
03648                         switch (*cmd) {
03649                         case BN_VLIST_POLY_START:
03650                         case BN_VLIST_POLY_VERTNORM:
03651                                 /* Has normal vector, not location */
03652                                 break;
03653                         case BN_VLIST_LINE_MOVE:
03654                         case BN_VLIST_LINE_DRAW:
03655                         case BN_VLIST_POLY_MOVE:
03656                         case BN_VLIST_POLY_DRAW:
03657                         case BN_VLIST_POLY_END:
03658                                 V_MIN(xmin, (*pt)[X]);
03659                                 V_MAX(xmax, (*pt)[X]);
03660                                 V_MIN(ymin, (*pt)[Y]);
03661                                 V_MAX(ymax, (*pt)[Y]);
03662                                 V_MIN(zmin, (*pt)[Z]);
03663                                 V_MAX(zmax, (*pt)[Z]);
03664                                 break;
03665                         default:
03666                                 {
03667                                         struct bu_vls tmp_vls;
03668 
03669                                         bu_vls_init(&tmp_vls);
03670                                         bu_vls_printf(&tmp_vls, "unknown vlist op %d\n", *cmd);
03671                                         Tcl_AppendResult(interp, bu_vls_addr(&tmp_vls), (char *)NULL);
03672                                         bu_vls_free(&tmp_vls);
03673                                 }
03674                         }
03675                 }
03676                 sp->s_vlen += nused;
03677         }
03678 
03679         sp->s_center[X] = (xmin + xmax) * 0.5;
03680         sp->s_center[Y] = (ymin + ymax) * 0.5;
03681         sp->s_center[Z] = (zmin + zmax) * 0.5;
03682 
03683         sp->s_size = xmax - xmin;
03684         V_MAX( sp->s_size, ymax - ymin );
03685         V_MAX( sp->s_size, zmax - zmin );
03686 }
03687 
03688 /*
03689  *                      D M O _ D R A W h _ P A R T 2
03690  *
03691  *  Once the vlist has been created, perform the common tasks
03692  *  in handling the drawn solid.
03693  *
03694  *  This routine must be prepared to run in parallel.
03695  */
03696 void
03697 dgo_drawH_part2(int dashflag, struct bu_list *vhead, struct db_full_path *pathp, struct db_tree_state *tsp, struct solid *existing_sp, struct dg_client_data *dgcdp)
03698 {
03699         register struct solid *sp;
03700 
03701         if (!existing_sp) {
03702                 /* Handling a new solid */
03703                 GET_SOLID(sp, &FreeSolid.l);
03704                 /* NOTICE:  The structure is dirty & not initialized for you! */
03705 
03706                 sp->s_dlist = BU_LIST_LAST(solid, &dgcdp->dgop->dgo_headSolid)->s_dlist + 1;
03707         } else {
03708                 /* Just updating an existing solid.
03709                  *  'tsp' and 'pathpos' will not be used
03710                  */
03711                 sp = existing_sp;
03712         }
03713 
03714 
03715         /*
03716          * Compute the min, max, and center points.
03717          */
03718         BU_LIST_APPEND_LIST(&(sp->s_vlist), vhead);
03719         dgo_bound_solid(dgcdp->interp, sp);
03720 
03721         /*
03722          *  If this solid is new, fill in it's information.
03723          *  Otherwise, don't touch what is already there.
03724          */
03725         if (!existing_sp) {
03726                 /* Take note of the base color */
03727                 if (dgcdp->wireframe_color_override) {
03728                         /* a user specified the color, so arrange to use it */
03729                         sp->s_uflag = 1;
03730                         sp->s_dflag = 0;
03731                         sp->s_basecolor[0] = dgcdp->wireframe_color[0];
03732                         sp->s_basecolor[1] = dgcdp->wireframe_color[1];
03733                         sp->s_basecolor[2] = dgcdp->wireframe_color[2];
03734                 } else {
03735                         sp->s_uflag = 0;
03736                         if (tsp) {
03737                                 if (tsp->ts_mater.ma_color_valid) {
03738                                         sp->s_dflag = 0;        /* color specified in db */
03739                                         sp->s_basecolor[0] = tsp->ts_mater.ma_color[0] * 255.;
03740                                         sp->s_basecolor[1] = tsp->ts_mater.ma_color[1] * 255.;
03741                                         sp->s_basecolor[2] = tsp->ts_mater.ma_color[2] * 255.;
03742                                 } else {
03743                                         sp->s_dflag = 1;        /* default color */
03744                                         sp->s_basecolor[0] = 255;
03745                                         sp->s_basecolor[1] = 0;
03746                                         sp->s_basecolor[2] = 0;
03747                                 }
03748                         }
03749                 }
03750                 sp->s_cflag = 0;
03751                 sp->s_flag = DOWN;
03752                 sp->s_iflag = DOWN;
03753                 sp->s_soldash = dashflag;
03754                 sp->s_Eflag = 0;        /* This is a solid */
03755                 db_dup_full_path( &sp->s_fullpath, pathp );
03756                 sp->s_regionid = tsp->ts_regionid;
03757                 sp->s_transparency = dgcdp->transparency;
03758                 sp->s_dmode = dgcdp->dmode;
03759 
03760                 /* Add to linked list of solid structs */
03761                 bu_semaphore_acquire(RT_SEM_MODEL);
03762                 BU_LIST_APPEND(dgcdp->dgop->dgo_headSolid.back, &sp->l);
03763                 bu_semaphore_release(RT_SEM_MODEL);
03764         }
03765 
03766 #if 0
03767         /* Solid is successfully drawn */
03768         if (!existing_sp) {
03769                 /* Add to linked list of solid structs */
03770                 bu_semaphore_acquire(RT_SEM_MODEL);
03771                 BU_LIST_APPEND(dgcdp->dgop->dgo_headSolid.back, &sp->l);
03772                 bu_semaphore_release(RT_SEM_MODEL);
03773         } else {
03774                 /* replacing existing solid -- struct already linked in */
03775                 sp->s_flag = UP;
03776         }
03777 #endif
03778 }
03779 
03780 /*
03781  * This looks for a drawable geometry object that has a matching "dbip"
03782  * and deletes the solids corresponding to "dp" from the solid list.
03783  * At the moment this is being called from wdb_obj.c/wdb_kill_tcl() if the
03784  * object is not phony.
03785  */
03786 void
03787 dgo_eraseobjall_callback(struct db_i            *dbip,
03788                          Tcl_Interp             *interp,
03789                          struct directory       *dp,
03790                          int                    notify)
03791 {
03792         struct dg_obj           *dgop;
03793         struct directory        *dpp[2] = {DIR_NULL, DIR_NULL};
03794 
03795         dpp[0] = dp;
03796         for (BU_LIST_FOR(dgop, dg_obj, &HeadDGObj.l))
03797                 /* drawable geometry objects associated database matches */
03798                 if (dgop->dgo_wdbp->dbip == dbip) {
03799                         dgo_eraseobjall(dgop, interp, dpp);
03800 
03801                         if (notify)
03802                             dgo_notify(dgop, interp);
03803                 }
03804 }
03805 
03806 /*
03807  * Builds an array of directory pointers from argv and calls
03808  * either dgo_eraseobj or dgo_eraseobjall.
03809  */
03810 void
03811 dgo_eraseobjpath(struct dg_obj  *dgop,
03812                  Tcl_Interp     *interp,
03813                  int            argc,
03814                  char           **argv,
03815                  int            noisy,
03816                  int            all)
03817 {
03818         register struct directory *dp;
03819         register int i;
03820         struct bu_vls vls;
03821 #if 0
03822         Tcl_Obj *save_result;
03823 
03824         save_result = Tcl_GetObjResult(interp);
03825         Tcl_IncrRefCount(save_result);
03826 #endif
03827 
03828                 bu_vls_init(&vls);
03829         for (i = 0; i < argc; i++) {
03830                 int j;
03831                 char *list;
03832                 int ac;
03833                 char **av, **av_orig;
03834                 struct directory **dpp = (struct directory **)0;
03835 
03836 #if 0
03837                 bu_vls_trunc(&vls, 0);
03838                 bu_vls_printf(&vls, "split %s /", argv[i]);
03839                 if (Tcl_Eval(interp, bu_vls_addr(&vls)) != TCL_OK) {
03840                         continue;
03841                 }
03842                 list = Tcl_GetStringResult(interp);
03843 #else
03844                 {
03845                         char *begin;
03846                         char *end;
03847                         char *newstr = strdup(argv[i]);
03848 
03849                         begin = newstr;
03850                         bu_vls_trunc(&vls, 0);
03851 
03852                         while ((end = strchr(begin, '/')) != NULL) {
03853                                 *end = '\0';
03854                                 bu_vls_printf(&vls, "%s ", begin);
03855                                 begin = end + 1;
03856                         }
03857                         bu_vls_printf(&vls, "%s ", begin);
03858                         free((void *)newstr);
03859                 }
03860                 list = bu_vls_addr(&vls);
03861 #endif
03862                 if (Tcl_SplitList(interp, list, &ac, (const char ***)&av_orig) != TCL_OK)
03863                         continue;
03864 
03865                 /* make sure we will not dereference null */
03866                 if ( ( ac == 0 ) || (av_orig == 0) || ( *av_orig == 0 ) ) {
03867                         bu_log("WARNING: Asked to look up a null-named database object\n");
03868                         goto end;
03869                 }
03870 
03871                 /* skip first element if empty */
03872                 av = av_orig;
03873 
03874                 if (*av[0] == '\0') {
03875                         --ac;
03876                         ++av;
03877                 }
03878 
03879                 /* ignore last element if empty */
03880                 if (*av[ac-1] == '\0')
03881                         --ac;
03882 
03883                 dpp = bu_calloc(ac+1, sizeof(struct directory *), "eraseobjpath: directory pointers");
03884                 for (j = 0; j < ac; ++j)
03885                         if ((dp = db_lookup(dgop->dgo_wdbp->dbip, av[j], noisy)) != DIR_NULL)
03886                                 dpp[j] = dp;
03887                         else
03888                                 goto end;
03889 
03890                 dpp[j] = DIR_NULL;
03891 
03892                 if (all)
03893                         dgo_eraseobjall(dgop, interp, dpp);
03894                 else
03895                         dgo_eraseobj(dgop, interp, dpp);
03896 
03897         end:
03898                 bu_free((genptr_t)dpp, "eraseobjpath: directory pointers");
03899                 Tcl_Free((char *)av_orig);
03900         }
03901         bu_vls_free(&vls);
03902 
03903 #if 0
03904         Tcl_SetObjResult(interp, save_result);
03905         Tcl_DecrRefCount(save_result);
03906 #endif
03907 }
03908 
03909 /*
03910  *                      E R A S E O B J A L L
03911  *
03912  * This routine goes through the solid table and deletes all solids
03913  * from the solid list which contain the specified object anywhere in their 'path'
03914  */
03915 static void
03916 dgo_eraseobjall(struct dg_obj                   *dgop,
03917                 Tcl_Interp                      *interp,
03918                 register struct directory       **dpp)
03919 {
03920         register struct directory **tmp_dpp;
03921         register struct solid *sp;
03922         register struct solid *nsp;
03923         struct db_full_path     subpath;
03924 
03925         if(dgop->dgo_wdbp->dbip == DBI_NULL)
03926                 return;
03927 
03928         if (*dpp == DIR_NULL)
03929                 return;
03930 
03931         db_full_path_init(&subpath);
03932         for (tmp_dpp = dpp; *tmp_dpp != DIR_NULL; ++tmp_dpp)  {
03933                 RT_CK_DIR(*tmp_dpp);
03934                 db_add_node_to_full_path(&subpath, *tmp_dpp);
03935         }
03936 
03937         sp = BU_LIST_NEXT(solid, &dgop->dgo_headSolid);
03938         while (BU_LIST_NOT_HEAD(sp, &dgop->dgo_headSolid)) {
03939                 nsp = BU_LIST_PNEXT(solid, sp);
03940                 if( db_full_path_subset( &sp->s_fullpath, &subpath ) )  {
03941                         BU_LIST_DEQUEUE(&sp->l);
03942                         FREE_SOLID(sp, &FreeSolid.l);
03943                 }
03944                 sp = nsp;
03945         }
03946 
03947         if ((*dpp)->d_addr == RT_DIR_PHONY_ADDR) {
03948                 if (db_dirdelete(dgop->dgo_wdbp->dbip, *dpp) < 0) {
03949                         Tcl_AppendResult(interp, "dgo_eraseobjall: db_dirdelete failed\n", (char *)NULL);
03950                 }
03951         }
03952         db_free_full_path(&subpath);
03953 }
03954 
03955 /*
03956  *                      E R A S E O B J
03957  *
03958  * This routine goes through the solid table and deletes all solids
03959  * from the solid list which contain the specified object at the
03960  * beginning of their 'path'
03961  */
03962 static void
03963 dgo_eraseobj(struct dg_obj              *dgop,
03964              Tcl_Interp                 *interp,
03965              register struct directory  **dpp)
03966 {
03967 #if 1
03968         /*XXX
03969          * Temporarily put back the old behavior (as seen in Brlcad5.3),
03970          * as the behavior after the #else is identical to dgo_eraseobjall.
03971          */
03972         register struct directory **tmp_dpp;
03973         register struct solid *sp;
03974         register struct solid *nsp;
03975         register int i;
03976 
03977         if(dgop->dgo_wdbp->dbip == DBI_NULL)
03978                 return;
03979 
03980         if (*dpp == DIR_NULL)
03981                 return;
03982 
03983         for (tmp_dpp = dpp; *tmp_dpp != DIR_NULL; ++tmp_dpp)
03984                 RT_CK_DIR(*tmp_dpp);
03985 
03986         sp = BU_LIST_FIRST(solid, &dgop->dgo_headSolid);
03987         while (BU_LIST_NOT_HEAD(sp, &dgop->dgo_headSolid)) {
03988                 nsp = BU_LIST_PNEXT(solid, sp);
03989                 for (i = 0, tmp_dpp = dpp;
03990                      i < sp->s_fullpath.fp_len && *tmp_dpp != DIR_NULL;
03991                      ++i, ++tmp_dpp)
03992                         if (sp->s_fullpath.fp_names[i] != *tmp_dpp)
03993                                 goto end;
03994 
03995                 if (*tmp_dpp != DIR_NULL)
03996                         goto end;
03997 
03998                 BU_LIST_DEQUEUE(&sp->l);
03999                 FREE_SOLID(sp, &FreeSolid.l);
04000         end:
04001                 sp = nsp;
04002         }
04003 
04004         if ((*dpp)->d_addr == RT_DIR_PHONY_ADDR ) {
04005                 if (db_dirdelete(dgop->dgo_wdbp->dbip, *dpp) < 0) {
04006                         Tcl_AppendResult(interp, "dgo_eraseobj: db_dirdelete failed\n", (char *)NULL);
04007                 }
04008         }
04009 #else
04010         register struct directory **tmp_dpp;
04011         register struct solid *sp;
04012         register struct solid *nsp;
04013         struct db_full_path     subpath;
04014 
04015         if(dgop->dgo_wdbp->dbip == DBI_NULL)
04016                 return;
04017 
04018         if (*dpp == DIR_NULL)
04019                 return;
04020 
04021         db_full_path_init(&subpath);
04022         for (tmp_dpp = dpp; *tmp_dpp != DIR_NULL; ++tmp_dpp)  {
04023                 RT_CK_DIR(*tmp_dpp);
04024                 db_add_node_to_full_path(&subpath, *tmp_dpp);
04025         }
04026 
04027         sp = BU_LIST_FIRST(solid, &dgop->dgo_headSolid);
04028         while (BU_LIST_NOT_HEAD(sp, &dgop->dgo_headSolid)) {
04029                 nsp = BU_LIST_PNEXT(solid, sp);
04030                 if( db_full_path_subset( &sp->s_fullpath, &subpath ) )  {
04031                         BU_LIST_DEQUEUE(&sp->l);
04032                         FREE_SOLID(sp, &FreeSolid.l);
04033                 }
04034                 sp = nsp;
04035         }
04036 
04037         if ((*dpp)->d_addr == RT_DIR_PHONY_ADDR ) {
04038                 if (db_dirdelete(dgop->dgo_wdbp->dbip, *dpp) < 0) {
04039                         Tcl_AppendResult(interp, "dgo_eraseobj: db_dirdelete failed\n", (char *)NULL);
04040                 }
04041         }
04042         db_free_full_path(&subpath);
04043 #endif
04044 }
04045 
04046 /*
04047  *                      C O L O R _ S O L T A B
04048  *
04049  *  Pass through the solid table and set pointer to appropriate
04050  *  mater structure.
04051  */
04052 void
04053 dgo_color_soltab(struct solid *hsp)
04054 {
04055         register struct solid *sp;
04056         register struct mater *mp;
04057 
04058         FOR_ALL_SOLIDS(sp, &hsp->l) {
04059                 sp->s_cflag = 0;
04060 
04061                 /* the user specified the color, so use it */
04062                 if (sp->s_uflag) {
04063                         sp->s_color[0] = sp->s_basecolor[0];
04064                         sp->s_color[1] = sp->s_basecolor[1];
04065                         sp->s_color[2] = sp->s_basecolor[2];
04066                         continue;
04067                 }
04068 
04069                 for (mp = rt_material_head; mp != MATER_NULL; mp = mp->mt_forw) {
04070                         if (sp->s_regionid <= mp->mt_high &&
04071                             sp->s_regionid >= mp->mt_low) {
04072                                 sp->s_color[0] = mp->mt_r;
04073                                 sp->s_color[1] = mp->mt_g;
04074                                 sp->s_color[2] = mp->mt_b;
04075                                 goto done;
04076                         }
04077                 }
04078 
04079                 /*
04080                  *  There is no region-id-based coloring entry in the
04081                  *  table, so use the combination-record ("mater"
04082                  *  command) based color if one was provided. Otherwise,
04083                  *  use the default wireframe color.
04084                  *  This is the "new way" of coloring things.
04085                  */
04086 
04087                 /* use wireframe_default_color */
04088                 if (sp->s_dflag)
04089                   sp->s_cflag = 1;
04090                 /* Be conservative and copy color anyway, to avoid black */
04091                 sp->s_color[0] = sp->s_basecolor[0];
04092                 sp->s_color[1] = sp->s_basecolor[1];
04093                 sp->s_color[2] = sp->s_basecolor[2];
04094 done: ;
04095         }
04096 }
04097 
04098 /*
04099  *                    D G O _ B U I L D _ T O P S
04100  *
04101  *  Build a command line vector of the tops of all objects in view.
04102  */
04103 int
04104 dgo_build_tops(Tcl_Interp       *interp,
04105                struct solid     *hsp,
04106                char             **start,
04107                register char    **end)
04108 {
04109         register char **vp = start;
04110         register struct solid *sp;
04111 
04112         /*
04113          * Find all unique top-level entries.
04114          *  Mark ones already done with s_flag == UP
04115          */
04116         FOR_ALL_SOLIDS(sp, &hsp->l)
04117                 sp->s_flag = DOWN;
04118         FOR_ALL_SOLIDS(sp, &hsp->l)  {
04119                 register struct solid *forw;
04120                 struct directory *dp = FIRST_SOLID(sp);
04121 
04122                 if (sp->s_flag == UP)
04123                         continue;
04124                 if (dp->d_addr == RT_DIR_PHONY_ADDR)
04125                         continue;       /* Ignore overlays, predictor, etc */
04126                 if (vp < end)
04127                         *vp++ = dp->d_namep;
04128                 else  {
04129                   Tcl_AppendResult(interp, "mged: ran out of comand vector space at ",
04130                                    dp->d_namep, "\n", (char *)NULL);
04131                   break;
04132                 }
04133                 sp->s_flag = UP;
04134                 for (BU_LIST_PFOR(forw, sp, solid, &hsp->l)) {
04135                         if (FIRST_SOLID(forw) == dp)
04136                                 forw->s_flag = UP;
04137                 }
04138         }
04139         *vp = (char *) 0;
04140         return vp-start;
04141 }
04142 
04143 
04144 /*
04145  *                      D G O _ R T _ W R I T E
04146  *
04147  *  Write out the information that RT's -M option needs to show current view.
04148  *  Note that the model-space location of the eye is a parameter,
04149  *  as it can be computed in different ways.
04150  */
04151 static void
04152 dgo_rt_write(struct dg_obj      *dgop,
04153              struct view_obj    *vop,
04154              FILE               *fp,
04155              vect_t             eye_model)
04156 {
04157         register int    i;
04158         quat_t          quat;
04159         register struct solid *sp;
04160 
04161         (void)fprintf(fp, "viewsize %.15e;\n", vop->vo_size);
04162         quat_mat2quat(quat, vop->vo_rotation );
04163         (void)fprintf(fp, "orientation %.15e %.15e %.15e %.15e;\n", V4ARGS(quat));
04164         (void)fprintf(fp, "eye_pt %.15e %.15e %.15e;\n",
04165                       eye_model[X], eye_model[Y], eye_model[Z] );
04166 
04167         (void)fprintf(fp, "start 0; clean;\n");
04168         FOR_ALL_SOLIDS (sp, &dgop->dgo_headSolid) {
04169                 for (i=0;i<sp->s_fullpath.fp_len;i++) {
04170                         DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_flags &= ~DIR_USED;
04171                 }
04172         }
04173         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
04174                 for (i=0; i<sp->s_fullpath.fp_len; i++ ) {
04175                         if (!(DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_flags & DIR_USED)) {
04176                                 register struct animate *anp;
04177                                 for (anp = DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_animate; anp;
04178                                     anp=anp->an_forw) {
04179                                         db_write_anim(fp, anp);
04180                                 }
04181                                 DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_flags |= DIR_USED;
04182                         }
04183                 }
04184         }
04185 
04186         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
04187                 for (i=0;i< sp->s_fullpath.fp_len;i++) {
04188                         DB_FULL_PATH_GET(&sp->s_fullpath,i)->d_flags &= ~DIR_USED;
04189                 }
04190         }
04191         (void)fprintf(fp, "end;\n");
04192 }
04193 
04194 #ifndef _WIN32
04195 static void
04196 dgo_rt_output_handler(ClientData        clientData,
04197                       int               mask)
04198 {
04199     struct dg_rt_client_data *drcdp = (struct dg_rt_client_data *)clientData;
04200     struct run_rt *run_rtp;
04201     int count;
04202     char line[RT_MAXLINE+1];
04203 
04204     if (drcdp == (struct dg_rt_client_data *)NULL ||
04205         drcdp->dgop == (struct dg_obj *)NULL ||
04206         drcdp->rrtp == (struct run_rt *)NULL ||
04207         drcdp->interp == (Tcl_Interp *)NULL)
04208         return;
04209 
04210     run_rtp = drcdp->rrtp;
04211 
04212     /* Get data from rt */
04213     count = read((int)run_rtp->fd, line, RT_MAXLINE);
04214     if (count <= 0) {
04215         int retcode;
04216         int rpid;
04217         int aborted;
04218 
04219         if (count < 0) {
04220             perror("READ ERROR");
04221         }
04222 
04223         Tcl_DeleteFileHandler(run_rtp->fd);
04224         close(run_rtp->fd);
04225 
04226         /* wait for the forked process */
04227         while ((rpid = wait(&retcode)) != run_rtp->pid && rpid != -1);
04228 
04229         aborted = run_rtp->aborted;
04230 
04231         if (drcdp->dgop->dgo_outputHandler != NULL) {
04232             struct bu_vls vls;
04233 
04234             bu_vls_init(&vls);
04235 
04236             if (aborted)
04237                 bu_vls_printf(&vls, "%s \"Raytrace aborted.\n\"",
04238                               drcdp->dgop->dgo_outputHandler);
04239             else
04240                 bu_vls_printf(&vls, "%s \"Raytrace complete.\n\"",
04241                               drcdp->dgop->dgo_outputHandler);
04242 
04243             Tcl_Eval(drcdp->interp, bu_vls_addr(&vls));
04244             bu_vls_free(&vls);
04245         } else {
04246             if (aborted)
04247                 bu_log("Raytrace aborted.\n");
04248             else
04249                 bu_log("Raytrace complete.\n");
04250         }
04251 
04252         /* free run_rtp */
04253         BU_LIST_DEQUEUE(&run_rtp->l);
04254         bu_free((genptr_t)run_rtp, "dgo_rt_output_handler: run_rtp");
04255 
04256         bu_free((genptr_t)drcdp, "dgo_rt_output_handler: drcdp");
04257 
04258         return;
04259     }
04260 
04261     line[count] = '\0';
04262 
04263     /*XXX For now just blather to stderr */
04264     if (drcdp->dgop->dgo_outputHandler != NULL) {
04265         struct bu_vls vls;
04266 
04267         bu_vls_init(&vls);
04268         bu_vls_printf(&vls, "%s \"%s\"", drcdp->dgop->dgo_outputHandler, line);
04269         Tcl_Eval(drcdp->interp, bu_vls_addr(&vls));
04270         bu_vls_free(&vls);
04271     } else
04272         bu_log("%s", line);
04273 }
04274 
04275 #else
04276 static void
04277 dgo_rt_output_handler(ClientData        clientData,
04278                       int               mask)
04279 {
04280     struct dg_rt_client_data *drcdp = (struct dg_rt_client_data *)clientData;
04281     struct run_rt *run_rtp;
04282     int count;
04283     char line[10240+1] = {0};
04284 
04285     if (drcdp == (struct dg_rt_client_data *)NULL ||
04286         drcdp->dgop == (struct dg_obj *)NULL ||
04287         drcdp->rrtp == (struct run_rt *)NULL ||
04288         drcdp->interp == (Tcl_Interp *)NULL)
04289         return;
04290 
04291     run_rtp = drcdp->rrtp;
04292 
04293     /* Get data from rt */
04294     if (Tcl_Eof(run_rtp->chan) ||
04295         (!ReadFile(run_rtp->fd, line, 10240,&count,0))) {
04296         int aborted;
04297 
04298         Tcl_DeleteChannelHandler(run_rtp->chan,
04299                                  dgo_rt_output_handler,
04300                                  (ClientData)drcdp);
04301         Tcl_Close(drcdp->interp, run_rtp->chan);
04302         CloseHandle(run_rtp->fd);
04303 
04304         /* wait for the forked process
04305          * either EOF has been sent or there was a read error.
04306          * there is no need to block indefinately
04307          */
04308         WaitForSingleObject( run_rtp->hProcess, 120 );
04309         /* !!! need to observer implications of being non-infinate
04310          *      WaitForSingleObject( run_rtp->hProcess, INFINITE );
04311          */
04312 
04313         if(GetLastError() == ERROR_PROCESS_ABORTED) {
04314             run_rtp->aborted = 1;
04315         }
04316 
04317         aborted = run_rtp->aborted;
04318 
04319         if (drcdp->dgop->dgo_outputHandler != NULL) {
04320             struct bu_vls vls;
04321 
04322             bu_vls_init(&vls);
04323 
04324             if (aborted)
04325                 bu_vls_printf(&vls, "%s \"Raytrace aborted.\n\"",
04326                               drcdp->dgop->dgo_outputHandler);
04327             else
04328                 bu_vls_printf(&vls, "%s \"Raytrace complete.\n\"",
04329                               drcdp->dgop->dgo_outputHandler);
04330 
04331             Tcl_Eval(drcdp->interp, bu_vls_addr(&vls));
04332             bu_vls_free(&vls);
04333         } else {
04334             if (aborted)
04335                 bu_log("Raytrace aborted.\n");
04336             else
04337                 bu_log("Raytrace complete.\n");
04338         }
04339 
04340         /* free run_rtp */
04341         BU_LIST_DEQUEUE(&run_rtp->l);
04342         bu_free((genptr_t)run_rtp, "dgo_rt_output_handler: run_rtp");
04343 
04344         bu_free((genptr_t)drcdp, "dgo_rt_output_handler: drcdp");
04345 
04346         return;
04347     }
04348 
04349     line[count] = '\0';
04350 
04351     /*XXX For now just blather to stderr */
04352     if (drcdp->dgop->dgo_outputHandler != NULL) {
04353         struct bu_vls vls;
04354 
04355         bu_vls_init(&vls);
04356         bu_vls_printf(&vls, "%s \"%s\"", drcdp->dgop->dgo_outputHandler, line);
04357         Tcl_Eval(drcdp->interp, bu_vls_addr(&vls));
04358         bu_vls_free(&vls);
04359     } else
04360         bu_log("%s", line);
04361 }
04362 
04363 #endif
04364 
04365 static void
04366 dgo_rt_set_eye_model(struct dg_obj *dgop,
04367                      struct view_obj *vop,
04368                      vect_t eye_model)
04369 {
04370         if (vop->vo_zclip || vop->vo_perspective > 0) {
04371                 vect_t temp;
04372 
04373                 VSET(temp, 0.0, 0.0, 1.0);
04374                 MAT4X3PNT(eye_model, vop->vo_view2model, temp);
04375         } else {
04376                 /* not doing zclipping, so back out of geometry */
04377                 register struct solid *sp;
04378                 register int i;
04379                 double  t;
04380                 double  t_in;
04381                 vect_t  direction;
04382                 vect_t  extremum[2];
04383                 vect_t  minus, plus;    /* vers of this solid's bounding box */
04384 
04385                 VSET(eye_model, -vop->vo_center[MDX],
04386                      -vop->vo_center[MDY], -vop->vo_center[MDZ]);
04387 
04388                 for (i = 0; i < 3; ++i) {
04389                         extremum[0][i] = INFINITY;
04390                         extremum[1][i] = -INFINITY;
04391                 }
04392 
04393                 FOR_ALL_SOLIDS (sp, &dgop->dgo_headSolid) {
04394                         minus[X] = sp->s_center[X] - sp->s_size;
04395                         minus[Y] = sp->s_center[Y] - sp->s_size;
04396                         minus[Z] = sp->s_center[Z] - sp->s_size;
04397                         VMIN( extremum[0], minus );
04398                         plus[X] = sp->s_center[X] + sp->s_size;
04399                         plus[Y] = sp->s_center[Y] + sp->s_size;
04400                         plus[Z] = sp->s_center[Z] + sp->s_size;
04401                         VMAX( extremum[1], plus );
04402                 }
04403                 VMOVEN(direction, vop->vo_rotation + 8, 3);
04404                 VSCALE(direction, direction, -1.0);
04405                 for (i = 0; i < 3; ++i)
04406                         if (NEAR_ZERO(direction[i], 1e-10))
04407                                 direction[i] = 0.0;
04408                 if ((eye_model[X] >= extremum[0][X]) &&
04409                     (eye_model[X] <= extremum[1][X]) &&
04410                     (eye_model[Y] >= extremum[0][Y]) &&
04411                     (eye_model[Y] <= extremum[1][Y]) &&
04412                     (eye_model[Z] >= extremum[0][Z]) &&
04413                     (eye_model[Z] <= extremum[1][Z])) {
04414                         t_in = -INFINITY;
04415                         for (i = 0; i < 6; ++i) {
04416                                 if (direction[i%3] == 0)
04417                                         continue;
04418                                 t = (extremum[i/3][i%3] - eye_model[i%3]) /
04419                                         direction[i%3];
04420                                 if ((t < 0) && (t > t_in))
04421                                         t_in = t;
04422                         }
04423                         VJOIN1(eye_model, eye_model, t_in, direction);
04424                 }
04425         }
04426 }
04427 
04428 /*
04429  *                  D G O _ R U N _ R T
04430  */
04431 static int
04432 dgo_run_rt(struct dg_obj *dgop,
04433            struct view_obj *vop)
04434 {
04435         register int    i;
04436         FILE            *fp_in;
04437 #ifndef _WIN32
04438         int             pipe_in[2];
04439         int             pipe_err[2];
04440 #else
04441         HANDLE pipe_in[2],pipe_inDup;
04442         HANDLE pipe_err[2],pipe_errDup;
04443         STARTUPINFO si = {0};
04444         PROCESS_INFORMATION pi = {0};
04445         SECURITY_ATTRIBUTES sa          = {0};
04446         char line[2048];
04447         char name[256];
04448 #endif
04449         vect_t          eye_model;
04450         struct run_rt   *run_rtp;
04451         struct dg_rt_client_data        *drcdp;
04452 #ifndef _WIN32
04453         int             pid;
04454 
04455         (void)pipe(pipe_in);
04456         (void)pipe(pipe_err);
04457 
04458         if ((pid = fork()) == 0) {
04459                 /* make this a process group leader */
04460                 setpgid(0, 0);
04461 
04462                 /* Redirect stdin and stderr */
04463                 (void)close(0);
04464                 (void)dup(pipe_in[0]);
04465                 (void)close(2);
04466                 (void)dup(pipe_err[1]);
04467 
04468                 /* close pipes */
04469                 (void)close(pipe_in[0]);
04470                 (void)close(pipe_in[1]);
04471                 (void)close(pipe_err[0]);
04472                 (void)close(pipe_err[1]);
04473 
04474                 for (i=3; i < 20; i++)
04475                         (void)close(i);
04476 
04477                 (void)execvp(dgop->dgo_rt_cmd[0], dgop->dgo_rt_cmd);
04478                 perror(dgop->dgo_rt_cmd[0]);
04479                 exit(16);
04480         }
04481 
04482         /* As parent, send view information down pipe */
04483         (void)close(pipe_in[0]);
04484         fp_in = fdopen(pipe_in[1], "w");
04485 
04486         (void)close(pipe_err[1]);
04487 
04488         dgo_rt_set_eye_model(dgop, vop, eye_model);
04489         dgo_rt_write(dgop, vop, fp_in, eye_model);
04490         (void)fclose(fp_in);
04491 
04492         BU_GETSTRUCT(run_rtp, run_rt);
04493         BU_LIST_INIT(&run_rtp->l);
04494         BU_LIST_APPEND(&dgop->dgo_headRunRt.l, &run_rtp->l);
04495 
04496         run_rtp->fd = pipe_err[0];
04497         run_rtp->pid = pid;
04498 
04499         BU_GETSTRUCT(drcdp, dg_rt_client_data);
04500         drcdp->dgop = dgop;
04501         drcdp->rrtp = run_rtp;
04502         drcdp->interp = dgop->dgo_wdbp->wdb_interp;
04503 
04504         Tcl_CreateFileHandler(run_rtp->fd,
04505                               TCL_READABLE,
04506                               dgo_rt_output_handler,
04507                               (ClientData)drcdp);
04508 
04509         return 0;
04510 
04511 #else
04512         sa.nLength = sizeof(sa);
04513         sa.bInheritHandle = TRUE;
04514         sa.lpSecurityDescriptor = NULL;
04515 
04516         /* Create a pipe for the child process's STDOUT. */
04517         CreatePipe( &pipe_err[0], &pipe_err[1], &sa, 0);
04518 
04519         /* Create noninheritable read handle and close the inheritable read handle. */
04520         DuplicateHandle( GetCurrentProcess(), pipe_err[0],
04521         GetCurrentProcess(),  &pipe_errDup ,
04522                 0,  FALSE,
04523         DUPLICATE_SAME_ACCESS );
04524         CloseHandle( pipe_err[0] );
04525 
04526         /* Create a pipe for the child process's STDIN. */
04527         CreatePipe(&pipe_in[0], &pipe_in[1], &sa, 0);
04528 
04529         /* Duplicate the write handle to the pipe so it is not inherited. */
04530         DuplicateHandle(GetCurrentProcess(), pipe_in[1],
04531                 GetCurrentProcess(), &pipe_inDup,
04532                 0, FALSE,                  /* not inherited */
04533                 DUPLICATE_SAME_ACCESS );
04534         CloseHandle(pipe_in[1]);
04535 
04536 
04537         si.cb = sizeof(STARTUPINFO);
04538         si.lpReserved = NULL;
04539         si.lpReserved2 = NULL;
04540         si.cbReserved2 = 0;
04541         si.lpDesktop = NULL;
04542         si.dwFlags = STARTF_USESTDHANDLES;
04543         si.hStdInput   = pipe_in[0];
04544         si.hStdOutput  = pipe_err[1];
04545         si.hStdError   = pipe_err[1];
04546 
04547         sprintf(line,"%s ",dgop->dgo_rt_cmd[0]);
04548         for(i=1;i<dgop->dgo_rt_cmd_len;i++) {
04549             sprintf(name,"%s ",dgop->dgo_rt_cmd[i]);
04550             strcat(line,name); }
04551 
04552 
04553         CreateProcess(NULL, line, NULL, NULL, TRUE,
04554                       DETACHED_PROCESS, NULL, NULL,
04555                       &si, &pi);
04556 
04557         CloseHandle(pipe_in[0]);
04558         CloseHandle(pipe_err[1]);
04559 
04560         /* As parent, send view information down pipe */
04561         fp_in = _fdopen( _open_osfhandle((HFILE)pipe_inDup,_O_TEXT), "wb" );
04562         _setmode(_fileno(fp_in), _O_BINARY);
04563 
04564         dgo_rt_set_eye_model(dgop, vop, eye_model);
04565         dgo_rt_write(dgop, vop, fp_in, eye_model);
04566         (void)fclose(fp_in);
04567 
04568         BU_GETSTRUCT(run_rtp, run_rt);
04569         BU_LIST_INIT(&run_rtp->l);
04570         BU_LIST_APPEND(&dgop->dgo_headRunRt.l, &run_rtp->l);
04571 
04572         run_rtp->fd = pipe_errDup;
04573         run_rtp->hProcess = pi.hProcess;
04574         run_rtp->pid = pi.dwProcessId;
04575         run_rtp->aborted=0;
04576         run_rtp->chan = Tcl_MakeFileChannel(run_rtp->fd, TCL_READABLE);
04577 
04578         BU_GETSTRUCT(drcdp, dg_rt_client_data);
04579         drcdp->dgop = dgop;
04580         drcdp->rrtp = run_rtp;
04581         drcdp->interp = dgop->dgo_wdbp->wdb_interp;
04582 
04583         Tcl_CreateChannelHandler(run_rtp->chan,
04584                                  TCL_READABLE,
04585                                  dgo_rt_output_handler,
04586                                  (ClientData)drcdp);
04587 
04588         return 0;
04589 
04590 #endif
04591 
04592 }
04593 
04594 void
04595 dgo_notify(struct dg_obj        *dgop,
04596            Tcl_Interp           *interp)
04597 {
04598         bu_observer_notify(interp, &dgop->dgo_observers, bu_vls_addr(&dgop->dgo_name));
04599 }
04600 
04601 void
04602 dgo_notifyWdb(struct rt_wdb *wdbp,
04603               Tcl_Interp    *interp)
04604 {
04605     struct dg_obj *dgop;
04606 
04607     for (BU_LIST_FOR(dgop, dg_obj, &HeadDGObj.l))
04608         if (dgop->dgo_wdbp == wdbp)
04609             dgo_notify(dgop, interp);
04610 }
04611 
04612 void
04613 dgo_impending_wdb_close(struct rt_wdb   *wdbp,
04614                         Tcl_Interp      *interp)
04615 {
04616         struct dg_obj *dgop;
04617 
04618         for (BU_LIST_FOR(dgop, dg_obj, &HeadDGObj.l))
04619                 if (dgop->dgo_wdbp == wdbp) {
04620                         dgo_zap_cmd(dgop, interp);
04621                         dgop->dgo_wdbp = RT_WDB_NULL;
04622                         dgo_notify(dgop, interp);
04623                 }
04624 }
04625 
04626 void
04627 dgo_zapall(struct rt_wdb *wdbp, Tcl_Interp *interp)
04628 {
04629         struct dg_obj *dgop;
04630 
04631         for (BU_LIST_FOR(dgop, dg_obj, &HeadDGObj.l))
04632                 if (dgop->dgo_wdbp == wdbp) {
04633                         dgo_zap_cmd(dgop, interp);
04634                         dgo_notify(dgop, interp);
04635                 }
04636 }
04637 
04638 /*
04639  *                      D G O _ P R _ S C H A I N
04640  *
04641  *  Given a pointer to a member of the circularly linked list of solids
04642  *  (typically the head), chase the list and print out the information
04643  *  about each solid structure.
04644  */
04645 static void
04646 dgo_print_schain(struct dg_obj *dgop, Tcl_Interp *interp, int lvl)
04647 
04648 
04649                                                 /* debug level */
04650 {
04651         register struct solid           *sp;
04652         register struct bn_vlist        *vp;
04653         int                             nvlist;
04654         int                             npts;
04655         struct bu_vls           vls;
04656 
04657         if (dgop->dgo_wdbp->dbip == DBI_NULL)
04658                 return;
04659 
04660         bu_vls_init(&vls);
04661 
04662         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
04663                 if (lvl <= -2) {
04664                         /* print only leaves */
04665                         bu_vls_printf(&vls, "%s ", LAST_SOLID(sp)->d_namep);
04666                         continue;
04667                 }
04668 
04669                 db_path_to_vls(&vls, &sp->s_fullpath);
04670 
04671                 if ((lvl != -1) && (sp->s_iflag == UP))
04672                         bu_vls_printf(&vls, " ILLUM");
04673 
04674                 bu_vls_printf(&vls, "\n");
04675 
04676                 if (lvl <= 0)
04677                         continue;
04678 
04679                 /* convert to the local unit for printing */
04680                 bu_vls_printf(&vls, "  cent=(%.3f,%.3f,%.3f) sz=%g ",
04681                               sp->s_center[X]*dgop->dgo_wdbp->dbip->dbi_base2local,
04682                               sp->s_center[Y]*dgop->dgo_wdbp->dbip->dbi_base2local,
04683                               sp->s_center[Z]*dgop->dgo_wdbp->dbip->dbi_base2local,
04684                               sp->s_size*dgop->dgo_wdbp->dbip->dbi_base2local);
04685                 bu_vls_printf(&vls, "reg=%d\n",sp->s_regionid);
04686                 bu_vls_printf(&vls, "  basecolor=(%d,%d,%d) color=(%d,%d,%d)%s%s%s\n",
04687                               sp->s_basecolor[0],
04688                               sp->s_basecolor[1],
04689                               sp->s_basecolor[2],
04690                               sp->s_color[0],
04691                               sp->s_color[1],
04692                               sp->s_color[2],
04693                               sp->s_uflag?" U":"",
04694                               sp->s_dflag?" D":"",
04695                               sp->s_cflag?" C":"");
04696 
04697                 if (lvl <= 1)
04698                         continue;
04699 
04700                 /* Print the actual vector list */
04701                 nvlist = 0;
04702                 npts = 0;
04703                 for (BU_LIST_FOR(vp, bn_vlist, &(sp->s_vlist))) {
04704                         register int    i;
04705                         register int    nused = vp->nused;
04706                         register int    *cmd = vp->cmd;
04707                         register point_t *pt = vp->pt;
04708 
04709                         BN_CK_VLIST(vp);
04710                         nvlist++;
04711                         npts += nused;
04712 
04713                         if (lvl <= 2)
04714                                 continue;
04715 
04716                         for (i = 0; i < nused; i++,cmd++,pt++) {
04717                                 bu_vls_printf(&vls, "  %s (%g, %g, %g)\n",
04718                                               rt_vlist_cmd_descriptions[*cmd],
04719                                               V3ARGS(*pt));
04720                         }
04721                 }
04722 
04723                 bu_vls_printf(&vls, "  %d vlist structures, %d pts\n", nvlist, npts);
04724                 bu_vls_printf(&vls, "  %d pts (via rt_ck_vlist)\n", rt_ck_vlist(&(sp->s_vlist)));
04725         }
04726 
04727         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
04728         bu_vls_free(&vls);
04729 }
04730 
04731 /*
04732  *                      D G O _ P R _ S C H A I N _ V L C M D S
04733  *
04734  *  Given a pointer to a member of the circularly linked list of solids
04735  *  (typically the head), chase the list and print out the vlist cmds
04736  *  for each structure.
04737  */
04738 static void
04739 dgo_print_schain_vlcmds(struct dg_obj *dgop, Tcl_Interp *interp)
04740 {
04741         register struct solid           *sp;
04742         register struct bn_vlist        *vp;
04743         struct bu_vls           vls;
04744 
04745         if (dgop->dgo_wdbp->dbip == DBI_NULL)
04746                 return;
04747 
04748         bu_vls_init(&vls);
04749 
04750         FOR_ALL_SOLIDS(sp, &dgop->dgo_headSolid) {
04751                 bu_vls_printf(&vls, "-1 %d %d %d\n",
04752                               sp->s_color[0],
04753                               sp->s_color[1],
04754                               sp->s_color[2]);
04755 
04756                 /* Print the actual vector list */
04757                 for (BU_LIST_FOR(vp, bn_vlist, &(sp->s_vlist))) {
04758                         register int    i;
04759                         register int    nused = vp->nused;
04760                         register int    *cmd = vp->cmd;
04761                         register point_t *pt = vp->pt;
04762 
04763                         BN_CK_VLIST(vp);
04764 
04765                         for (i = 0; i < nused; i++, cmd++, pt++)
04766                                 bu_vls_printf(&vls, "%d %g %g %g\n", *cmd, V3ARGS(*pt));
04767                 }
04768         }
04769 
04770         Tcl_AppendResult(interp, bu_vls_addr(&vls), (char *)NULL);
04771         bu_vls_free(&vls);
04772 }
04773 
04774 /*
04775  *                      P R _ W A I T _ S T A T U S
04776  *
04777  *  Interpret the status return of a wait() system call,
04778  *  for the edification of the watching luser.
04779  *  Warning:  This may be somewhat system specific, most especially
04780  *  on non-UNIX machines.
04781  */
04782 void
04783 dgo_pr_wait_status(Tcl_Interp   *interp,
04784                    int          status)
04785 {
04786         int     sig = status & 0x7f;
04787         int     core = status & 0x80;
04788         int     ret = status >> 8;
04789         struct bu_vls tmp_vls;
04790 
04791         if (status == 0) {
04792                 Tcl_AppendResult(interp, "Normal exit\n", (char *)NULL);
04793                 return;
04794         }
04795 
04796         bu_vls_init(&tmp_vls);
04797         bu_vls_printf(&tmp_vls, "Abnormal exit x%x", status);
04798 
04799         if (core)
04800                 bu_vls_printf(&tmp_vls, ", core dumped");
04801 
04802         if (sig)
04803                 bu_vls_printf(&tmp_vls, ", terminating signal = %d", sig);
04804         else
04805                 bu_vls_printf(&tmp_vls, ", return (exit) code = %d", ret);
04806 
04807         Tcl_AppendResult(interp, bu_vls_addr(&tmp_vls), "\n", (char *)NULL);
04808         bu_vls_free(&tmp_vls);
04809 }
04810 
04811 static union tree *
04812 dgo_bot_check_region_end(register struct db_tree_state  *tsp,
04813                          struct db_full_path            *pathp,
04814                          union tree                     *curtree,
04815                          genptr_t                       client_data)
04816 {
04817   return curtree;
04818 }
04819 
04820 static union tree *
04821 dgo_bot_check_leaf(struct db_tree_state         *tsp,
04822                    struct db_full_path          *pathp,
04823                    struct rt_db_internal        *ip,
04824                    genptr_t                     client_data)
04825 {
04826     union tree *curtree;
04827     int  ac = 1;
04828     char *av[2];
04829     struct dg_client_data *dgcdp = (struct dg_client_data *)client_data;
04830 
04831     av[0] = db_path_to_string(pathp);
04832     av[1] = (char *)0;
04833 
04834     /* Indicate success by returning something other than TREE_NULL */
04835     RT_GET_TREE(curtree, tsp->ts_resp);
04836     curtree->magic = RT_TREE_MAGIC;
04837     curtree->tr_op = OP_NOP;
04838 
04839     /*
04840      * Use dgop->dgo_shaded_mode if set and not being overridden. Otherwise use dgcdp->shaded_mode_override.
04841      */
04842 
04843     switch (dgcdp->dmode) {
04844     case DGO_SHADED_MODE_BOTS:
04845         if (ip->idb_major_type == DB5_MAJORTYPE_BRLCAD &&
04846             ip->idb_minor_type == DB5_MINORTYPE_BRLCAD_BOT) {
04847             struct bu_list vhead;
04848 
04849             BU_LIST_INIT(&vhead);
04850 
04851             (void)rt_bot_plot_poly(&vhead, ip, tsp->ts_ttol, tsp->ts_tol);
04852             dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
04853         } else if (ip->idb_major_type == DB5_MAJORTYPE_BRLCAD &&
04854                    ip->idb_minor_type == DB5_MINORTYPE_BRLCAD_POLY) {
04855             struct bu_list vhead;
04856 
04857             BU_LIST_INIT(&vhead);
04858 
04859             (void)rt_pg_plot_poly(&vhead, ip, tsp->ts_ttol, tsp->ts_tol);
04860             dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
04861         } else {
04862             /* save shaded mode states */
04863             int save_dgo_shaded_mode = dgcdp->dgop->dgo_shaded_mode;
04864             int save_shaded_mode_override = dgcdp->shaded_mode_override;
04865             int save_dmode = dgcdp->dmode;
04866 
04867             /* turn shaded mode off for this non-bot/non-poly object */
04868             dgcdp->dgop->dgo_shaded_mode = 0;
04869             dgcdp->shaded_mode_override = -1;
04870             dgcdp->dmode = DGO_WIREFRAME;
04871 
04872             dgo_drawtrees(dgcdp->dgop, dgcdp->interp, ac, av, 1, client_data);
04873 
04874             /* restore shaded mode states */
04875             dgcdp->dgop->dgo_shaded_mode = save_dgo_shaded_mode;
04876             dgcdp->shaded_mode_override = save_shaded_mode_override;
04877             dgcdp->dmode = save_dmode;
04878         }
04879 
04880         break;
04881     case DGO_SHADED_MODE_ALL:
04882         if (ip->idb_major_type == DB5_MAJORTYPE_BRLCAD &&
04883             ip->idb_minor_type != DB5_MINORTYPE_BRLCAD_PIPE) {
04884             if (ip->idb_minor_type == DB5_MINORTYPE_BRLCAD_BOT) {
04885                 struct bu_list vhead;
04886 
04887                 BU_LIST_INIT(&vhead);
04888 
04889                 (void)rt_bot_plot_poly(&vhead, ip, tsp->ts_ttol, tsp->ts_tol);
04890                 dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
04891             } else if (ip->idb_minor_type == DB5_MINORTYPE_BRLCAD_POLY) {
04892                 struct bu_list vhead;
04893 
04894                 BU_LIST_INIT(&vhead);
04895 
04896                 (void)rt_pg_plot_poly(&vhead, ip, tsp->ts_ttol, tsp->ts_tol);
04897                 dgo_drawH_part2(0, &vhead, pathp, tsp, SOLID_NULL, dgcdp);
04898             } else
04899                 dgo_drawtrees(dgcdp->dgop, dgcdp->interp, ac, av, 3, client_data);
04900         } else {
04901             /* save shaded mode states */
04902             int save_dgo_shaded_mode = dgcdp->dgop->dgo_shaded_mode;
04903             int save_shaded_mode_override = dgcdp->shaded_mode_override;
04904             int save_dmode = dgcdp->dmode;
04905 
04906             /* turn shaded mode off for this pipe object */
04907             dgcdp->dgop->dgo_shaded_mode = 0;
04908             dgcdp->shaded_mode_override = -1;
04909             dgcdp->dmode = DGO_WIREFRAME;
04910 
04911             dgo_drawtrees(dgcdp->dgop, dgcdp->interp, ac, av, 1, client_data);
04912 
04913             /* restore shaded mode states */
04914             dgcdp->dgop->dgo_shaded_mode = save_dgo_shaded_mode;
04915             dgcdp->shaded_mode_override = save_shaded_mode_override;
04916             dgcdp->dmode = save_dmode;
04917         }
04918 
04919         break;
04920     }
04921 
04922     bu_free((genptr_t)av[0], "dgo_bot_check_leaf: av[0]");
04923 
04924     return curtree;
04925 }
04926 
04927 /*@}*/
04928 /*
04929  * Local Variables:
04930  * mode: C
04931  * tab-width: 8
04932  * c-basic-offset: 4
04933  * indent-tabs-mode: t
04934  * End:
04935  * ex: shiftwidth=4 tabstop=8
04936  */

Generated on Mon Sep 18 01:24:49 2006 for BRL-CAD by  doxygen 1.4.6