Revision: 76107
          http://sourceforge.net/p/brlcad/code/76107
Author:   starseeker
Date:     2020-06-11 14:30:34 +0000 (Thu, 11 Jun 2020)
Log Message:
-----------
checkpoint

Modified Paths:
--------------
    brlcad/branches/bioh/src/burst2/CMakeLists.txt
    brlcad/branches/bioh/src/burst2/burst.cpp
    brlcad/branches/bioh/src/burst2/burst.h
    brlcad/branches/bioh/src/burst2/grid.cpp

Added Paths:
-----------
    brlcad/branches/bioh/src/burst2/paint.cpp

Modified: brlcad/branches/bioh/src/burst2/CMakeLists.txt
===================================================================
--- brlcad/branches/bioh/src/burst2/CMakeLists.txt      2020-06-11 00:33:24 UTC 
(rev 76106)
+++ brlcad/branches/bioh/src/burst2/CMakeLists.txt      2020-06-11 14:30:34 UTC 
(rev 76107)
@@ -13,8 +13,9 @@
 set(burst_SOURCES
   burst.cpp
   execute.cpp
-  #grid.cpp
+  grid.cpp
   idents.cpp
+  paint.cpp
   ${LDIR}/utf8.c
   ${LDIR}/linenoise.c
   )

Modified: brlcad/branches/bioh/src/burst2/burst.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/burst.cpp   2020-06-11 00:33:24 UTC (rev 
76106)
+++ brlcad/branches/bioh/src/burst2/burst.cpp   2020-06-11 14:30:34 UTC (rev 
76107)
@@ -113,25 +113,25 @@
     s->reqburstair = 1;
     s->shotburst = 0;
     s->userinterrupt = 0;
-    memset(s->airfile, 0, LNBUFSZ);
-    memset(s->armorfile, 0, LNBUFSZ);
-    memset(s->burstfile, 0, LNBUFSZ);
-    memset(s->cmdbuf, 0, LNBUFSZ);
-    memset(s->cmdname, 0, LNBUFSZ);
-    memset(s->colorfile, 0, LNBUFSZ);
-    memset(s->critfile, 0, LNBUFSZ);
+    bu_vls_init(&s->airfile);
+    bu_vls_init(&s->armorfile);
+    bu_vls_init(&s->burstfile);
+    bu_vls_init(&s->cmdbuf);
+    bu_vls_init(&s->cmdname);
+    bu_vls_init(&s->colorfile);
+    bu_vls_init(&s->critfile);
     s->errfile = NULL;
     bu_vls_init(&s->fbfile);
     bu_vls_init(&s->gedfile);
-    memset(s->gridfile, 0, LNBUFSZ);
-    memset(s->histfile, 0, LNBUFSZ);
+    bu_vls_init(&s->gridfile);
+    bu_vls_init(&s->histfile);
     bu_vls_init(&s->objects);
-    memset(s->outfile, 0, LNBUFSZ);
+    bu_vls_init(&s->outfile);
     bu_vls_init(&s->plotfile);
     memset(s->scrbuf, 0, LNBUFSZ);
     memset(s->scriptfile, 0, LNBUFSZ);
-    memset(s->shotfile, 0, LNBUFSZ);
-    memset(s->shotlnfile, 0, LNBUFSZ);
+    bu_vls_init(&s->shotfile);
+    bu_vls_init(&s->shotlnfile);
     memset(s->title, 0, TITLE_LEN);
     memset(s->timer, 0, TIMER_LEN);
     bu_vls_init(&s->cmdhist);
@@ -257,6 +257,8 @@
 
     printf("Reading critical component idents... done.\n");
 
+    bu_vls_sprintf(&s->critfile, "%s", argv[1]);
+
     return ret;
 }
 
@@ -481,6 +483,7 @@
 
     /* If we're given a NULL argument, disable the grid file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
+       bu_vls_trunc(&s->gridfile, 0);
        return ret;
     }
 
@@ -491,6 +494,8 @@
        ret = BRLCAD_ERROR;
     }
 
+    bu_vls_sprintf(&s->gridfile, "%s", argv[1]);
+
     return ret;
 }
 
@@ -634,6 +639,8 @@
 
     printf("Reading burst air idents... done.\n");
 
+    bu_vls_sprintf(&s->airfile, "%s", argv[1]);
+
     return ret;
 }
 
@@ -665,6 +672,7 @@
 
     /* If we're given a NULL argument, disable the grid file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
+       bu_vls_trunc(&s->histfile, 0);
        return ret;
     }
 
@@ -675,6 +683,8 @@
        ret = BRLCAD_ERROR;
     }
 
+    bu_vls_sprintf(&s->histfile, "%s", argv[1]);
+
     return BRLCAD_OK;
 }
 
@@ -910,6 +920,7 @@
     /* If we're given a NULL argument, disable the error file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
        s->firemode = 0;
+       bu_vls_trunc(&s->shotfile, 0);
        return ret;
     }
 
@@ -919,6 +930,8 @@
        ret = BRLCAD_ERROR;
     }
 
+    bu_vls_sprintf(&s->shotfile, "%s", argv[1]);
+
     s->firemode = FM_SHOT | FM_FILE;
 
     return ret;
@@ -952,6 +965,7 @@
     /* If we're given a NULL argument, disable the error file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
        s->firemode = 0;
+       bu_vls_trunc(&s->shotfile, 0);
        return ret;
     }
 
@@ -960,6 +974,7 @@
        printf("failed to open critical component file: %s\n", argv[1]);
        ret = BRLCAD_ERROR;
     }
+    bu_vls_sprintf(&s->shotfile, "%s", argv[1]);
 
     s->firemode = FM_SHOT | FM_FILE | FM_3DIM;
 
@@ -994,6 +1009,8 @@
 
     printf("Reading burst armor idents... done.\n");
 
+    bu_vls_sprintf(&s->armorfile, "%s", argv[1]);
+    
     return ret;
 }
 
@@ -1025,6 +1042,7 @@
     /* If we're given a NULL argument, disable the error file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
        s->firemode = 0;
+       bu_vls_trunc(&s->burstfile, 0);
        return ret;
     }
 
@@ -1034,6 +1052,7 @@
        ret = BRLCAD_ERROR;
     }
 
+    bu_vls_sprintf(&s->burstfile, "%s", argv[1]);
     s->firemode = FM_BURST | FM_3DIM | FM_FILE;
 
     return BRLCAD_OK;
@@ -1168,6 +1187,7 @@
 
     /* If we're given a NULL argument, disable the shotline file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
+       bu_vls_trunc(&s->shotlnfile, 0);
        return ret;
     }
 
@@ -1179,6 +1199,8 @@
        ret = BRLCAD_ERROR;
     }
 
+    bu_vls_sprintf(&s->shotlnfile, "%s", argv[1]);
+
     return ret;
 }
 
@@ -1385,6 +1407,7 @@
 
     /* If we're given a NULL argument, disable the burst file */
     if (BU_STR_EQUAL(argv[1], "NULL") || BU_STR_EQUAL(argv[1], "/dev/NULL")) {
+       bu_vls_trunc(&s->outfile, 0);
        return ret;
     }
 
@@ -1395,6 +1418,7 @@
        printf("failed to open burst file: %s\n", argv[1]);
        ret = BRLCAD_ERROR;
     }
+    bu_vls_sprintf(&s->outfile, "%s", argv[1]);
 
     return ret;
 }
@@ -1451,6 +1475,8 @@
     }
 
     printf("Reading ident-to-color mappings... done.\n");
+    
+    bu_vls_sprintf(&s->colorfile, "%s", argv[1]);
 
     return ret;
 }

Modified: brlcad/branches/bioh/src/burst2/burst.h
===================================================================
--- brlcad/branches/bioh/src/burst2/burst.h     2020-06-11 00:33:24 UTC (rev 
76106)
+++ brlcad/branches/bioh/src/burst2/burst.h     2020-06-11 14:30:34 UTC (rev 
76107)
@@ -108,25 +108,25 @@
     int shotburst;            /* if true, burst along shotline */
     int userinterrupt;         /* has the ray trace been interrupted */
 
-    char airfile[LNBUFSZ];     /* input file name for burst air ids */
-    char armorfile[LNBUFSZ];   /* input file name for burst armor ids */
-    char burstfile[LNBUFSZ];   /* input file name for burst points */
-    char cmdbuf[LNBUFSZ];      /* */
-    char cmdname[LNBUFSZ];     /* */
-    char colorfile[LNBUFSZ];   /* ident range-to-color file name */
-    char critfile[LNBUFSZ];    /* input file for critical components */
+    struct bu_vls airfile;     /* input file name for burst air ids */
+    struct bu_vls armorfile;   /* input file name for burst armor ids */
+    struct bu_vls burstfile;   /* input file name for burst points */
+    struct bu_vls cmdbuf;      /* */
+    struct bu_vls cmdname;     /* */
+    struct bu_vls colorfile;   /* ident range-to-color file name */
+    struct bu_vls critfile;    /* input file for critical components */
     FILE *errfile;             /* errors/diagnostics log file */
     struct bu_vls fbfile;      /* frame buffer image file name */
     struct bu_vls gedfile;     /* MGED data base file name */
-    char gridfile[LNBUFSZ];    /* saved grid (2-d shots) file name */
-    char histfile[LNBUFSZ];    /* histogram file name (statistics) */
+    struct bu_vls gridfile;    /* saved grid (2-d shots) file name */
+    struct bu_vls histfile;    /* histogram file name (statistics) */
     struct bu_vls objects;     /* list of objects from MGED file */
-    char outfile[LNBUFSZ];     /* burst point library output file name */
+    struct bu_vls outfile;     /* burst point library output file name */
     struct bu_vls plotfile;    /* 3-D UNIX plot file name (debugging) */
     char scrbuf[LNBUFSZ];      /* scratch buffer for temporary use */
     char scriptfile[LNBUFSZ];  /* shell script file name */
-    char shotfile[LNBUFSZ];    /* input file of firing coordinates */
-    char shotlnfile[LNBUFSZ];  /* shotline output file name */
+    struct bu_vls shotfile;    /* input file of firing coordinates */
+    struct bu_vls shotlnfile;  /* shotline output file name */
     char title[TITLE_LEN];     /* title of MGED target description */
     char timer[TIMER_LEN];     /* CPU usage statistics */
     char tmpfname[TIMER_LEN];  /* temporary file for logging input */
@@ -214,6 +214,9 @@
 void gridInit(struct burst_state *s);
 void spallInit(struct burst_state *s);
 
+void paintCellFb(struct application *ap, unsigned char *pixpaint, unsigned 
char *pixexpendable);
+void paintSpallFb(struct application *ap);
+
 #endif  /* BURST_BURST_H */
 
 /*

Modified: brlcad/branches/bioh/src/burst2/grid.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/grid.cpp    2020-06-11 00:33:24 UTC (rev 
76106)
+++ brlcad/branches/bioh/src/burst2/grid.cpp    2020-06-11 14:30:34 UTC (rev 
76107)
@@ -46,6 +46,8 @@
 #define C_MAIN         0
 #define C_CRIT                 1
 
+#define COS_TOL                0.01
+
 /* colors for UNIX plot files */
 #define R_GRID          255     /* grid - yellow */
 #define G_GRID          255
@@ -84,7 +86,16 @@
 #define OutsideAir(rp)  ((rp)->reg_aircode == OUTSIDE_AIR)
 #define InsideAir(rp)   (Air(rp)&& !OutsideAir(rp))
 
+#define PB_ASPECT_INIT          '1'
+#define PB_CELL_IDENT           '2'
+#define PB_RAY_INTERSECT        '3'
+#define PB_RAY_HEADER           '4'
+#define PB_REGION_HEADER        '5'
 
+#define PS_ASPECT_INIT          '1'
+#define PS_CELL_IDENT           '2'
+#define PS_SHOT_INTERSECT       '3'
+
 #define DEBUG_GRID     0
 #define DEBUG_SHOT     1
 
@@ -96,6 +107,35 @@
 };
 #define PT_Q_NULL (Pt_Queue *) 0
 
+int
+qAdd(struct partition *pp, Pt_Queue **qpp)
+{
+    Pt_Queue *newq;
+    bu_semaphore_acquire(BU_SEM_SYSCALL);
+    if ((newq = (Pt_Queue *) malloc(sizeof(Pt_Queue))) == PT_Q_NULL) {
+        bu_semaphore_release(BU_SEM_SYSCALL);
+        return 0;
+    }
+    bu_semaphore_release(BU_SEM_SYSCALL);
+    newq->q_next = *qpp;
+    newq->q_part = pp;
+    *qpp = newq;
+    return 1;
+}
+
+
+void
+qFree(Pt_Queue *qp)
+{
+    if (qp == PT_Q_NULL)
+        return;
+    qFree(qp->q_next);
+    bu_semaphore_acquire(BU_SEM_SYSCALL);
+    free((char *) qp);
+    bu_semaphore_release(BU_SEM_SYSCALL);
+}
+
+
 /* local communication with multitasking process */
 static int currshot;   /* current shot index */
 static int lastshot;   /* final shot index */
@@ -163,19 +203,7 @@
     return;
 }
 
-static void
-view_pix(struct burst_state *s, struct application *ap)
-{
-    bu_semaphore_acquire(BU_SEM_SYSCALL);
-    if (!TSTBIT(s->firemode, FM_BURST)) {
-       prntGridOffsets(ap->a_x, ap->a_y);
-    }
-    bu_semaphore_release(BU_SEM_SYSCALL);
-    return;
-}
 
-
-
 /*
   void enforceLOS(struct application *ap,
   struct partition *pt_headp)
@@ -201,6 +229,326 @@
 
 
 /*
+  Burst Point Library: information about burst ray.  All angles are
+  WRT the shotline coordinate system, represented by X', Y' and Z'.
+  Ref. Figure 20., Line Number 19 of ICD.
+
+  NOTE: field width of first 2 floats compatible with PB_CELL_IDENT
+  record.
+*/
+void
+prntRayHeader(struct burst_state *s,
+               fastf_t *raydir /* burst ray direction vector */,
+               fastf_t *shotdir /* shotline direction vector */,
+       unsigned rayno /* ray number for this burst point */)
+{
+    double cosxr;        /* cosine of angle between X' and raydir */
+    double cosyr;        /* cosine of angle between Y' and raydir */
+    fastf_t azim;        /* ray azim in radians */
+    fastf_t sinelev; /* sine of ray elevation */
+    if (!bu_vls_strlen(&s->outfile))
+        return;
+    cosxr = -VDOT(shotdir, raydir); /* shotdir is reverse of X' */
+    cosyr = VDOT(s->gridhor, raydir);
+    if (NEAR_ZERO(cosyr, VDIVIDE_TOL) && NEAR_ZERO(cosxr, VDIVIDE_TOL))
+        azim = 0.0;
+    else
+        azim = atan2(cosyr, cosxr);
+    sinelev = VDOT(s->gridver, raydir);
+    if (fprintf(s->outfp,
+                "%c %8.3f %8.3f %6u\n",
+                PB_RAY_HEADER,
+                azim,   /* ray azimuth angle WRT shotline (radians). */
+                sinelev, /* sine of ray elevation angle WRT shotline. */
+                rayno
+            ) < 0
+        ) {
+        bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->outfile));
+    }
+}
+
+
+/*
+  void getRtHitNorm(struct hit *hitp, struct soltab *stp,
+  struct xray *rayp, int flipped, fastf_t normvec[3])
+
+  Fill normal and hit point into hit struct and if the flipped
+  flag is set, reverse the normal.  Return a private copy of the
+  flipped normal in normvec.  NOTE: the normal placed in the hit
+  struct should not be modified (i.e. reversed) by the application
+  because it can be instanced by other solids.
+*/
+void
+getRtHitNorm(struct hit *hitp, struct soltab *stp, struct xray *UNUSED(rayp), 
int flipped, fastf_t normvec[3])
+{
+    RT_HIT_NORMAL(normvec, hitp, stp, rayp, flipped);
+}
+
+int
+chkEntryNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], 
const char *purpose)
+{
+    fastf_t f;
+    static int flipct = 0;
+    static int totalct = 0;
+    struct soltab *stp = pp->pt_inseg->seg_stp;
+    int ret = 1;
+    totalct++;
+    /* Dot product of ray direction with normal *should* be negative. */
+    f = VDOT(rayp->r_dir, normvec);
+    if (ZERO(f)) {
+       ret = 0;
+    }
+    if (f > 0.0) {
+       flipct++;
+       bu_log("Fixed flipped entry normal:\n");
+       bu_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
+                pp->pt_regionp->reg_name, stp->st_name,
+                stp->st_id, purpose);
+       VSCALE(normvec, normvec, -1.0);
+       ret = 0;
+    }
+    return ret;
+}
+
+int
+chkExitNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], const 
char *purpose)
+{
+    fastf_t f;
+    static int flipct = 0;
+    static int totalct = 0;
+    struct soltab *stp = pp->pt_outseg->seg_stp;
+    int ret = 1;
+    totalct++;
+    /* Dot product of ray direction with normal *should* be positive. */
+    f = VDOT(rayp->r_dir, normvec);
+    if (ZERO(f)) {
+#ifdef DEBUG
+       bu_log("chkExitNorm: near 90 degree obliquity.\n");
+       bu_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+                normvec[X], normvec[Y], normvec[Z]);
+#endif
+       ret = 0;
+    }
+    if (f < 0.0) {
+       flipct++;
+       bu_log("Fixed flipped exit normal:\n");
+       bu_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
+                pp->pt_regionp->reg_name, stp->st_name,
+                stp->st_id, purpose);
+#ifdef DEBUG
+       bu_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
+                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
+                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
+                normvec[X], normvec[Y], normvec[Z]);
+       bu_log("\tDist %g Hit Pnt %g, %g, %g\n",
+                pp->pt_outhit->hit_dist,
+                pp->pt_outhit->hit_point[X],
+                pp->pt_outhit->hit_point[Y],
+                pp->pt_outhit->hit_point[Z]);
+       bu_log("\t%d of %d normals flipped.\n", flipct, totalct);
+#endif
+       VSCALE(normvec, normvec, -1.0);
+       ret = 0;
+    }
+    return ret;
+}
+
+static int
+f_Nerror(struct application *ap)
+{
+    bu_log("Couldn't compute thickness or exit point along normal 
direction.\n");
+    bu_log("\tpnt\t<%12.6f, %12.6f, %12.6f>\n", V3ARGS(ap->a_ray.r_pt));
+    bu_log("\tdir\t<%12.6f, %12.6f, %12.6f>\n", V3ARGS(ap->a_ray.r_dir));
+    ap->a_rbeam = 0.0;
+    return 0;
+}
+
+/*
+ * Shooting from surface of object along reversed entry normal to
+ * compute exit point along normal direction and normal thickness.
+ * Thickness returned in "a_rbeam".
+ */
+static int
+f_Normal(struct application *ap, struct partition *pt_headp, struct seg 
*UNUSED(segp))
+{
+    struct partition *pp = pt_headp->pt_forw;
+    struct partition *cp;
+    struct hit *ohitp;
+
+    for (cp = pp->pt_forw;
+         cp != pt_headp && SameCmp(pp->pt_regionp, cp->pt_regionp);
+         cp = cp->pt_forw
+        )
+        ;
+    ohitp = cp->pt_back->pt_outhit;
+    ap->a_rbeam = ohitp->hit_dist - pp->pt_inhit->hit_dist;
+    return 1;
+}
+
+/*
+  Given a partition structure with entry hit point and a private copy
+  of the associated normal vector, the current application structure
+  and the cosine of the obliquity at entry to the component, return
+  the normal thickness through the component at the given hit point.
+
+*/
+static fastf_t
+getNormThickness(struct application *ap, struct partition *pp, fastf_t 
cosobliquity, fastf_t normvec[3])
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    if (NEAR_EQUAL(cosobliquity, 1.0, COS_TOL)) {
+        /* Trajectory was normal to surface, so no need
+           to shoot another ray. */
+        fastf_t thickness = pp->pt_outhit->hit_dist -
+            pp->pt_inhit->hit_dist;
+        return thickness;
+    } else {
+        /* need to shoot ray */
+        struct application a_thick;
+        struct hit *ihitp = pp->pt_inhit;
+        struct region *regp = pp->pt_regionp;
+        a_thick = *ap;
+        a_thick.a_hit = f_Normal;
+        a_thick.a_miss = f_Nerror;
+        a_thick.a_level++;
+        a_thick.a_user = regp->reg_regionid;
+        a_thick.a_purpose = "normal thickness";
+        VMOVE(a_thick.a_ray.r_pt, ihitp->hit_point);
+        VSCALE(a_thick.a_ray.r_dir, normvec, -1.0);
+        if (rt_shootray(&a_thick) == -1 && s->fatalerror) {
+            /* Fatal error in application routine. */
+            bu_log("Fatal error: raytracing aborted.\n");
+            return 0.0;
+        }
+        return a_thick.a_rbeam;
+    }
+    /*NOTREACHED*/
+}
+
+/*
+ * Burst Point Library: intersection along burst ray.
+  Ref. Figure 20., Line Number 20 of ICD.
+*/
+void
+prntRegionHdr(struct application *ap, struct partition *pt_headp, struct 
partition *pp, fastf_t entrynorm[3], fastf_t exitnorm[3])
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    fastf_t cosobliquity;
+    fastf_t normthickness;
+    struct hit *ihitp = pp->pt_inhit;
+    struct hit *ohitp = pp->pt_outhit;
+    struct region *regp = pp->pt_regionp;
+    struct xray *rayp = &ap->a_ray;
+    /* Get entry/exit normals and fill in hit points */
+    getRtHitNorm(ihitp, pp->pt_inseg->seg_stp, rayp,
+                 (int) pp->pt_inflip, entrynorm);
+    if (! chkEntryNorm(pp, rayp, entrynorm,
+                       "spall ray component entry normal")) {
+    }
+    getRtHitNorm(ohitp, pp->pt_outseg->seg_stp, rayp,
+                 (int) pp->pt_outflip, exitnorm);
+    if (! chkExitNorm(pp, rayp, exitnorm,
+                      "spall ray component exit normal")) {
+    }
+
+
+    /* calculate cosine of obliquity angle */
+    cosobliquity = VDOT(ap->a_ray.r_dir, entrynorm);
+    cosobliquity = -cosobliquity;
+
+    if (!bu_vls_strlen(&s->outfile))
+        return;
+
+
+    /* Now we must find normal thickness through component. */
+    normthickness = getNormThickness(ap, pp, cosobliquity, entrynorm);
+    bu_semaphore_acquire(BU_SEM_SYSCALL);               /* lock */
+    if (fprintf(s->outfp,
+                "%c % 10.3f % 9.3f % 9.3f %4d %5d % 6.3f\n",
+                PB_REGION_HEADER,
+                ihitp->hit_dist*s->unitconv, /* distance from burst pt. */
+                (ohitp->hit_dist - ihitp->hit_dist)*s->unitconv, /* LOS */
+                normthickness*s->unitconv,   /* normal thickness */
+                pp->pt_forw == pt_headp ?
+                EXIT_AIR : pp->pt_forw->pt_regionp->reg_aircode,
+                regp->reg_regionid,
+                cosobliquity
+            ) < 0
+        ) {
+        bu_semaphore_release(BU_SEM_SYSCALL);   /* unlock */
+        bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->outfile));
+    }
+    bu_semaphore_release(BU_SEM_SYSCALL);       /* unlock */
+}
+
+
+void
+prntShieldComp(struct application *ap, struct partition *pt_headp, Pt_Queue 
*qp)
+{
+    fastf_t entrynorm[3], exitnorm[3];
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    if (!bu_vls_strlen(&s->outfile))
+        return;
+    if (qp == PT_Q_NULL)
+        return;
+    prntShieldComp(ap, pt_headp, qp->q_next);
+    prntRegionHdr(ap, pt_headp, qp->q_part, entrynorm, exitnorm);
+}
+
+void
+plotPartition(struct burst_state *s, struct hit *ihitp, struct hit *ohitp)
+{
+    if (s->plotfp == NULL)
+        return;
+    bu_semaphore_acquire(BU_SEM_SYSCALL);
+    pl_3line(s->plotfp,
+             (int) ihitp->hit_point[X],
+             (int) ihitp->hit_point[Y],
+             (int) ihitp->hit_point[Z],
+             (int) ohitp->hit_point[X],
+             (int) ohitp->hit_point[Y],
+             (int) ohitp->hit_point[Z]
+        );
+    bu_semaphore_release(BU_SEM_SYSCALL);
+    return;
+}
+
+/*
+  void lgtModel(struct application *ap, struct partition *pp,
+  struct hit *hitp, struct xray *rayp,
+  fastf_t surfnorm[3])
+
+  This routine is a simple lighting model which places RGB coefficients
+  (0 to 1) in ap->a_color based on the cosine of the angle between
+  the surface normal and viewing direction and the color associated with
+  the component.  Also, the distance to the surface is placed in
+  ap->a_cumlen so that the impact location can be projected into grid
+  space.
+*/
+static void
+lgtModel(struct application *ap, struct partition *pp, struct hit *hitp, 
struct xray *UNUSED(rayp), fastf_t surfnorm[3])
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    struct colors *colorp;
+    fastf_t intensity = -VDOT(viewdir, surfnorm);
+    if (intensity < 0.0)
+       intensity = -intensity;
+
+    colorp = findColors(pp->pt_regionp->reg_regionid, &s->colorids);
+    if (colorp != NULL) {
+       ap->a_color[RED] = (fastf_t)colorp->c_rgb[RED]/255.0;
+       ap->a_color[GRN] = (fastf_t)colorp->c_rgb[GRN]/255.0;
+       ap->a_color[BLU] = (fastf_t)colorp->c_rgb[BLU]/255.0;
+    } else {
+       ap->a_color[RED] = ap->a_color[GRN] = ap->a_color[BLU] = 1.0;
+    }
+    VSCALE(ap->a_color, ap->a_color, intensity);
+    ap->a_cumlen = hitp->hit_dist;
+}
+
+/*
   int f_BurstHit(struct application *ap, struct partition *pt_headp)
 
   This routine handles all output associated with burst ray intersections.
@@ -239,8 +587,7 @@
        if (findIdents(regp->reg_regionid, &s->critids)) {
            fastf_t entrynorm[3], exitnorm[3];
            if (ncrit == 0)
-               prntRayHeader(ap->a_ray.r_dir, viewdir,
-                             ap->a_user);
+               prntRayHeader(s, ap->a_ray.r_dir, viewdir, ap->a_user);
            /* Output queued non-critical components. */
            prntShieldComp(ap, pt_headp, qshield);
            qFree(qshield);
@@ -249,20 +596,20 @@
            /* Output critical component intersection;
               prntRegionHdr fills in hit entry/exit normals. */
            prntRegionHdr(ap, pt_headp, cpp, entrynorm, exitnorm);
-           colorPartition(regp, C_CRIT);
-           plotPartition(cpp->pt_inhit, cpp->pt_outhit);
+           colorPartition(s, regp, C_CRIT);
+           plotPartition(s, cpp->pt_inhit, cpp->pt_outhit);
 
-           if (fbfile[0] != NUL && ncrit == 0)
+           if (bu_vls_strlen(&s->fbfile) && ncrit == 0) {
                /* first hit on critical component */
-               lgtModel(ap, cpp, cpp->pt_inhit, rayp,
-                        entrynorm);
+               lgtModel(ap, cpp, cpp->pt_inhit, rayp, entrynorm);
+           }
            ncrit++;
        } else
            /* Queue up shielding components until we hit a critical one. */
            if (cpp->pt_forw != pt_headp) {
                if (! qAdd(cpp, &qshield)) {
-                   fatalerror = 1;
-                   return      -1;
+                   s->fatalerror = 1;
+                   return -1;
                }
                nbar++;
            }
@@ -292,15 +639,15 @@
 static int
 f_HushOverlap(struct application *ap, struct partition *pp, struct region 
*reg1, struct region *reg2, struct partition *pheadp)
 {
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
     fastf_t depth;
     depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
     if (depth >= OVERLAP_TOL)
-       noverlaps++;
+       s->noverlaps++;
 
     return rt_defoverlap(ap, pp, reg1, reg2, pheadp);
 }
 
-
 /*
   int f_Overlap(struct application *ap, struct partition *pp,
   struct region *reg1, struct region *reg2,
@@ -318,22 +665,23 @@
 static int
 f_Overlap(struct application *ap, struct partition *pp, struct region *reg1, 
struct region *reg2, struct partition *pheadp)
 {
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
     fastf_t depth;
     point_t pt;
     depth = pp->pt_outhit->hit_dist - pp->pt_inhit->hit_dist;
     if (depth >= OVERLAP_TOL) {
-       noverlaps++;
+       s->noverlaps++;
 
        VJOIN1(pt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist,
               ap->a_ray.r_dir);
-       brst_log("OVERLAP:\n");
-       brst_log("reg=%s isol=%s, \n",
+       bu_log("OVERLAP:\n");
+       bu_log("reg=%s isol=%s, \n",
                 reg1->reg_name, pp->pt_inseg->seg_stp->st_name
            );
-       brst_log("reg=%s osol=%s, \n",
+       bu_log("reg=%s osol=%s, \n",
                 reg2->reg_name, pp->pt_outseg->seg_stp->st_name
            );
-       brst_log("depth %.2fmm at (%g, %g, %g) x%d y%d lvl%d purpose=%s\n",
+       bu_log("depth %.2fmm at (%g, %g, %g) x%d y%d lvl%d purpose=%s\n",
                 depth,
                 pt[X], pt[Y], pt[Z],
                 ap->a_x, ap->a_y, ap->a_level, ap->a_purpose
@@ -343,8 +691,394 @@
     return rt_defoverlap(ap, pp, reg1, reg2, pheadp);
 }
 
+/*
+  Burst Point Library and Shotline file: information about shotline.
+  Ref. Figure 20., Line Number 2 and Figure 19., Line Number 2 of ICD.
 
+  NOTE: field width of first 2 floats compatible with PB_RAY_HEADER
+  record.
+*/
+void
+prntCellIdent(struct application *ap)
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    if (bu_vls_strlen(&s->outfile)) {
+       int ret = fprintf(s->outfp,
+               "%c % 8.3f % 8.3f\n",
+               PB_CELL_IDENT,
+               ap->a_uvec[X]*s->unitconv,
+               /* horizontal coordinate of shotline (Y') */
+               ap->a_uvec[Y]*s->unitconv
+               /* vertical coordinate of shotline (Z') */
+               );
+
+       if (ret < 0) {
+           bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->outfile));
+       }
+    }
+    if (bu_vls_strlen(&s->shotlnfile)) {
+       int ret = fprintf(s->shotlnfp,
+               "%c % 8.3f % 8.3f\n",
+               PS_CELL_IDENT,
+               ap->a_uvec[X]*s->unitconv,
+               /* horizontal coordinate of shotline (Y') */
+               ap->a_uvec[Y]*s->unitconv
+               /* vertical coordinate of shotline (Z') */
+               );
+       if (ret < 0) {
+           bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->shotlnfile));
+       }
+    }
+    return;
+}
+
+#define PHANTOM_ARMOR 111
 /*
+  Output "phantom armor" pseudo component.  This component has no
+  surface normal or thickness, so many zero fields are used for
+  conformity with the normal component output formats.
+*/
+void
+prntPhantom(
+       struct burst_state *s,
+       struct hit *hitp /* ptr. to phantom's intersection information */,
+               int space        /* space code behind phantom */)
+{
+    if (bu_vls_strlen(&s->outfile)) {
+       int ret = fprintf(s->outfp,
+               "%c % 8.2f % 8.2f %5d %2d % 7.3f % 7.3f % 7.3f %c\n",
+               PB_RAY_INTERSECT,
+               (s->standoff - hitp->hit_dist)*s->unitconv,
+               /* X'-coordinate of intersection */
+               0.0,    /* LOS thickness of component */
+               PHANTOM_ARMOR, /* component code number */
+               space,  /* space code */
+               0.0,    /* sine of fallback angle */
+               0.0,    /* rotation angle (degrees) */
+               0.0, /* cosine of obliquity angle at entry */
+               '0'     /* no burst from phantom armor */
+               );
+        if (ret < 0) {
+           bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->outfile));
+       }
+    }
+    if (bu_vls_strlen(&s->shotlnfile)) {
+       int ret = fprintf(s->shotlnfp,
+                        "%c % 8.2f % 7.3f % 7.3f %5d % 8.2f % 8.2f %2d % 7.2f 
% 7.2f\n",
+                        PS_SHOT_INTERSECT,
+                        (s->standoff - hitp->hit_dist)*s->unitconv,
+                        /* X'-coordinate of intersection */
+                        0.0,            /* sine of fallback angle */
+                        0.0,            /* rotation angle in degrees */
+                        PHANTOM_ARMOR,  /* component code number */
+                        0.0,            /* normal thickness of component */
+                        0.0,            /* LOS thickness of component */
+                        space,          /* space code */
+                        0.0,            /* entry obliquity angle in degrees */
+                        0.0             /* exit obliquity angle in degrees */
+               );
+       if (ret < 0) {
+           bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->shotlnfile));
+       }
+    }
+    return;
+}
+
+/*
+  Burst Point Library and Shotline file: information about each component
+  hit along path of main penetrator (shotline).
+  Ref. Figure 20., Line Number 3 and Figure 19., Line Number 2 of ICD.
+*/
+void
+prntSeg(struct application *ap,
+               struct partition *cpp /* component partition */,
+               int space, fastf_t entrynorm[3], fastf_t exitnorm[3],
+               int burstflag /* Was a burst generated by this partition? */
+       )
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    fastf_t icosobliquity;      /* cosine of obliquity at entry */
+    fastf_t ocosobliquity;      /* cosine of obliquity at exit */
+    fastf_t entryangle; /* obliquity angle at entry */
+    fastf_t exitangle;  /* obliquity angle at exit */
+    fastf_t los;                /* line-of-sight thickness */
+    fastf_t normthickness;      /* normal thickness */
+    fastf_t rotangle;   /* rotation angle */
+    fastf_t sinfbangle; /* sine of fall back angle */
+
+    /* This *should* give negative of desired result. */
+    icosobliquity = VDOT(ap->a_ray.r_dir, entrynorm);
+    icosobliquity = -icosobliquity;
+
+    ocosobliquity = VDOT(ap->a_ray.r_dir, exitnorm);
+
+    if (NEAR_ZERO(exitnorm[Y], VDIVIDE_TOL) && NEAR_ZERO(exitnorm[X], 
VDIVIDE_TOL))
+       rotangle = 0.0;
+    else {
+       rotangle = atan2(exitnorm[Y], exitnorm[X]);
+       rotangle *= RAD2DEG; /* convert to degrees */
+       if (rotangle < 0.0)
+           rotangle += 360.0;
+    }
+    /* Compute sine of fallback angle.  NB: the Air Force measures the
+       fallback angle from the horizontal (X-Y) plane. */
+    sinfbangle = VDOT(exitnorm, s->zaxis);
+
+    los = (cpp->pt_outhit->hit_dist-cpp->pt_inhit->hit_dist)*s->unitconv;
+
+    if (bu_vls_strlen(&s->outfile)
+           &&      fprintf(s->outfp,
+               "%c % 8.2f % 8.2f %5d %2d % 7.3f % 7.2f % 7.3f %c\n",
+               PB_RAY_INTERSECT,
+               (s->standoff - cpp->pt_inhit->hit_dist)*s->unitconv,
+               /* X'-coordinate of intersection */
+               los,            /* LOS thickness of component */
+               cpp->pt_regionp->reg_regionid,
+               /* component code number */
+               space,          /* space code */
+               sinfbangle,     /* sine of fallback angle at exit */
+               rotangle,       /* rotation angle in degrees at exit */
+               icosobliquity,  /* cosine of obliquity angle at entry */
+               burstflag ? '1' : '0' /* flag generation of burst */
+               ) < 0
+       ) {
+       bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->outfile));
+    }
+
+    if (!bu_vls_strlen(&s->shotlnfile))
+       return;
+    entryangle = NEAR_EQUAL(icosobliquity, 1.0, COS_TOL) ? 0.0 : 
acos(icosobliquity) * RAD2DEG;
+    if ((normthickness = getNormThickness(ap, cpp, icosobliquity, entrynorm)) 
<= 0.0 && s->fatalerror) {
+        bu_log("Couldn't compute normal thickness.\n");
+        bu_log("\tshotline coordinates <%g, %g>\n",
+                 ap->a_uvec[X]*s->unitconv,
+                 ap->a_uvec[Y]*s->unitconv
+            );
+        bu_log("\tregion name '%s' solid name '%s'\n",
+                 cpp->pt_regionp->reg_name,
+                 cpp->pt_inseg->seg_stp->st_name);
+        return;
+    }
+    exitangle = NEAR_EQUAL(ocosobliquity, 1.0, COS_TOL) ? 0.0 : 
acos(ocosobliquity) * RAD2DEG;
+    if (fprintf(s->shotlnfp,
+                "%c % 8.2f % 7.3f % 7.2f %5d % 8.2f % 8.2f %2d % 7.2f % 
7.2f\n",
+                PS_SHOT_INTERSECT,
+                (s->standoff - cpp->pt_inhit->hit_dist)*s->unitconv,
+                /* X'-coordinate of intersection */
+                sinfbangle,     /* sine of fallback angle at exit */
+                rotangle,       /* rotation angle in degrees at exit */
+                cpp->pt_regionp->reg_regionid,
+                /* component code number */
+                normthickness*s->unitconv,
+                /* normal thickness of component */
+                los,            /* LOS thickness of component */
+                space,          /* space code */
+                entryangle,     /* entry obliquity angle in degrees */
+                exitangle       /* exit obliquity angle in degrees */
+            ) < 0
+        ) {
+        bu_exit(EXIT_FAILURE, "Write failed to file (%s)!\n", 
bu_vls_cstr(&s->shotlnfile));
+    }
+}
+
+/*
+  int f_BurstMiss(struct application *ap)
+
+  Burst ray missed the model, so do nothing.
+*/
+static int
+f_BurstMiss(struct application *ap)
+{
+    VSETALL(ap->a_color, 0.0); /* All misses black. */
+    return     0;
+}
+
+/* To facilitate one-time per burst point initialization of the spall
+   ray application structure while leaving burstRay() with the
+   capability of being used as a multitasking process, a_burst must
+   be accessible by both the burstPoint() and burstRay() routines, but
+   can be local to this module. */
+static struct application      a_burst; /* prototype spall ray */
+
+static void
+spallVec(struct burst_state *s, fastf_t *dvec, fastf_t *s_rdir, fastf_t phi, 
fastf_t gammaval)
+{
+    fastf_t cosphi = cos(phi);
+    fastf_t singamma = sin(gammaval);
+    fastf_t cosgamma = cos(gammaval);
+    fastf_t csgaphi, ssgaphi;
+    fastf_t sinphi = sin(phi);
+    fastf_t cosdphi[3];
+    fastf_t fvec[3];
+    fastf_t evec[3];
+
+    if (VNEAR_EQUAL(dvec, s->zaxis, VEC_TOL) || VNEAR_EQUAL(dvec, s->negzaxis, 
VEC_TOL)) {
+       VMOVE(evec, s->xaxis);
+    } else {
+       VCROSS(evec, dvec, s->zaxis);
+    }
+    VCROSS(fvec, evec, dvec);
+    VSCALE(cosdphi, dvec, cosphi);
+    ssgaphi = singamma * sinphi;
+    csgaphi = cosgamma * sinphi;
+    VJOIN2(s_rdir, cosdphi, ssgaphi, evec, csgaphi, fvec);
+    VUNITIZE(s_rdir);
+    return;
+}
+
+void
+plotRayPoint(struct burst_state *s, struct xray *rayp)
+{
+    int endpoint[3];
+    if (s->plotfp == NULL)
+        return;
+    VJOIN1(endpoint, rayp->r_pt, s->cellsz, rayp->r_dir);
+
+    bu_semaphore_acquire(BU_SEM_SYSCALL);
+    pl_color(s->plotfp, R_BURST, G_BURST, B_BURST);
+
+    /* draw point */
+    pl_3point(s->plotfp, (int) endpoint[X], (int) endpoint[Y], (int) 
endpoint[Z]);
+
+    bu_semaphore_release(BU_SEM_SYSCALL);
+    return;
+}
+
+void
+plotRayLine(struct burst_state *s, struct xray *rayp)
+{
+    int endpoint[3];
+    if (s->plotfp == NULL)
+        return;
+    VJOIN1(endpoint, rayp->r_pt, s->cellsz, rayp->r_dir);
+
+    bu_semaphore_acquire(BU_SEM_SYSCALL);
+    pl_color(s->plotfp, R_BURST, G_BURST, B_BURST);
+
+    /* draw line */
+    pl_3line(s->plotfp,
+             (int) rayp->r_pt[X],
+             (int) rayp->r_pt[Y],
+             (int) rayp->r_pt[Z],
+             endpoint[X],
+             endpoint[Y],
+             endpoint[Z]
+        );
+
+    bu_semaphore_release(BU_SEM_SYSCALL);
+    return;
+}
+
+
+static int
+burstRay(struct burst_state *s)
+{
+    /* Need local copy of all but readonly variables for concurrent
+       threads of execution. */
+    struct application a_spall;
+    fastf_t                    phi;
+    int                        hitcrit = 0;
+    a_spall = a_burst;
+    a_spall.a_resource = RESOURCE_NULL;
+    for (; ! s->userinterrupt;) {
+       fastf_t sinphi;
+       fastf_t gammaval, gammainc, gammalast;
+       int done;
+       int m;
+       bu_semaphore_acquire(RT_SEM_WORKER);
+       phi = comphi;
+       comphi += phiinc;
+       done = phi > s->conehfangle;
+       bu_semaphore_release(RT_SEM_WORKER);
+       if (done)
+           break;
+       sinphi = sin(phi);
+       sinphi = fabs(sinphi);
+       m = (M_2PI * sinphi)/delta + 1;
+       gammainc = M_2PI / m;
+       gammalast = M_2PI - gammainc + VUNITIZE_TOL;
+       for (gammaval = 0.0; gammaval <= gammalast; gammaval += gammainc) {
+           int ncrit;
+           spallVec(s, a_burst.a_ray.r_dir, a_spall.a_ray.r_dir,
+                    phi, gammaval);
+
+           if (s->plotline)
+               plotRayPoint(s, &a_spall.a_ray);
+           else
+               plotRayLine(s, &a_spall.a_ray);
+
+           bu_semaphore_acquire(RT_SEM_WORKER);
+           a_spall.a_user = a_burst.a_user++;
+           bu_semaphore_release(RT_SEM_WORKER);
+           if ((ncrit = rt_shootray(&a_spall)) == -1
+               &&      s->fatalerror) {
+               /* Fatal error in application routine. */
+               bu_log("Error: ray tracing aborted.\n");
+               return  0;
+           }
+           if (bu_vls_strlen(&s->fbfile) && ncrit > 0) {
+               paintSpallFb(&a_spall);
+               hitcrit = 1;
+           }
+           if (bu_vls_strlen(&s->histfile)) {
+               bu_semaphore_acquire(BU_SEM_SYSCALL);
+               (void) fprintf(s->histfp, "%d\n", ncrit);
+               bu_semaphore_release(BU_SEM_SYSCALL);
+           }
+       }
+    }
+    if (bu_vls_strlen(&s->fbfile)) {
+       if (hitcrit)
+           paintCellFb(&a_spall, s->pixcrit, s->pixtarg);
+       else
+           paintCellFb(&a_spall, s->pixbhit, s->pixtarg);
+    }
+    return     1;
+}
+
+/*
+ * This routine dispatches the burst point ray tracing task burstRay().
+ * RETURN CODES:       0 for fatal ray tracing error, 1 otherwise.
+ *
+ * bpt is burst point coordinates.
+ */
+static int
+burstPoint(struct application *ap, fastf_t *normal, fastf_t *bpt)
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    a_burst = *ap;
+    a_burst.a_miss = f_BurstMiss;
+    a_burst.a_hit = f_BurstHit;
+    a_burst.a_level++;
+    a_burst.a_user = 0; /* ray number */
+    a_burst.a_purpose = "spall ray";
+    a_burst.a_uptr = ap->a_uptr;
+    assert(a_burst.a_overlap == ap->a_overlap);
+
+    /* If pitch or yaw is specified, cant the main penetrator
+       axis. */
+    if (s->cantwarhead) {
+       VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, cantdelta);
+       VUNITIZE(a_burst.a_ray.r_dir);
+    }
+    /* If a deflected cone is specified (the default) the spall cone
+       axis is half way between the main penetrator axis and exit
+       normal of the spalling component.
+    */
+    if (s->deflectcone) {
+       VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, normal);
+       VUNITIZE(a_burst.a_ray.r_dir);
+    }
+    VMOVE(a_burst.a_ray.r_pt, bpt);
+
+    comphi = 0.0; /* Initialize global for concurrent access. */
+
+    /* SERIAL case -- one CPU does all the work. */
+    return burstRay(s);
+}
+
+
+/*
   int f_ShotHit(struct application *ap, struct partition *pt_headp)
 
   This routine is called when a shotline hits the model.  All output
@@ -359,22 +1093,15 @@
 static int
 f_ShotHit(struct application *ap, struct partition *pt_headp, struct seg 
*UNUSED(segp))
 {
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
     struct partition *pp;
     struct partition *bp = PT_NULL;
     vect_t burstnorm = VINIT_ZERO; /* normal at burst point */
-#if DEBUG_GRID
-    brst_log("f_ShotHit\n");
-    for (pp = pt_headp->pt_forw; pp != pt_headp; pp = pp->pt_forw)
-       brst_log("\tregion is '%s', \tid=%d\taircode=%d\n",
-                pp->pt_regionp->reg_name,
-                (int) pp->pt_regionp->reg_regionid,
-                (int) pp->pt_regionp->reg_aircode);
-#endif
     /* Output cell identification. */
     prntCellIdent(ap);
     /* Color cell if making frame buffer image. */
-    if (fbfile[0] != NUL)
-       paintCellFb(ap, pixtarg, zoom == 1 ? pixblack : pixbkgr);
+    if (bu_vls_strlen(&s->fbfile))
+       paintCellFb(ap, s->pixtarg, s->zoom == 1 ? s->pixblack : s->pixbkgr);
 
     /* First delete thin partitions. */
     enforceLOS(ap, pt_headp);
@@ -403,12 +1130,10 @@
            struct hit *ihitp = pp->pt_inhit;
            struct hit *ohitp = pp->pt_outhit;
            struct xray *rayp = &ap->a_ray;
-           VJOIN1(ihitp->hit_point, rayp->r_pt, ihitp->hit_dist,
-                  rayp->r_dir);
-           VJOIN1(ohitp->hit_point, rayp->r_pt, ohitp->hit_dist,
-                  rayp->r_dir);
-           colorPartition(regp, C_MAIN);
-           plotPartition(ihitp, ohitp);
+           VJOIN1(ihitp->hit_point, rayp->r_pt, ihitp->hit_dist, rayp->r_dir);
+           VJOIN1(ohitp->hit_point, rayp->r_pt, ohitp->hit_dist, rayp->r_dir);
+           colorPartition(s, regp, C_MAIN);
+           plotPartition(s, ihitp, ohitp);
        }
 
        /* Check for voids. */
@@ -415,29 +1140,13 @@
        if (np != pt_headp) {
            fastf_t los = 0.0;
 
-#if DEBUG_GRID
-           brst_log("\tprocessing region '%s', \tid=%d\taircode=%d\n",
-                    pp->pt_regionp->reg_name,
-                    (int) pp->pt_regionp->reg_regionid,
-                    (int) pp->pt_regionp->reg_aircode);
-           brst_log("\tcheck for voids\n");
-#endif
-           los = np->pt_inhit->hit_dist -
-               pp->pt_outhit->hit_dist;
-#if DEBUG_GRID
-           brst_log("\tlos=%g tolerance=%g\n",
-                    los, LOS_TOL);
-#endif
+           los = np->pt_inhit->hit_dist - pp->pt_outhit->hit_dist;
            voidflag = (los > LOS_TOL);
            /* If the void occurs adjacent to explicit outside
               air, extend the outside air to fill it. */
            if (OutsideAir(np->pt_regionp)) {
-#if DEBUG_GRID
-               brst_log("\t\toutside air\n");
-#endif
                if (voidflag) {
-                   np->pt_inhit->hit_dist =
-                       pp->pt_outhit->hit_dist;
+                   np->pt_inhit->hit_dist = pp->pt_outhit->hit_dist;
                    voidflag = 0;
                }
                /* Keep going until we are past 01 air. */
@@ -444,40 +1153,29 @@
                for (cp = np->pt_forw;
                     cp != pt_headp;
                     cp = cp->pt_forw) {
-                   if (OutsideAir(cp->pt_regionp))
+                   if (OutsideAir(cp->pt_regionp)) {
                        /* Include outside air. */
-                       np->pt_outhit->hit_dist =
-                           cp->pt_outhit->hit_dist;
-                   else
-                       if (cp->pt_inhit->hit_dist -
-                           np->pt_outhit->hit_dist
-                           > LOS_TOL)
-                           /* Include void following
-                              outside air. */
-                           np->pt_outhit->hit_dist =
-                               cp->pt_inhit->hit_dist;
-                       else
+                       np->pt_outhit->hit_dist = cp->pt_outhit->hit_dist;
+                   } else {
+                       if (cp->pt_inhit->hit_dist - np->pt_outhit->hit_dist > 
LOS_TOL) {
+                           /* Include void following outside air. */
+                           np->pt_outhit->hit_dist = cp->pt_inhit->hit_dist;
+                       } else {
                            break;
+                       }
+                   }
                }
            }
        }
        /* Merge adjacent inside airs of same type. */
        if (np != pt_headp && InsideAir(np->pt_regionp)) {
-#if DEBUG_GRID
-           brst_log("\tmerging inside airs\n");
-#endif
-           for (cp = np->pt_forw;
-                cp != pt_headp;
-                cp = cp->pt_forw) {
-               if (InsideAir(cp->pt_regionp)
-                   &&  SameAir(np->pt_regionp, cp->pt_regionp)
-                   &&  cp->pt_inhit->hit_dist -
-                   np->pt_outhit->hit_dist
-                   <= LOS_TOL)
-                   np->pt_outhit->hit_dist =
-                       cp->pt_outhit->hit_dist;
-               else
+           for (cp = np->pt_forw; cp != pt_headp; cp = cp->pt_forw) {
+               if (InsideAir(cp->pt_regionp) && SameAir(np->pt_regionp, 
cp->pt_regionp)
+                   &&  cp->pt_inhit->hit_dist - np->pt_outhit->hit_dist <= 
LOS_TOL) {
+                   np->pt_outhit->hit_dist = cp->pt_outhit->hit_dist;
+               } else {
                    break;
+               }
            }
        }
 
@@ -486,45 +1184,33 @@
        if (pp->pt_back == pt_headp && InsideAir(regp)) {
            /* If adjacent partitions are the same air, extend
               the first on to include them. */
-#if DEBUG_GRID
-           brst_log("\tphantom armor before internal air\n");
-#endif
            for (cp = np; cp != pt_headp; cp = cp->pt_forw) {
-               if (InsideAir(cp->pt_regionp)
-                   &&  SameAir(regp, cp->pt_regionp)
-                   &&  cp->pt_inhit->hit_dist -
-                   pp->pt_outhit->hit_dist
-                   <= LOS_TOL)
-                   pp->pt_outhit->hit_dist =
-                       cp->pt_outhit->hit_dist;
-               else
+               if (InsideAir(cp->pt_regionp) && SameAir(regp, cp->pt_regionp)
+                   &&  cp->pt_inhit->hit_dist - pp->pt_outhit->hit_dist <= 
LOS_TOL) {
+                   pp->pt_outhit->hit_dist = cp->pt_outhit->hit_dist;
+               } else {
                    break;
-
+               }
            }
 
-           prntPhantom(pp->pt_inhit, (int) regp->reg_aircode);
-       } else
-           if (! Air(regp)) {
+           prntPhantom(s, pp->pt_inhit, (int) regp->reg_aircode);
+       } else {
+           if (!Air(regp)) {
                /* If we have a component, output it. */
                fastf_t entrynorm[3];   /* normal at entry */
                fastf_t exitnorm[3];    /* normal at exit */
                /* Get entry normal. */
                getRtHitNorm(pp->pt_inhit, pp->pt_inseg->seg_stp,
-                            &ap->a_ray, (int) pp->pt_inflip, entrynorm);
-               (void) chkEntryNorm(pp, &ap->a_ray, entrynorm,
-                                   "shotline entry normal");
+                       &ap->a_ray, (int) pp->pt_inflip, entrynorm);
+               (void) chkEntryNorm(pp, &ap->a_ray, entrynorm, "shotline entry 
normal");
                /* Get exit normal. */
                getRtHitNorm(pp->pt_outhit, pp->pt_outseg->seg_stp,
-                            &ap->a_ray, (int) pp->pt_outflip, exitnorm);
-               (void) chkExitNorm(pp, &ap->a_ray, exitnorm,
-                                  "shotline exit normal");
+                       &ap->a_ray, (int) pp->pt_outflip, exitnorm);
+               (void) chkExitNorm(pp, &ap->a_ray, exitnorm, "shotline exit 
normal");
 
-#if DEBUG_GRID
-               brst_log("\twe have a component\n");
-#endif
                /* In the case of fragmenting munitions, a hit on any
                   component will cause a burst point. */
-               if (bp == PT_NULL && bdist > 0.0) {
+               if (bp == PT_NULL && s->bdist > 0.0) {
                    bp = pp;    /* exterior burst */
                    VMOVE(burstnorm, exitnorm);
                }
@@ -531,252 +1217,96 @@
 
                /* If there is a void, output 01 air as space. */
                if (voidflag) {
-#if DEBUG_GRID
-                   brst_log("\t\tthere is a void, %s\n",
-                            "so outputting 01 air");
-#endif
-                   if (bp == PT_NULL && ! reqburstair
-                       &&      findIdents(regp->reg_regionid,
-                                          &armorids)) {
+                   if (bp == PT_NULL && ! s->reqburstair && 
findIdents(regp->reg_regionid, &s->armorids)) {
                        /* Bursting on armor/void (ouch). */
                        bp = pp;
                        VMOVE(burstnorm, exitnorm);
                    }
-                   prntSeg(ap, pp, OUTSIDE_AIR,
-                           entrynorm, exitnorm, pp == bp);
-               } else
+                   prntSeg(ap, pp, OUTSIDE_AIR, entrynorm, exitnorm, pp == bp);
+               } else {
                    /* If air explicitly follows, output space code. */
                    if (np != pt_headp && Air(nregp)) {
                        /* Check for interior burst point. */
-#if DEBUG_GRID
-                       brst_log("\t\texplicit air follows\n");
-#endif
-                       if (bp == PT_NULL && bdist <= 0.0
-                           &&  findIdents(regp->reg_regionid,
-                                          &armorids)
-                           && (! reqburstair
-                               ||      findIdents(nregp->reg_aircode,
-                                                  &airids))
-                           ) {
+                       if (bp == PT_NULL && s->bdist <= 0.0 && 
findIdents(regp->reg_regionid, &s->armorids)
+                               && (!s->reqburstair || 
findIdents(nregp->reg_aircode, &s->airids))) {
                            bp = pp; /* interior burst */
                            VMOVE(burstnorm, exitnorm);
                        }
-                       prntSeg(ap, pp, nregp->reg_aircode,
-                               entrynorm, exitnorm, pp == bp);
-                   } else
+                       prntSeg(ap, pp, nregp->reg_aircode, entrynorm, 
exitnorm, pp == bp);
+                   } else {
                        if (np == pt_headp) {
                            /* Last component gets 09 air. */
-#if DEBUG_GRID
-                           brst_log("\t\tlast component\n");
-#endif
-                           prntSeg(ap, pp, EXIT_AIR,
-                                   entrynorm, exitnorm, pp == bp);
-                       } else
+                           prntSeg(ap, pp, EXIT_AIR, entrynorm, exitnorm, pp 
== bp);
+                       } else {
                            /* No air follows component. */
                            if (SameCmp(regp, nregp)) {
-#if DEBUG_GRID
-                               brst_log("\t\tmerging adjacent components\n");
-#endif
-                               /* Merge adjacent components with same
-                                  idents. */
+                               /* Merge adjacent components with same idents. 
*/
                                *np->pt_inhit = *pp->pt_inhit;
                                np->pt_inseg = pp->pt_inseg;
                                np->pt_inflip = pp->pt_inflip;
                                continue;
                            } else {
-#if DEBUG_GRID
-                               brst_log("\t\tdifferent component follows\n");
-#endif
-                               prntSeg(ap, pp, 0,
-                                       entrynorm, exitnorm, pp == bp);
+                               prntSeg(ap, pp, 0, entrynorm, exitnorm, pp == 
bp);
                                /* component follows */
                            }
+                       }
+                   }
+               }
            }
+       }
+
        /* Check for adjacency of differing airs, implicit or
           explicit and output phantom armor as needed. */
        if (InsideAir(regp)) {
-#if DEBUG_GRID
-           brst_log("\tcheck for adjacency of differing airs; inside air\n");
-#endif
            /* Inside air followed by implicit outside air. */
            if (voidflag)
-               prntPhantom(pp->pt_outhit, OUTSIDE_AIR);
+               prntPhantom(s, pp->pt_outhit, OUTSIDE_AIR);
        }
        /* Check next partition for adjacency problems. */
        if (np != pt_headp) {
-#if DEBUG_GRID
-           brst_log("\tcheck next partition for adjacency\n");
-#endif
            /* See if inside air follows impl. outside air. */
            if (voidflag && InsideAir(nregp)) {
-#if DEBUG_GRID
-               brst_log("\t\tinside air follows impl. outside air\n");
-#endif
-               prntPhantom(np->pt_inhit, nregp->reg_aircode);
+               prntPhantom(s, np->pt_inhit, nregp->reg_aircode);
            } else
                /* See if differing airs are adjacent. */
-               if (!   voidflag
-                   &&  Air(regp)
-                   &&  Air(nregp)
-                   &&  DiffAir(nregp, regp)
-                   ) {
-#if DEBUG_GRID
-                   brst_log("\t\tdiffering airs are adjacent\n");
-#endif
-                   prntPhantom(np->pt_inhit, (int) nregp->reg_aircode);
+               if (!voidflag && Air(regp) && Air(nregp) && DiffAir(nregp, 
regp)) {
+                   prntPhantom(s, np->pt_inhit, (int) nregp->reg_aircode);
                }
        }
        /* Output phantom armor if internal air is last hit. */
        if (np == pt_headp && InsideAir(regp)) {
-#if DEBUG_GRID
-           brst_log("\tinternal air last hit\n");
-#endif
-           prntPhantom(pp->pt_outhit, EXIT_AIR);
+           prntPhantom(s, pp->pt_outhit, EXIT_AIR);
        }
     }
-    if (nriplevels == 0)
+    if (s->nriplevels == 0)
        return  1;
 
     if (bp != PT_NULL) {
        fastf_t burstpt[3];
        /* This is a burst point, calculate coordinates. */
-       if (bdist > 0.0) {
+       if (s->bdist > 0.0) {
            /* Exterior burst point (i.e. case-fragmenting
               munition with contact-fuzed set-back device):
               location is bdist prior to entry point. */
-           VJOIN1(burstpt, bp->pt_inhit->hit_point, -bdist,
-                  ap->a_ray.r_dir);
+           VJOIN1(burstpt, bp->pt_inhit->hit_point, -s->bdist, 
ap->a_ray.r_dir);
        } else
-           if (bdist < 0.0) {
+           if (s->bdist < 0.0) {
                /* Interior burst point (i.e. case-fragment
                   munition with delayed fuzing): location is
                   the magnitude of bdist beyond the exit
                   point. */
-               VJOIN1(burstpt, bp->pt_outhit->hit_point, -bdist,
-                      ap->a_ray.r_dir);
+               VJOIN1(burstpt, bp->pt_outhit->hit_point, -s->bdist, 
ap->a_ray.r_dir);
            } else        /* Interior burst point: no fuzing offset. */
                VMOVE(burstpt, bp->pt_outhit->hit_point);
 
-       /* Only generate burst rays if nspallrays is greater than
-          zero. */
-       if (nspallrays < 1)
-           return      1;
-
-       return  burstPoint(ap, burstnorm, burstpt);
+       /* Only generate burst rays if nspallrays is greater than zero. */
+       return  (s->nspallrays < 1) ? 1 : burstPoint(ap, burstnorm, burstpt);
     }
-    return     1;
+    return 1;
 }
 
 
-/*
-  void getRtHitNorm(struct hit *hitp, struct soltab *stp,
-  struct xray *rayp, int flipped, fastf_t normvec[3])
 
-  Fill normal and hit point into hit struct and if the flipped
-  flag is set, reverse the normal.  Return a private copy of the
-  flipped normal in normvec.  NOTE: the normal placed in the hit
-  struct should not be modified (i.e. reversed) by the application
-  because it can be instanced by other solids.
-*/
-void
-getRtHitNorm(struct hit *hitp, struct soltab *stp, struct xray *UNUSED(rayp), 
int flipped, fastf_t normvec[3])
-{
-    RT_HIT_NORMAL(normvec, hitp, stp, rayp, flipped);
-}
-
-
-int
-chkEntryNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], char 
*purpose)
-{
-    fastf_t f;
-    static int flipct = 0;
-    static int totalct = 0;
-    struct soltab *stp = pp->pt_inseg->seg_stp;
-    int ret = 1;
-    totalct++;
-    /* Dot product of ray direction with normal *should* be negative. */
-    f = VDOT(rayp->r_dir, normvec);
-    if (ZERO(f)) {
-#ifdef DEBUG
-       brst_log("chkEntryNorm: near 90 degree obliquity.\n");
-       brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
-                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
-                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
-                normvec[X], normvec[Y], normvec[Z]);
-#endif
-       ret = 0;
-    }
-    if (f > 0.0) {
-       flipct++;
-       brst_log("Fixed flipped entry normal:\n");
-       brst_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
-                pp->pt_regionp->reg_name, stp->st_name,
-                stp->st_id, purpose);
-#ifdef DEBUG
-       brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
-                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
-                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
-                normvec[X], normvec[Y], normvec[Z]);
-       brst_log("\tDist %g Hit Pnt %g, %g, %g\n",
-                pp->pt_inhit->hit_dist,
-                pp->pt_inhit->hit_point[X],
-                pp->pt_inhit->hit_point[Y],
-                pp->pt_inhit->hit_point[Z]);
-       brst_log("\t%d of %d normals flipped.\n", flipct, totalct);
-#endif
-       VSCALE(normvec, normvec, -1.0);
-       ret = 0;
-    }
-    return ret;
-}
-
-
-int
-chkExitNorm(struct partition *pp, struct xray *rayp, fastf_t normvec[3], char 
*purpose)
-{
-    fastf_t f;
-    static int flipct = 0;
-    static int totalct = 0;
-    struct soltab *stp = pp->pt_outseg->seg_stp;
-    int ret = 1;
-    totalct++;
-    /* Dot product of ray direction with normal *should* be positive. */
-    f = VDOT(rayp->r_dir, normvec);
-    if (ZERO(f)) {
-#ifdef DEBUG
-       brst_log("chkExitNorm: near 90 degree obliquity.\n");
-       brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
-                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
-                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
-                normvec[X], normvec[Y], normvec[Z]);
-#endif
-       ret = 0;
-    }
-    if (f < 0.0) {
-       flipct++;
-       brst_log("Fixed flipped exit normal:\n");
-       brst_log("\tregion \"%s\" solid \"%s\" type %d \"%s\".\n",
-                pp->pt_regionp->reg_name, stp->st_name,
-                stp->st_id, purpose);
-#ifdef DEBUG
-       brst_log("\tPnt %g, %g, %g\n\tDir %g, %g, %g\n\tNorm %g, %g, %g.\n",
-                rayp->r_pt[X], rayp->r_pt[Y], rayp->r_pt[Z],
-                rayp->r_dir[X], rayp->r_dir[Y], rayp->r_dir[Z],
-                normvec[X], normvec[Y], normvec[Z]);
-       brst_log("\tDist %g Hit Pnt %g, %g, %g\n",
-                pp->pt_outhit->hit_dist,
-                pp->pt_outhit->hit_point[X],
-                pp->pt_outhit->hit_point[Y],
-                pp->pt_outhit->hit_point[Z]);
-       brst_log("\t%d of %d normals flipped.\n", flipct, totalct);
-#endif
-       VSCALE(normvec, normvec, -1.0);
-       ret = 0;
-    }
-    return ret;
-}
-
-
 /*
   int f_ShotMiss(struct application *ap)
 
@@ -820,7 +1350,7 @@
            } else
                if (bdist < 0.0) {
                    /* interior burst not implemented in ground */
-                   brst_log("User error: %s %s.\n",
+                   bu_log("User error: %s %s.\n",
                             "negative burst distance can not be",
                             "specified with ground plane bursting"
                        );
@@ -844,19 +1374,8 @@
 }
 
 
-/*
-  int f_BurstMiss(struct application *ap)
+#if 0
 
-  Burst ray missed the model, so do nothing.
-*/
-static int
-f_BurstMiss(struct application *ap)
-{
-    VSETALL(ap->a_color, 0.0); /* All misses black. */
-    return     0;
-}
-
-
 /*
   int getRayOrigin(struct application *ap)
 
@@ -964,39 +1483,6 @@
 }
 
 /*
-  void lgtModel(struct application *ap, struct partition *pp,
-  struct hit *hitp, struct xray *rayp,
-  fastf_t surfnorm[3])
-
-  This routine is a simple lighting model which places RGB coefficients
-  (0 to 1) in ap->a_color based on the cosine of the angle between
-  the surface normal and viewing direction and the color associated with
-  the component.  Also, the distance to the surface is placed in
-  ap->a_cumlen so that the impact location can be projected into grid
-  space.
-*/
-static void
-lgtModel(struct application *ap, struct partition *pp, struct hit *hitp, 
struct xray *UNUSED(rayp), fastf_t surfnorm[3])
-{
-    struct colors *colorp;
-    fastf_t intensity = -VDOT(viewdir, surfnorm);
-    if (intensity < 0.0)
-       intensity = -intensity;
-
-    colorp = findColors(pp->pt_regionp->reg_regionid, &s->colorids
-    if (colorp != COLORS_NULL) {
-       ap->a_color[RED] = (fastf_t)colorp->c_rgb[RED]/255.0;
-       ap->a_color[GRN] = (fastf_t)colorp->c_rgb[GRN]/255.0;
-       ap->a_color[BLU] = (fastf_t)colorp->c_rgb[BLU]/255.0;
-    } else {
-       ap->a_color[RED] = ap->a_color[GRN] = ap->a_color[BLU] = 1.0;
-    }
-    VSCALE(ap->a_color, ap->a_color, intensity);
-    ap->a_cumlen = hitp->hit_dist;
-}
-
-
-/*
   int readBurst(fastf_t *vec)
 
   This routine reads the next set of burst point coordinates from the
@@ -1016,7 +1502,7 @@
     VMOVE(vec, scan); /* double to fastf_t */
     if (items != 3) {
        if (items != EOF) {
-           brst_log("Fatal error: %d burst coordinates read.\n",
+           bu_log("Fatal error: %d burst coordinates read.\n",
                     items);
            fatalerror = 1;
            return      0;
@@ -1057,7 +1543,7 @@
        VMOVE(vec, scan);
        if (items != 2) {
            if (items != EOF) {
-               brst_log("Fatal error: only %d firing coordinates read.\n", 
items);
+               bu_log("Fatal error: only %d firing coordinates read.\n", 
items);
                fatalerror = 1;
                return  0;
            } else {
@@ -1077,7 +1563,7 @@
            VMOVE(vec, scan); /* double to fastf_t */
            if (items != 3) {
                if (items != EOF) {
-                   brst_log("Fatal error: %d firing coordinates read.\n", 
items);
+                   bu_log("Fatal error: %d firing coordinates read.\n", items);
                    fatalerror = 1;
                    return      0;
                } else {
@@ -1089,7 +1575,7 @@
                vec[Z] /= unitconv;
            }
        } else {
-           brst_log("BUG: readShot called with bad firemode.\n");
+           bu_log("BUG: readShot called with bad firemode.\n");
            return      0;
        }
     return     1;
@@ -1112,150 +1598,10 @@
 }
 
 
-static void
-spallVec(fastf_t *dvec, fastf_t *s_rdir, fastf_t phi, fastf_t gammaval)
-{
-    fastf_t                    cosphi = cos(phi);
-    fastf_t                    singamma = sin(gammaval);
-    fastf_t                    cosgamma = cos(gammaval);
-    fastf_t                    csgaphi, ssgaphi;
-    fastf_t                    sinphi = sin(phi);
-    fastf_t                    cosdphi[3];
-    fastf_t                    fvec[3];
-    fastf_t                    evec[3];
 
-    if (VNEAR_EQUAL(dvec, zaxis, VEC_TOL)
-       ||      VNEAR_EQUAL(dvec, negzaxis, VEC_TOL)
-       ) {
-       VMOVE(evec, xaxis);
-    } else {
-       VCROSS(evec, dvec, zaxis);
-    }
-    VCROSS(fvec, evec, dvec);
-    VSCALE(cosdphi, dvec, cosphi);
-    ssgaphi = singamma * sinphi;
-    csgaphi = cosgamma * sinphi;
-    VJOIN2(s_rdir, cosdphi, ssgaphi, evec, csgaphi, fvec);
-    VUNITIZE(s_rdir);
-    return;
-}
 
 
-static int
-burstRay(struct burst_state *s)
-{
-    /* Need local copy of all but readonly variables for concurrent
-       threads of execution. */
-    struct application a_spall;
-    fastf_t                    phi;
-    int                        hitcrit = 0;
-    a_spall = a_burst;
-    a_spall.a_resource = RESOURCE_NULL;
-    for (; ! userinterrupt;) {
-       fastf_t sinphi;
-       fastf_t gammaval, gammainc, gammalast;
-       int done;
-       int m;
-       bu_semaphore_acquire(RT_SEM_WORKER);
-       phi = comphi;
-       comphi += phiinc;
-       done = phi > conehfangle;
-       bu_semaphore_release(RT_SEM_WORKER);
-       if (done)
-           break;
-       sinphi = sin(phi);
-       sinphi = fabs(sinphi);
-       m = (M_2PI * sinphi)/delta + 1;
-       gammainc = M_2PI / m;
-       gammalast = M_2PI - gammainc + VUNITIZE_TOL;
-       for (gammaval = 0.0; gammaval <= gammalast; gammaval += gammainc) {
-           int ncrit;
-           spallVec(a_burst.a_ray.r_dir, a_spall.a_ray.r_dir,
-                    phi, gammaval);
-
-           if (plotline)
-               plotRayPoint(&a_spall.a_ray);
-           else
-               plotRayLine(&a_spall.a_ray);
-
-           bu_semaphore_acquire(RT_SEM_WORKER);
-           a_spall.a_user = a_burst.a_user++;
-           bu_semaphore_release(RT_SEM_WORKER);
-           if ((ncrit = rt_shootray(&a_spall)) == -1
-               &&      fatalerror) {
-               /* Fatal error in application routine. */
-               brst_log("Error: ray tracing aborted.\n");
-               return  0;
-           }
-           if (fbfile[0] != NUL && ncrit > 0) {
-               paintSpallFb(&a_spall);
-               hitcrit = 1;
-           }
-           if (histfile[0] != NUL) {
-               bu_semaphore_acquire(BU_SEM_SYSCALL);
-               (void) fprintf(histfp, "%d\n", ncrit);
-               bu_semaphore_release(BU_SEM_SYSCALL);
-           }
-       }
-    }
-    if (fbfile[0] != NUL) {
-       if (hitcrit)
-           paintCellFb(&a_spall, pixcrit, pixtarg);
-       else
-           paintCellFb(&a_spall, pixbhit, pixtarg);
-    }
-    return     1;
-}
-
-
-
-/* To facilitate one-time per burst point initialization of the spall
-   ray application structure while leaving burstRay() with the
-   capability of being used as a multitasking process, a_burst must
-   be accessible by both the burstPoint() and burstRay() routines, but
-   can be local to this module. */
-static struct application      a_burst; /* prototype spall ray */
-
 /*
- * This routine dispatches the burst point ray tracing task burstRay().
- * RETURN CODES:       0 for fatal ray tracing error, 1 otherwise.
- *
- * bpt is burst point coordinates.
- */
-static int
-burstPoint(struct application *ap, fastf_t *normal, fastf_t *bpt)
-{
-    a_burst = *ap;
-    a_burst.a_miss = f_BurstMiss;
-    a_burst.a_hit = f_BurstHit;
-    a_burst.a_level++;
-    a_burst.a_user = 0; /* ray number */
-    a_burst.a_purpose = "spall ray";
-    assert(a_burst.a_overlap == ap->a_overlap);
-
-    /* If pitch or yaw is specified, cant the main penetrator
-       axis. */
-    if (cantwarhead) {
-       VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, cantdelta);
-       VUNITIZE(a_burst.a_ray.r_dir);
-    }
-    /* If a deflected cone is specified (the default) the spall cone
-       axis is half way between the main penetrator axis and exit
-       normal of the spalling component.
-    */
-    if (deflectcone) {
-       VADD2(a_burst.a_ray.r_dir, a_burst.a_ray.r_dir, normal);
-       VUNITIZE(a_burst.a_ray.r_dir);
-    }
-    VMOVE(a_burst.a_ray.r_pt, bpt);
-
-    comphi = 0.0; /* Initialize global for concurrent access. */
-
-    /* SERIAL case -- one CPU does all the work. */
-    return     burstRay();
-}
-
-/*
   This routine gets called when explicit burst points are being
   input.  Crank through all burst points.  Return code of 0
   would indicate a failure in the application routine given to
@@ -1280,7 +1626,7 @@
        prntBurstHdr(burstpoint, viewdir);
        if (! burstPoint(&ag, zaxis, burstpoint)) {
            /* fatal error in application routine */
-           brst_log("Fatal error: raytracing aborted.\n");
+           bu_log("Fatal error: raytracing aborted.\n");
            return      0;
        }
        if (! TSTBIT(firemode, FM_FILE)) {
@@ -1328,7 +1674,7 @@
        plotGrid(a.a_ray.r_pt);
        if (rt_shootray(&a) == -1 && fatalerror) {
            /* fatal error in application routine */
-           brst_log("Fatal error: raytracing aborted.\n");
+           bu_log("Fatal error: raytracing aborted.\n");
            return      0;
        }
        if (! TSTBIT(firemode, FM_FILE) && TSTBIT(firemode, FM_SHOT)) {
@@ -1400,34 +1746,34 @@
 
 #if DEBUG_SHOT
     if (TSTBIT(firemode, FM_BURST))
-       brst_log("gridInit: reading burst points.\n");
+       bu_log("gridInit: reading burst points.\n");
     else       {
        if (TSTBIT(firemode, FM_SHOT))
-           brst_log("gridInit: shooting discrete shots.\n");
+           bu_log("gridInit: shooting discrete shots.\n");
        else
-           brst_log("gridInit: shooting %s.\n",
+           bu_log("gridInit: shooting %s.\n",
                     TSTBIT(firemode, FM_PART) ?
                     "partial envelope" : "full envelope");
     }
     if (TSTBIT(firemode, FM_BURST) || TSTBIT(firemode, FM_SHOT)) {
-       brst_log("gridInit: reading %s coordinates from %s.\n",
+       bu_log("gridInit: reading %s coordinates from %s.\n",
                 TSTBIT(firemode, FM_3DIM) ? "3-d" : "2-d",
                 TSTBIT(firemode, FM_FILE) ? "file" : "command stream");
 
     } else
        if (TSTBIT(firemode, FM_FILE) || TSTBIT(firemode, FM_3DIM))
-           brst_log("BUG: insane combination of fire mode bits:0x%x\n",
+           bu_log("BUG: insane combination of fire mode bits:0x%x\n",
                     firemode);
     if (TSTBIT(firemode, FM_BURST) || shotburst)
-       nriplevels = 1;
+       s->nriplevels = 1;
     else
-       nriplevels = 0;
+       s->nriplevels = 0;
     if (!shotburst && groundburst) {
        (void) snprintf(scrbuf, LNBUFSZ,
                        "Ground bursting directive ignored: %s.\n",
                        "only relevant if bursting along shotline");
        warning(scrbuf);
-       brst_log(scrbuf);
+       bu_log(scrbuf);
     }
 #endif
     /* compute grid unit vectors */
@@ -1438,9 +1784,9 @@
        fastf_t sinpitch = sin(pitch);
        fastf_t xdeltavec[3], ydeltavec[3];
 #if DEBUG_SHOT
-       brst_log("gridInit: canting warhead\n");
+       bu_log("gridInit: canting warhead\n");
 #endif
-       cantwarhead = 1;
+       s->cantwarhead = 1;
        VSCALE(xdeltavec, gridhor, negsinyaw);
        VSCALE(ydeltavec, gridver, sinpitch);
        VADD2(cantdelta, xdeltavec, ydeltavec);
@@ -1570,9 +1916,9 @@
        gridyfin++;
     }
 #if DEBUG_SHOT
-    brst_log("gridInit: xorg, xfin, yorg, yfin=%d, %d, %d, %d\n",
+    bu_log("gridInit: xorg, xfin, yorg, yfin=%d, %d, %d, %d\n",
             gridxorg, gridxfin, gridyorg, gridyfin);
-    brst_log("gridInit: left, right, down, up=%g, %g, %g, %g\n",
+    bu_log("gridInit: left, right, down, up=%g, %g, %g, %g\n",
             gridlf, gridrt, griddn, gridup);
 #endif
 
@@ -1627,7 +1973,7 @@
        delta = 0.0;
        phiinc = 0.0;
        raysolidangle = 0.0;
-       brst_log("%d sampling rays\n", spallct);
+       bu_log("%d sampling rays\n", spallct);
        return;
     }
 
@@ -1652,12 +1998,14 @@
            spallct++;
     }
     raysolidangle = theta / spallct;
-    brst_log("Solid angle of sampling cone = %g\n", theta);
-    brst_log("Solid angle per sampling ray = %g\n", raysolidangle);
-    brst_log("%d sampling rays\n", spallct);
+    bu_log("Solid angle of sampling cone = %g\n", theta);
+    bu_log("Solid angle per sampling ray = %g\n", raysolidangle);
+    bu_log("%d sampling rays\n", spallct);
     return;
 }
 
+#endif
+
 /*
  * Local Variables:
  * mode: C

Added: brlcad/branches/bioh/src/burst2/paint.cpp
===================================================================
--- brlcad/branches/bioh/src/burst2/paint.cpp                           (rev 0)
+++ brlcad/branches/bioh/src/burst2/paint.cpp   2020-06-11 14:30:34 UTC (rev 
76107)
@@ -0,0 +1,181 @@
+/*                       P A I N T . C P P
+ * BRL-CAD
+ *
+ * Copyright (c) 2004-2020 United States Government as represented by
+ * the U.S. Army Research Laboratory.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * version 2.1 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this file; see the file named COPYING for more
+ * information.
+ *
+ */
+/** @file burst/paint.cpp
+ *
+ */
+
+#include "common.h"
+
+#include <assert.h>
+#include <stdio.h>
+
+#include "vmath.h"
+#include "raytrace.h"
+#include "fb.h"
+
+#include "./burst.h"
+
+static int roundToInt(fastf_t f)
+{
+    int a = (int)f;
+    return (f - a >= 0.5) ? a + 1 : a;
+}
+
+/* Offset frame buffer coordinates to center of cell from grid lines. */
+#define CenterCell(b)  (b += roundToInt((fastf_t) s->zoom / 2.0))
+
+/* Compare one RGB pixel to another. */
+#define SAMERGB(a, b)  ((a)[RED] == (b)[RED] &&\
+                        (a)[GRN] == (b)[GRN] &&\
+                        (a)[BLU] == (b)[BLU])
+
+#define MAXDEVWID      10000   /* maximum width of frame buffer */
+static unsigned char pixbuf[MAXDEVWID][3];
+static int gridxmargin;
+static int gridymargin;
+
+void
+gridToFb(struct burst_state *s, int gx, int gy, int *fxp, int *fyp)
+{
+    /* map grid offsets to frame buffer coordinates */
+    *fxp = (gx - s->gridxorg)*s->zoom + gridxmargin;
+    *fyp = (gy - s->gridyorg)*s->zoom + gridymargin;
+    return;
+}
+
+void
+paintGridFb(struct burst_state *s)
+{
+    int fx, fy;
+    int fxbeg, fybeg;
+    int fxfin, fyfin;
+    int fxorg, fyorg;
+    int fgridwid;
+    if (fb_clear(s->fbiop, s->pixbkgr) == -1)
+       return;
+    gridxmargin = (s->devwid - (s->gridwidth*s->zoom)) / 2.0;
+    gridymargin = (s->devhgt - (s->gridheight*s->zoom)) / 2.0;
+    gridToFb(s, s->gridxorg, s->gridyorg, &fxbeg, &fybeg);
+    gridToFb(s, s->gridxfin+1, s->gridyfin+1, &fxfin, &fyfin);
+    gridToFb(s, 0, 0, &fxorg, &fyorg);
+    CenterCell(fxorg); /* center of cell */
+    CenterCell(fyorg);
+    if (s->zoom == 1) {
+       fgridwid = s->gridwidth + 2;
+       fxfin++;
+    } else {
+       fgridwid = s->gridwidth * s->zoom + 1;
+    }
+
+    /* draw vertical lines */
+    for (fx = 1; fx < fgridwid; fx++)
+       COPYRGB(&pixbuf[fx][0], s->pixbkgr);
+    for (fx = fxbeg; fx <= fxfin; fx += s->zoom)
+       COPYRGB(&pixbuf[fx-fxbeg][0], &s->pixgrid[0]);
+    for (fy = fybeg; fy <= fyfin; fy++)
+       (void) fb_write(s->fbiop, fxbeg, fy, (unsigned char *)pixbuf, fgridwid);
+    for (fy = 0; fy < s->devwid; fy++)
+       (void) fb_write(s->fbiop, fxorg, fy, s->pixaxis, 1);
+
+    /* draw horizontal lines */
+    if (s->zoom > 1) {
+       for (fy = fybeg; fy <= fyfin; fy += s->zoom) {
+           (void) fb_write(s->fbiop, fxbeg, fy, s->pixgrid, fgridwid);
+       }
+    }
+    for (fx = 0; fx < s->devwid; fx++) {
+       COPYRGB(&pixbuf[fx][0], s->pixaxis);
+    }
+    (void) fb_write(s->fbiop, 0, fyorg, (unsigned char *)pixbuf, s->devwid);
+    return;
+}
+
+
+void
+paintCellFb(struct application *ap, unsigned char *pixpaint, unsigned char 
*pixexpendable)
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    int gx, gy;
+    int gyfin, gxfin;
+    int gxorg, gyorg;
+    int x, y;
+    int cnt;
+    gridToFb(s, ap->a_x, ap->a_y, &gx, &gy);
+    gxorg = gx+1;
+    gyorg = gy+1;
+    gxfin = s->zoom == 1 ? gx+s->zoom+1 : gx+s->zoom;
+    gyfin = s->zoom == 1 ? gy+s->zoom+1 : gy+s->zoom;
+    cnt = gxfin - gxorg;
+    for (y = gyorg; y < gyfin; y++) {
+       if (s->zoom != 1 && (y - gy) % s->zoom == 0) {
+           continue;
+       }
+       bu_semaphore_acquire(BU_SEM_GENERAL);
+       (void) fb_read(s->fbiop, gxorg, y, (unsigned char *)pixbuf, cnt);
+       bu_semaphore_release(BU_SEM_GENERAL);
+       for (x = gxorg; x < gxfin; x++) {
+           if (SAMERGB(&pixbuf[x-gxorg][0], pixexpendable)) {
+               COPYRGB(&pixbuf[x-gxorg][0], pixpaint);
+           }
+       }
+       bu_semaphore_acquire(BU_SEM_GENERAL);
+       (void) fb_write(s->fbiop, gxorg, y, (unsigned char *)pixbuf, cnt);
+       bu_semaphore_release(BU_SEM_GENERAL);
+    }
+    return;
+}
+
+
+void
+paintSpallFb(struct application *ap)
+{
+    struct burst_state *s = (struct burst_state *)ap->a_uptr;
+    unsigned char pixel[3];
+    int x, y;
+    int err;
+    fastf_t celldist;
+    pixel[RED] = ap->a_color[RED] * 255;
+    pixel[GRN] = ap->a_color[GRN] * 255;
+    pixel[BLU] = ap->a_color[BLU] * 255;
+    gridToFb(s, ap->a_x, ap->a_y, &x, &y);
+    CenterCell(x);     /* center of cell */
+    CenterCell(y);
+    celldist = ap->a_cumlen/s->cellsz * s->zoom;
+    x = roundToInt(x + VDOT(ap->a_ray.r_dir, s->gridhor) * celldist);
+    y = roundToInt(y + VDOT(ap->a_ray.r_dir, s->gridver) * celldist);
+    bu_semaphore_acquire(BU_SEM_GENERAL);
+    err = fb_write(s->fbiop, x, y, pixel, 1);
+    bu_semaphore_release(BU_SEM_GENERAL);
+    if (err == -1)
+       bu_log("Write failed to pixel <%d, %d> from cell <%d, %d>.\n", x, y, 
ap->a_x, ap->a_y);
+    return;
+}
+
+
+/*
+ * Local Variables:
+ * mode: C
+ * tab-width: 8
+ * indent-tabs-mode: t
+ * c-file-style: "stroustrup"
+ * End:
+ * ex: shiftwidth=4 tabstop=8
+ */


Property changes on: brlcad/branches/bioh/src/burst2/paint.cpp
___________________________________________________________________
Added: svn:eol-style
## -0,0 +1 ##
+native
\ No newline at end of property
Added: svn:mime-type
## -0,0 +1 ##
+text/plain
\ No newline at end of property
This was sent by the SourceForge.net collaborative development platform, the 
world's largest Open Source development site.



_______________________________________________
BRL-CAD Source Commits mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/brlcad-commits

Reply via email to