int
rt_gen_conic(struct xrays *rays, const struct xray *center_ray,
	     fastf_t theta, vect_t up_vector, int rays_per_radius)
{
    int count = 0;

    point_t start;
    vect_t orig_dir;

    fastf_t x, y;

    /* Setting radius to tan(theta) works because, as shown in the
     * following diagram, the ray that starts at the given point and
     * passes through orig_dir + (radius in any orthogonal direction)
     * has an angle of theta with the original ray; when the
     * resulting vector is normalized, the angle is preserved.
     */
    fastf_t radius = tan(theta);
    fastf_t rsq = radius * radius; /* radius-squared, for use in the loop */

    fastf_t gridsize = 2 * radius / (rays_per_radius - 1);

    vect_t a_dir, b_dir;

    register struct xrays *xrayp;

    VMOVE(start, center_ray->r_pt);
    VMOVE(orig_dir, center_ray->r_dir);

    /* Create vectors a_dir, b_dir that are orthogonal to orig_dir. */
    VMOVE(b_dir, up_vector);
    VUNITIZE(b_dir);

    VCROSS(a_dir, orig_dir, up_vector);
    VUNITIZE(a_dir);

    for (y = -radius; y <= radius; y += gridsize) {
	vect_t tmp;
	printf("y:%f\n", y);
	VSCALE(tmp, b_dir, y);
	printf("y_partofit: %f,%f,%f\n", V3ARGS(tmp));
	for (x = -radius; x <= radius; x += gridsize) {
	    if (((x*x)/rsq + (y*y)/rsq) <= 1) {
		BU_ALLOC(xrayp, struct xrays);
		VMOVE(xrayp->ray.r_pt, start);
		VJOIN2(xrayp->ray.r_dir, orig_dir, x, a_dir, y, b_dir);
		VUNITIZE(xrayp->ray.r_dir);
		xrayp->ray.index = count++;
		xrayp->ray.magic = RT_RAY_MAGIC;
		BU_LIST_APPEND(&rays->l, &xrayp->l);
	    }
	}
    }
    return count;
}
HIDDEN int
rt_pattern_rect_perspgrid(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir,
	       const vect_t a_vec, const vect_t b_vec,
	       const fastf_t a_theta, const fastf_t b_theta,
	       const fastf_t a_num, const fastf_t b_num)
{
    int count = 0;
    vect_t rdir;
    vect_t a_dir, b_dir;
    fastf_t x, y;
    fastf_t a_length = tan(a_theta);
    fastf_t b_length = tan(b_theta);
    fastf_t a_inc = 2 * a_length / (a_num - 1);
    fastf_t b_inc = 2 * b_length / (b_num - 1);

    VMOVE(a_dir, a_vec);
    VUNITIZE(a_dir);
    VMOVE(b_dir, b_vec);
    VUNITIZE(b_dir);

    /* Find out how much memory we'll need and get it */
    for (y = -b_length; y <= b_length + BN_TOL_DIST; y += b_inc) {
	for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) {
	    count++;
	}
    }
    *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, count + 1, "rays");

    /* Now that we have memory, reset count so it can
     * be used to index into the array */
    count = 0;

    /* This adds BN_TOL_DIST to the *_length variables in the
     * condition because in some cases, floating-point problems can
     * make extremely close numbers compare incorrectly. */
    for (y = -b_length; y <= b_length + BN_TOL_DIST; y += b_inc) {
	for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) {
	    VJOIN2(rdir, dir, x, a_dir, y, b_dir);
	    VUNITIZE(rdir);
	    (*rays)[6*count] = center_pt[0];
	    (*rays)[6*count+1] = center_pt[1];
	    (*rays)[6*count+2] = center_pt[2];
	    (*rays)[6*count+3] = rdir[0];
	    (*rays)[6*count+4] = rdir[1];
	    (*rays)[6*count+5] = rdir[2];
	    count++;

	}
    }
    *(ray_cnt) = count;
    return count;
}
void
ellipse_point_at_radian(
	point_t result,
	const vect_t center,
	const vect_t axis_a,
	const vect_t axis_b,
	fastf_t radian)
{
    fastf_t cos_rad, sin_rad;

    cos_rad = cos(radian);
    sin_rad = sin(radian);

    VJOIN2(result, center, cos_rad, axis_a, sin_rad, axis_b);
}
HIDDEN int
rt_pattern_rect_orthogrid(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir,
		const vect_t a_vec, const vect_t b_vec, const fastf_t da, const fastf_t db)
{
    int count = 0;
    point_t pt;
    vect_t a_dir;
    vect_t b_dir;
    fastf_t x, y;
    fastf_t a_length = MAGNITUDE(a_vec);
    fastf_t b_length = MAGNITUDE(b_vec);

    if (!rays || !ray_cnt) return -1;

    VMOVE(a_dir, a_vec);
    VUNITIZE(a_dir);

    VMOVE(b_dir, b_vec);
    VUNITIZE(b_dir);

    /* Find out how much memory we'll need and get it */
    for (y = -b_length; y <= b_length; y += db) {
	for (x = -a_length; x <= a_length; x += da) {
	    count++;
	}
    }
    *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, count + 1, "rays");

    /* Now that we have memory, reset count so it can
     * be used to index into the array */
    count = 0;

    /* Build the rays */
    for (y = -b_length; y <= b_length; y += db) {
	for (x = -a_length; x <= a_length; x += da) {
	    VJOIN2(pt, center_pt, x, a_dir, y, b_dir);
	    (*rays)[6*count] = pt[0];
	    (*rays)[6*count+1] = pt[1];
	    (*rays)[6*count+2] = pt[2];
	    (*rays)[6*count+3] = dir[0];
	    (*rays)[6*count+4] = dir[1];
	    (*rays)[6*count+5] = dir[2];
	    count++;
	}
    }
    *(ray_cnt) = count;
    return count;
}
HIDDEN int
rt_pattern_circ_spiral(fastf_t **rays, size_t *ray_cnt, const point_t center_pt, const vect_t dir,
       	const double radius, const int rays_per_ring, const int nring, const double delta)
{
    int ring;
    double fraction = 1.0;
    double theta;
    double radial_scale;
    vect_t avec, bvec;
    int ray_index = 0;

    bn_vec_ortho(avec, dir);
    VCROSS(bvec, dir, avec);
    VUNITIZE(bvec);

    if (!rays || !ray_cnt) return -1;

    *(rays) = (fastf_t *)bu_calloc(sizeof(fastf_t) * 6, (rays_per_ring * nring) + 1, "rays");

    for (ring = 0; ring < nring; ring++) {
	register int i;

	theta = 0;
	fraction = ((double)(ring+1)) / nring;
	theta = delta * fraction;       /* spiral skew */
	radial_scale = radius * fraction;
	for (i=0; i < rays_per_ring; i++) {
	    register double ct, st;
	    point_t pt;
	    /* pt = V + cos(theta) * A + sin(theta) * B */
	    ct = cos(theta) * radial_scale;
	    st = sin(theta) * radial_scale;
	    VJOIN2(pt, center_pt, ct, avec, st, bvec);
	    (*rays)[6*ray_index] = pt[0];
	    (*rays)[6*ray_index+1] = pt[1];
	    (*rays)[6*ray_index+2] = pt[2];
	    (*rays)[6*ray_index+3] = dir[0];
	    (*rays)[6*ray_index+4] = dir[1];
	    (*rays)[6*ray_index+5] = dir[2];
	    theta += delta;
	    ray_index++;
	}
    }
    *(ray_cnt) = ray_index;
    return ray_index;
}
int
rt_gen_frustum(struct xrays *rays, const struct xray *center_ray,
	       const vect_t a_vec, const vect_t b_vec,
	       const fastf_t a_theta, const fastf_t b_theta,
	       const fastf_t a_num, const fastf_t UNUSED(b_num))
{
    int count = 0;

    point_t start;
    vect_t orig_dir;

    fastf_t x, y;

    fastf_t a_length = tan(a_theta);
    fastf_t b_length = tan(b_theta);
    fastf_t a_inc = 2 * a_length / (a_num - 1);

    vect_t a_dir, b_dir;

    register struct xrays *xrayp;

    VMOVE(start, center_ray->r_pt);
    VMOVE(orig_dir, center_ray->r_dir);

    VMOVE(a_dir, a_vec);
    VUNITIZE(a_dir);
    VMOVE(b_dir, b_vec);
    VUNITIZE(b_dir);

    /* This adds BN_TOL_DIST to the *_length variables in the
     * condition because in some cases, floating-point problems can
     * make extremely close numbers compare incorrectly. */
    for (y = -b_length; y <= b_length + BN_TOL_DIST;) {
	for (x = -a_length; x <= a_length + BN_TOL_DIST; x += a_inc) {
	    BU_ALLOC(xrayp, struct xrays);
	    VMOVE(xrayp->ray.r_pt, start);
	    VJOIN2(xrayp->ray.r_dir, orig_dir, x, a_dir, y, b_dir);
	    VUNITIZE(xrayp->ray.r_dir);
	    xrayp->ray.index = count++;
	    xrayp->ray.magic = RT_RAY_MAGIC;
	    BU_LIST_APPEND(&rays->l, &xrayp->l);
	}
    }
    return count;
}
int
rt_gen_elliptical_grid(struct xrays *rays, const struct xray *center_ray, const fastf_t *avec, const fastf_t *bvec, fastf_t gridsize)
{
    register struct xrays *xrayp;
    int count = 0;
    point_t C;
    vect_t dir;
    vect_t a_dir;
    vect_t b_dir;

    fastf_t a = MAGNITUDE(avec);
    fastf_t b = MAGNITUDE(bvec);
    fastf_t x, y;

    int acpr = a / gridsize;
    int bcpr = b / gridsize;

    VMOVE(a_dir, avec);
    VUNITIZE(a_dir);

    VMOVE(b_dir, bvec);
    VUNITIZE(b_dir);

    VMOVE(C, center_ray->r_pt);
    VMOVE(dir, center_ray->r_dir);
    /* make sure avec perpendicular to bvec perpendicular to ray direction */
    BU_ASSERT(NEAR_ZERO(VDOT(avec, bvec), VUNITIZE_TOL));
    BU_ASSERT(NEAR_ZERO(VDOT(avec, dir), VUNITIZE_TOL));

    for (y=gridsize * (-bcpr); y <= b; y=y+gridsize) {
	for (x= gridsize * (-acpr); x <= a; x=x+gridsize) {
	    if (((x*x)/(a*a) + (y*y)/(b*b)) < 1) {
		BU_ALLOC(xrayp, struct xrays);
		VJOIN2(xrayp->ray.r_pt, C, x, a_dir, y, b_dir);
		VMOVE(xrayp->ray.r_dir, dir);
		xrayp->ray.index = count++;
		xrayp->ray.magic = RT_RAY_MAGIC;
		BU_LIST_APPEND(&rays->l, &xrayp->l);
	    }
	}
    }
    return count;
}
Ejemplo n.º 8
0
/**
 * Compute the origin for this ray, based upon the number of samples
 * per pixel and the number of the current sample.  For certain
 * ray-counts, it is highly advantageous to subdivide the pixel and
 * fire each ray in a specific sub-section of the pixel.
 */
static void
jitter_start_pt(vect_t point, struct application *a, int samplenum, int pat_num)
{
    fastf_t dx, dy;

    if (pat_num >= 0) {
	dx = a->a_x + pt_pats[pat_num].coords[samplenum*2] +
	    (bn_rand_half(a->a_resource->re_randptr) *
	     pt_pats[pat_num].rand_scale[X]);

	dy = a->a_y + pt_pats[pat_num].coords[samplenum*2 + 1] +
	    (bn_rand_half(a->a_resource->re_randptr) *
	     pt_pats[pat_num].rand_scale[Y]);
    } else {
	dx = a->a_x + bn_rand_half(a->a_resource->re_randptr);
	dy = a->a_y + bn_rand_half(a->a_resource->re_randptr);
    }
    VJOIN2(point, viewbase_model, dx, dx_model, dy, dy_model);
}
int rt_gen_rect(struct xrays *rays, const struct xray *center_ray,
		const vect_t a_vec, const vect_t b_vec,
		const fastf_t da, const fastf_t db)
{
    int count = 0;

    point_t orig_start;
    vect_t dir;

    fastf_t x, y;

    fastf_t a_length = MAGNITUDE(a_vec);
    fastf_t b_length = MAGNITUDE(b_vec);

    vect_t a_dir;
    vect_t b_dir;

    register struct xrays *xrayp;

    VMOVE(orig_start, center_ray->r_pt);
    VMOVE(dir, center_ray->r_dir);

    VMOVE(a_dir, a_vec);
    VUNITIZE(a_dir);

    VMOVE(b_dir, b_vec);
    VUNITIZE(b_dir);

    for (y = -b_length; y <= b_length; y += db) {
	for (x = -a_length; x <= a_length; x += da) {
	    BU_ALLOC(xrayp, struct xrays);
	    VJOIN2(xrayp->ray.r_pt, orig_start, x, a_dir, y, b_dir);
	    VMOVE(xrayp->ray.r_dir, dir);
	    xrayp->ray.index = count++;
	    xrayp->ray.magic = RT_RAY_MAGIC;
	    BU_LIST_APPEND(&rays->l, &xrayp->l);
	}
    }
    return count;
}
int
rt_raybundle_maker(struct xray *rp, double radius, const fastf_t *avec, const fastf_t *bvec, int rays_per_ring, int nring)
{
    register struct xray *rayp = rp+1;
    int ring;
    double fraction = 1.0;
    double theta;
    double delta;
    double radial_scale;
    int count = 0;

    rp[0].index = count++;
    rp[0].magic =RT_RAY_MAGIC;

    for (ring=0; ring < nring; ring++) {
	register int i;

	theta = 0;
	delta = M_2PI / rays_per_ring;
	fraction = ((double)(ring+1)) / nring;
	theta = delta * fraction;	/* spiral skew */
	radial_scale = radius * fraction;
	for (i=0; i < rays_per_ring; i++) {
	    register double ct, st;
	    /* pt = V + cos(theta) * A + sin(theta) * B */
	    ct = cos(theta) * radial_scale;
	    st = sin(theta) * radial_scale;
	    VJOIN2(rayp->r_pt, rp[0].r_pt, ct, avec, st, bvec);
	    VMOVE(rayp->r_dir, rp[0].r_dir);
	    rayp->index = count++;
	    rayp->magic = RT_RAY_MAGIC;
	    theta += delta;
	    rayp++;
	}
    }
    return count;
}
Ejemplo n.º 11
0
/*
 * Default keypoint in model space is established in "pt". Returns
 * GED_ERROR if unable to determine a keypoint, otherwise returns
 * GED_OK.
 */
int
_ged_get_solid_keypoint(struct ged *const gedp,
			fastf_t *const pt,
			const struct rt_db_internal *const ip,
			const fastf_t *const mat)
{
    point_t mpt;

    RT_CK_DB_INTERNAL(ip);

    switch (ip->idb_type) {
	case ID_CLINE:
	    {
		struct rt_cline_internal *cli =
		    (struct rt_cline_internal *)ip->idb_ptr;

		RT_CLINE_CK_MAGIC(cli);

		VMOVE(mpt, cli->v);
		break;
	    }
	case ID_PARTICLE:
	    {
		struct rt_part_internal *part =
		    (struct rt_part_internal *)ip->idb_ptr;

		RT_PART_CK_MAGIC(part);

		VMOVE(mpt, part->part_V);
		break;
	    }
	case ID_PIPE:
	    {
		struct rt_pipe_internal *pipeip;
		struct wdb_pipept *pipe_seg;

		pipeip = (struct rt_pipe_internal *)ip->idb_ptr;

		RT_PIPE_CK_MAGIC(pipeip);

		pipe_seg = BU_LIST_FIRST(wdb_pipept, &pipeip->pipe_segs_head);
		VMOVE(mpt, pipe_seg->pp_coord);
		break;
	    }
	case ID_METABALL:
	    {
		struct rt_metaball_internal *metaball =
		    (struct rt_metaball_internal *)ip->idb_ptr;
		struct wdb_metaballpt *metaballpt;

		RT_METABALL_CK_MAGIC(metaball);

		VSETALL(mpt, 0.0);
		metaballpt = BU_LIST_FIRST(wdb_metaballpt,
					   &metaball->metaball_ctrl_head);
		VMOVE(mpt, metaballpt->coord);
		break;
	    }
	case ID_ARBN:
	    {
		struct rt_arbn_internal *arbn =
		    (struct rt_arbn_internal *)ip->idb_ptr;
		size_t i, j, k;
		int good_vert = 0;

		RT_ARBN_CK_MAGIC(arbn);
		for (i = 0; i < arbn->neqn; i++) {
		    for (j = i + 1; j < arbn->neqn; j++) {
			for (k = j + 1; k < arbn->neqn; k++) {
			    if (!bn_mkpoint_3planes(mpt, arbn->eqn[i],
						    arbn->eqn[j],
						    arbn->eqn[k])) {
				size_t l;

				good_vert = 1;
				for (l = 0; l < arbn->neqn; l++) {
				    if (l == i || l == j || l == k)
					continue;

				    if (DIST_PT_PLANE(mpt,
					arbn->eqn[l]) >
					gedp->ged_wdbp->wdb_tol.dist) {
					good_vert = 0;
					break;
				    }
				}

				if (good_vert)
				    break;
			    }
			}
			if (good_vert)
			    break;
		    }
		    if (good_vert)
			break;
		}

		break;
	    }
	case ID_EBM:
	    {
		struct rt_ebm_internal *ebm =
		    (struct rt_ebm_internal *)ip->idb_ptr;
		point_t pnt;

		RT_EBM_CK_MAGIC(ebm);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, ebm->mat, pnt);
		break;
	    }
	case ID_BOT:
	    {
		struct rt_bot_internal *bot =
		    (struct rt_bot_internal *)ip->idb_ptr;

		    VMOVE(mpt, bot->vertices);
		break;
	    }
	case ID_DSP:
	    {
		struct rt_dsp_internal *dsp =
		    (struct rt_dsp_internal *)ip->idb_ptr;
		point_t pnt;

		RT_DSP_CK_MAGIC(dsp);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, dsp->dsp_stom, pnt);
		break;
	    }
	case ID_HF:
	    {
		struct rt_hf_internal *hf =
		    (struct rt_hf_internal *)ip->idb_ptr;

		RT_HF_CK_MAGIC(hf);

		VMOVE(mpt, hf->v);
		break;
	    }
	case ID_VOL:
	    {
		struct rt_vol_internal *vol =
		    (struct rt_vol_internal *)ip->idb_ptr;
		point_t pnt;

		RT_VOL_CK_MAGIC(vol);

		VSETALL(pnt, 0.0);
		MAT4X3PNT(mpt, vol->mat, pnt);
		break;
	    }
	case ID_HALF:
	    {
		struct rt_half_internal *haf =
		    (struct rt_half_internal *)ip->idb_ptr;
		RT_HALF_CK_MAGIC(haf);

		VSCALE(mpt, haf->eqn, haf->eqn[H]);
		break;
	    }
	case ID_ARB8:
	    {
		struct rt_arb_internal *arb =
		    (struct rt_arb_internal *)ip->idb_ptr;
		RT_ARB_CK_MAGIC(arb);

		VMOVE(mpt, arb->pt[0]);
		break;
	    }
	case ID_ELL:
	case ID_SPH:
	    {
		struct rt_ell_internal *ell =
		    (struct rt_ell_internal *)ip->idb_ptr;
		RT_ELL_CK_MAGIC(ell);

		VMOVE(mpt, ell->v);
		break;
	    }
	case ID_SUPERELL:
	    {
		struct rt_superell_internal *superell =
		    (struct rt_superell_internal *)ip->idb_ptr;
		RT_SUPERELL_CK_MAGIC(superell);

		VMOVE(mpt, superell->v);
		break;
	    }
	case ID_TOR:
	    {
		struct rt_tor_internal *tor =
		    (struct rt_tor_internal *)ip->idb_ptr;
		RT_TOR_CK_MAGIC(tor);

		VMOVE(mpt, tor->v);
		break;
	    }
	case ID_TGC:
	case ID_REC:
	    {
		struct rt_tgc_internal *tgc =
		    (struct rt_tgc_internal *)ip->idb_ptr;
		RT_TGC_CK_MAGIC(tgc);

		VMOVE(mpt, tgc->v);
		break;
	    }
	case ID_GRIP:
	    {
		struct rt_grip_internal *gip =
		    (struct rt_grip_internal *)ip->idb_ptr;
		RT_GRIP_CK_MAGIC(gip);
		VMOVE(mpt, gip->center);
		break;
	    }
	case ID_ARS:
	    {
		struct rt_ars_internal *ars =
		    (struct rt_ars_internal *)ip->idb_ptr;
		RT_ARS_CK_MAGIC(ars);

		VMOVE(mpt, &ars->curves[0][0]);
		break;
	    }
	case ID_RPC:
	    {
		struct rt_rpc_internal *rpc =
		    (struct rt_rpc_internal *)ip->idb_ptr;
		RT_RPC_CK_MAGIC(rpc);

		VMOVE(mpt, rpc->rpc_V);
		break;
	    }
	case ID_RHC:
	    {
		struct rt_rhc_internal *rhc =
		    (struct rt_rhc_internal *)ip->idb_ptr;
		RT_RHC_CK_MAGIC(rhc);

		VMOVE(mpt, rhc->rhc_V);
		break;
	    }
	case ID_EPA:
	    {
		struct rt_epa_internal *epa =
		    (struct rt_epa_internal *)ip->idb_ptr;
		RT_EPA_CK_MAGIC(epa);

		VMOVE(mpt, epa->epa_V);
		break;
	    }
	case ID_EHY:
	    {
		struct rt_ehy_internal *ehy =
		    (struct rt_ehy_internal *)ip->idb_ptr;
		RT_EHY_CK_MAGIC(ehy);

		VMOVE(mpt, ehy->ehy_V);
		break;
	    }
	case ID_HYP:
	    {
		struct rt_hyp_internal *hyp =
		    (struct rt_hyp_internal *)ip->idb_ptr;
		RT_HYP_CK_MAGIC(hyp);

		VMOVE(mpt, hyp->hyp_Vi);
		break;
	    }
	case ID_ETO:
	    {
		struct rt_eto_internal *eto =
		    (struct rt_eto_internal *)ip->idb_ptr;
		RT_ETO_CK_MAGIC(eto);

		VMOVE(mpt, eto->eto_V);
		break;
	    }
	case ID_POLY:
	    {
		struct rt_pg_face_internal *_poly;
		struct rt_pg_internal *pg =
		    (struct rt_pg_internal *)ip->idb_ptr;
		RT_PG_CK_MAGIC(pg);

		_poly = pg->poly;
		VMOVE(mpt, _poly->verts);
		break;
	    }
	case ID_SKETCH:
	    {
		struct rt_sketch_internal *skt =
		    (struct rt_sketch_internal *)ip->idb_ptr;
		RT_SKETCH_CK_MAGIC(skt);

		VMOVE(mpt, skt->V);
		break;
	    }
	case ID_EXTRUDE:
	    {
		struct rt_extrude_internal *extr =
		    (struct rt_extrude_internal *)ip->idb_ptr;
		RT_EXTRUDE_CK_MAGIC(extr);

		if (extr->skt && extr->skt->verts) {
		    VJOIN2(mpt, extr->V, extr->skt->verts[0][0], extr->u_vec,
			   extr->skt->verts[0][1], extr->v_vec);
		} else {
		    VMOVE(mpt, extr->V);
		}
		break;
	    }
	case ID_NMG:
	    {
		struct vertex *v;
		struct vertexuse *vu;
		struct edgeuse *eu;
		struct loopuse *lu;
		struct faceuse *fu;
		struct shell *s;
		struct nmgregion *r;
		struct model *m =
		    (struct model *) ip->idb_ptr;
		NMG_CK_MODEL(m);

		/* set default first */
		VSETALL(mpt, 0.0);

		if (BU_LIST_IS_EMPTY(&m->r_hd))
		    break;

		r = BU_LIST_FIRST(nmgregion, &m->r_hd);
		if (!r)
		    break;
		NMG_CK_REGION(r);

		if (BU_LIST_IS_EMPTY(&r->s_hd))
		    break;

		s = BU_LIST_FIRST(shell, &r->s_hd);
		if (!s)
		    break;
		NMG_CK_SHELL(s);

		if (BU_LIST_IS_EMPTY(&s->fu_hd))
		    fu = (struct faceuse *)NULL;
		else
		    fu = BU_LIST_FIRST(faceuse, &s->fu_hd);
		if (fu) {
		    NMG_CK_FACEUSE(fu);
		    lu = BU_LIST_FIRST(loopuse, &fu->lu_hd);
		    NMG_CK_LOOPUSE(lu);
		    if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
			eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
			NMG_CK_EDGEUSE(eu);
			NMG_CK_VERTEXUSE(eu->vu_p);
			v = eu->vu_p->v_p;
		    } else {
			vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
			NMG_CK_VERTEXUSE(vu);
			v = vu->v_p;
		    }
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		if (BU_LIST_IS_EMPTY(&s->lu_hd))
		    lu = (struct loopuse *)NULL;
		else
		    lu = BU_LIST_FIRST(loopuse, &s->lu_hd);
		if (lu) {
		    NMG_CK_LOOPUSE(lu);
		    if (BU_LIST_FIRST_MAGIC(&lu->down_hd) == NMG_EDGEUSE_MAGIC) {
			eu = BU_LIST_FIRST(edgeuse, &lu->down_hd);
			NMG_CK_EDGEUSE(eu);
			NMG_CK_VERTEXUSE(eu->vu_p);
			v = eu->vu_p->v_p;
		    } else {
			vu = BU_LIST_FIRST(vertexuse, &lu->down_hd);
			NMG_CK_VERTEXUSE(vu);
			v = vu->v_p;
		    }
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		if (BU_LIST_IS_EMPTY(&s->eu_hd))
		    eu = (struct edgeuse *)NULL;
		else
		    eu = BU_LIST_FIRST(edgeuse, &s->eu_hd);
		if (eu) {
		    NMG_CK_EDGEUSE(eu);
		    NMG_CK_VERTEXUSE(eu->vu_p);
		    v = eu->vu_p->v_p;
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
		vu = s->vu_p;
		if (vu) {
		    NMG_CK_VERTEXUSE(vu);
		    v = vu->v_p;
		    NMG_CK_VERTEX(v);
		    if (!v->vg_p)
			break;
		    VMOVE(mpt, v->vg_p->coord);
		    break;
		}
	    }
	default:
	    VSETALL(mpt, 0.0);
	    bu_vls_printf(gedp->ged_result_str,
			  "get_solid_keypoint: unrecognized solid type");
	    return GED_ERROR;
    }
    MAT4X3PNT(pt, mat, mpt);
    return GED_OK;
}
Ejemplo n.º 12
0
/*
 *			R A Y H I T
 *
 *  Rayhit() is called by rt_shootray() when the ray hits one or more objects.
 *  A per-shotline header record is written, followed by information about
 *  each object hit.
 *
 *  Note that the GIFT-3 format uses a different convention for the "zero"
 *  distance along the ray.  RT has zero at the ray origin (emanation plain),
 *  while GIFT has zero at the screen plain translated so that it contains
 *  the model origin.  This difference is compensated for by adding the
 *  'dcorrection' distance correction factor.
 *
 *  Also note that the GIFT-3 format requires information about the start
 *  point of the ray in two formats.  First, the h, v coordinates of the
 *  grid cell CENTERS (in screen space coordinates) are needed.
 *  Second, the ACTUAL h, v coordinates fired from are needed.
 *
 *  An optional rtg3.pl UnixPlot file is written, permitting a
 *  color vector display of ray-model intersections.
 */
int
rayhit(struct application *ap, register struct partition *PartHeadp, struct seg *segp)
{
    register struct partition *pp = PartHeadp->pt_forw;
    int 			comp_count;	/* component count */
    fastf_t			dfirst, dlast;	/* ray distances */
    static fastf_t		dcorrection = 0; /* RT to GIFT dist corr */
    int			card_count;	/* # comp. on this card */
    const char		*fmt;		/* printf() format string */
    struct bu_vls		str;
    char			buf[128];	/* temp. sprintf() buffer */
    point_t			hv;		/* GIFT h, v coords, in inches */
    point_t			hvcen;
    int			prev_id=-1;
    point_t			first_hit;
    int			first;

    if ( pp == PartHeadp )
	return(0);		/* nothing was actually hit?? */

    if ( ap->a_rt_i->rti_save_overlaps )
	rt_rebuild_overlaps( PartHeadp, ap, 1 );

    part_compact(ap, PartHeadp, TOL);

    /* count components in partitions */
    comp_count = 0;
    for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw )  {
	if ( pp->pt_regionp->reg_regionid > 0 ) {
	    prev_id = pp->pt_regionp->reg_regionid;
	    comp_count++;
	} else if ( prev_id <= 0 ) {
	    /* normally air would be output along with a solid partition, but this will require a '111' partition */
	    prev_id = pp->pt_regionp->reg_regionid;
	    comp_count++;
	} else
	    prev_id = pp->pt_regionp->reg_regionid;
    }
    pp = PartHeadp->pt_back;
    if ( pp!=PartHeadp && pp->pt_regionp->reg_regionid <= 0 )
	comp_count++;  /* a trailing '111' ident */
    if ( comp_count == 0 )
	return( 0 );

    /* Set up variable length string, to buffer this shotline in.
     * Note that there is one component per card, and that each card
     * (line) is 80 characters long.  Hence the parameters given to
     * rt-vls-extend().
     */

    bu_vls_init( &str );
    bu_vls_extend( &str, 80 * (comp_count+1) );

    /*
     *  Find the H, V coordinates of the grid cell center.
     *  RT uses the lower left corner of each cell.
     */
    {
	point_t		center;
	fastf_t		dx;
	fastf_t		dy;

	dx = ap->a_x + 0.5;
	dy = ap->a_y + 0.5;
	VJOIN2( center, viewbase_model, dx, dx_model, dy, dy_model );
	MAT4X3PNT( hvcen, model2hv, center );
    }

    /*
     *  Find exact h, v coordinates of actual ray start by
     *  projecting start point into GIFT h, v coordinates.
     */
    MAT4X3PNT( hv, model2hv, ap->a_ray.r_pt );

    /*
     *  In RT, rays are launched from the plane of the screen,
     *  and ray distances are relative to the start point.
     *  In GIFT-3 output files, ray distances are relative to
     *  the (H, V) plane translated so that it contains the origin.
     *  A distance correction is required to convert between the two.
     *  Since this really should be computed only once, not every time,
     *  the trip_count flag was added.
     */
    {

	static int  trip_count;
	vect_t	tmp;
	vect_t	viewZdir;

	if ( trip_count == 0) {

	    VSET( tmp, 0, 0, -1 );		/* viewing direction */
	    MAT4X3VEC( viewZdir, view2model, tmp );
	    VUNITIZE( viewZdir );
	    /* dcorrection will typically be negative */
	    dcorrection = VDOT( ap->a_ray.r_pt, viewZdir );
	    trip_count = 1;
	}
    }

    /* This code is for diagnostics.
     * bu_log("dcorrection=%g\n", dcorrection);
     */

    /* dfirst and dlast have been made negative to account for GIFT looking
     * in the opposite direction of RT.
     */

    dfirst = -(PartHeadp->pt_forw->pt_inhit->hit_dist + dcorrection);
    dlast = -(PartHeadp->pt_back->pt_outhit->hit_dist + dcorrection);
#if 0
    /* This code is to note any occurances of negative distances. */
    if ( PartHeadp->pt_forw->pt_inhit->hit_dist < 0)  {
	bu_log("ERROR: dfirst=%g at partition x%x\n", dfirst, PartHeadp->pt_forw );
	bu_log("\tdcorrection = %f\n", dcorrection );
	bu_log("\tray start point is ( %f %f %f ) in direction ( %f %f %f )\n", V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ) );
	VJOIN1( PartHeadp->pt_forw->pt_inhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_inhit->hit_dist, ap->a_ray.r_dir );
	VJOIN1( PartHeadp->pt_back->pt_outhit->hit_point, ap->a_ray.r_pt, PartHeadp->pt_forw->pt_outhit->hit_dist, ap->a_ray.r_dir );
	rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:");
    }
    /* End of bug trap. */
#endif
    /*
     *  Output the ray header.  The GIFT statements that
     *  would have generated this are:
     *  410	write(1, 411) hcen, vcen, h, v, ncomp, dfirst, dlast, a, e
     *  411	format(2f7.1, 2f9.3, i3, 2f8.2,' A', f6.1,' E', f6.1)
     */

#define	SHOT_FMT	"%7.1f%7.1f%9.3f%9.3f%3d%8.2f%8.2f A%6.1f E%6.1f"

    if ( rt_perspective > 0 )  {
	bn_ae_vec( &azimuth, &elevation, ap->a_ray.r_dir );
    }

    bu_vls_printf( &str, SHOT_FMT,
		   hvcen[0], hvcen[1],
		   hv[0], hv[1],
		   comp_count,
		   dfirst * MM2IN, dlast * MM2IN,
		   azimuth, elevation );

    /*
     *  As an aid to debugging, take advantage of the fact that
     *  there are more than 80 columns on UNIX "cards", and
     *  add debugging information to the end of the line to
     *  allow this shotline to be reproduced offline.
     *   -b gives the shotline x, y coordinates when re-running RTG3,
     *   -p and -d are used with RTSHOT
     *  The easy way to activate this is with the harmless -!1 option
     *  when running RTG3.
     */
    if ( R_DEBUG || bu_debug || RT_G_DEBUG )  {
	bu_vls_printf( &str, "   -b%d,%d -p %26.20e %26.20e %26.20e -d %26.20e %26.20e %26.20e\n",
		       ap->a_x, ap->a_y,
		       V3ARGS(ap->a_ray.r_pt),
		       V3ARGS(ap->a_ray.r_dir) );
    } else {
	bu_vls_putc( &str, '\n' );
    }

    /* loop here to deal with individual components */
    card_count = 0;
    prev_id = -1;
    first = 1;
    for ( pp=PartHeadp->pt_forw; pp!=PartHeadp; pp=pp->pt_forw )  {
	/*
	 *  The GIFT statements that would have produced
	 *  this output are:
	 *	do 632 i=icomp, iend
	 *	if (clos(icomp).gt.999.99.or.slos(i).gt.999.9) goto 635
	 * 632	continue
	 * 	write(1, 633)(item(i), clos(i), cangi(i), cango(i),
	 * &			kspac(i), slos(i), i=icomp, iend)
	 * 633	format(1x, 3(i4, f6.2, 2f5.1, i1, f5.1))
	 *	goto 670
	 * 635	write(1, 636)(item(i), clos(i), cangi(i), cango(i),
	 * &			kspac(i), slos(i), i=icomp, iend)
	 * 636	format(1x, 3(i4, f6.1, 2f5.1, i1, f5.0))
	 */
	fastf_t	comp_thickness;	/* component line of sight thickness */
	fastf_t	in_obliq;	/* in obliquity angle */
	fastf_t	out_obliq;	/* out obliquity angle */
	int	region_id;	/* solid region's id */
	int	air_id;		/* air id */
	fastf_t	dot_prod;	/* dot product of normal and ray dir */
	fastf_t	air_thickness;	/* air line of sight thickness */
	vect_t	normal;		/* surface normal */
	register struct partition	*nextpp = pp->pt_forw;

	region_id = pp->pt_regionp->reg_regionid;

	if ( region_id <= 0 && prev_id > 0 )
	{
	    /* air region output with previous partition */
	    prev_id = region_id;
	    continue;
	}
	comp_thickness = pp->pt_outhit->hit_dist -
	    pp->pt_inhit->hit_dist;

	/* The below code is meant to catch components with zero or
	 * negative thicknesses.  This is not supposed to be possible,
	 * but the condition has been seen.
	 */
#if 0
	if ( comp_thickness <= 0 )  {
	    VJOIN1( pp->pt_inhit->hit_point, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir );
	    VJOIN1( pp->pt_outhit->hit_point, ap->a_ray.r_pt, pp->pt_outhit->hit_dist, ap->a_ray.r_dir );
	    bu_log("ERROR: comp_thickness=%g for region id = %d at h=%g, v=%g (x=%d, y=%d), partition at x%x\n",
		   comp_thickness, region_id, hv[0], hv[1], ap->a_x, ap->a_y, pp );
	    rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:");
	    bu_log("Send this output to the BRL-CAD Developers ([email protected])\n");
	    if ( ! (RT_G_DEBUG & DEBUG_ARB8)) {
		rt_g.debug |= DEBUG_ARB8;
		rt_shootray(ap);
		rt_g.debug &= ~DEBUG_ARB8;
	    }
	}
#endif

	if ( nextpp == PartHeadp )  {
	    if ( region_id <= 0 ) {
		/* last partition is air, need a 111 'phantom armor' before AND after */
		bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before and after air region %s\n",
			pp->pt_regionp->reg_name );
		region_id = 111;
		air_id = pp->pt_regionp->reg_aircode;
		air_thickness = comp_thickness;
		comp_thickness = 0.0;
	    } else {
		/* Last partition, no air follows, use code 9 */
		air_id = 9;
		air_thickness = 0.0;
	    }
	} else if ( region_id <= 0 ) {
	    /* air region, need a 111 'phantom armor' */
	    bu_log( "WARNING: adding 'phantom armor' (id=111) with zero thickness before air region %s\n",
		    pp->pt_regionp->reg_name );
	    prev_id = region_id;
	    region_id = 111;
	    air_id = pp->pt_regionp->reg_aircode;
	    air_thickness = comp_thickness;
	    comp_thickness = 0.0;
	} else if ( nextpp->pt_regionp->reg_regionid <= 0 &&
		    nextpp->pt_regionp->reg_aircode != 0 )  {
	    /* Next partition is air region */
	    air_id = nextpp->pt_regionp->reg_aircode;
	    air_thickness = nextpp->pt_outhit->hit_dist -
		nextpp->pt_inhit->hit_dist;
	    prev_id = air_id;
	} else {
	    /* 2 solid regions, maybe with gap */
	    air_id = 0;
	    air_thickness = nextpp->pt_inhit->hit_dist -
		pp->pt_outhit->hit_dist;
	    if ( air_thickness < 0.0 )
		air_thickness = 0.0;
	    if ( !NEAR_ZERO( air_thickness, 0.1 ) )  {
		air_id = 1;	/* air gap */
		if ( R_DEBUG & RDEBUG_HITS )
		    bu_log("air gap added\n");
	    } else {
		air_thickness = 0.0;
	    }
	    prev_id = region_id;
	}

	/*
	 *  Compute the obliquity angles in degrees, ie,
	 *  the "declension" angle down off the normal vector.
	 *  RT normals always point outwards;
	 *  the "inhit" normal points opposite the ray direction,
	 *  the "outhit" normal points along the ray direction.
	 *  Hence the one sign change.
	 *  XXX this should probably be done with atan2()
	 */

	if ( first ) {
	    first = 0;
	    VJOIN1( first_hit, ap->a_ray.r_pt, pp->pt_inhit->hit_dist, ap->a_ray.r_dir );
	}
    out:
	RT_HIT_NORMAL( normal, pp->pt_inhit, pp->pt_inseg->seg_stp, &(ap->a_ray), pp->pt_inflip );
	dot_prod = VDOT( ap->a_ray.r_dir, normal );
	if ( dot_prod > 1.0 )
	    dot_prod = 1.0;
	if ( dot_prod < -1.0 )
	    dot_prod = (-1.0);

	in_obliq = acos( -dot_prod ) *
	    bn_radtodeg;
	RT_HIT_NORMAL( normal, pp->pt_outhit, pp->pt_outseg->seg_stp, &(ap->a_ray), pp->pt_outflip );
	dot_prod = VDOT( ap->a_ray.r_dir, normal );
	if ( dot_prod > 1.0 )
	    dot_prod = 1.0;
	if ( dot_prod < -1.0 )
	    dot_prod = (-1.0);

	out_obliq = acos( dot_prod ) *
	    bn_radtodeg;

	/* Check for exit obliquties greater than 90 degrees. */
#if 0
	if ( in_obliq > 90 || in_obliq < 0 )  {
	    bu_log("ERROR: in_obliquity=%g\n", in_obliq);
	    rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:");
	}
	if ( out_obliq > 90 || out_obliq < 0 )  {
	    bu_log("ERROR: out_obliquity=%g\n", out_obliq);
	    VPRINT(" r_dir", ap->a_ray.r_dir);
	    VPRINT("normal", normal);
	    bu_log("dot=%g, acos(dot)=%g\n",
		   VDOT( ap->a_ray.r_dir, normal ),
		   acos( VDOT( ap->a_ray.r_dir, normal ) ) );
	    /* Print the defective one */
	    rt_pr_pt( ap->a_rt_i, pp );
	    /* Print the whole ray's partition list */
	    rt_pr_partitions(ap->a_rt_i, PartHeadp, "Defective partion:");
	}
#endif

	if ( in_obliq > 90.0 )
	    in_obliq = 90.0;
	if ( in_obliq < 0.0 )
	    in_obliq = 0.0;
	if ( out_obliq > 90.0 )
	    out_obliq = 90.0;
	if ( out_obliq < 0.0 )
	    out_obliq = 0.0;

	/*
	 *  Handle 3-components per card output format, with
	 *  a leading space in front of the first component.
	 */
	if ( card_count == 0 )  {
	    bu_vls_strcat( &str, " " );
	}
	comp_thickness *= MM2IN;
	/* Check thickness fields for format overflow */
	if ( comp_thickness > 999.99 || air_thickness*MM2IN > 999.9 )
	    fmt = "%4d%6.1f%5.1f%5.1f%1d%5.0f";
	else
	    fmt = "%4d%6.2f%5.1f%5.1f%1d%5.1f";
#ifdef SPRINTF_NOT_PARALLEL
	bu_semaphore_acquire( BU_SEM_SYSCALL );
#endif
	snprintf(buf, 128, fmt,
		 region_id,
		 comp_thickness,
		 in_obliq, out_obliq,
		 air_id, air_thickness*MM2IN );
#ifdef SPRINTF_NOT_PARALLEL
	bu_semaphore_release( BU_SEM_SYSCALL );
#endif
	bu_vls_strcat( &str, buf );
	card_count++;
	if ( card_count >= 3 )  {
	    bu_vls_strcat( &str, "\n" );
	    card_count = 0;
	}

	/* A color rtg3.pl UnixPlot file of output commands
	 * is generated.  This is processed by plot(1)
	 * plotting filters such as pl-fb or pl-sgi.
	 * Portions of a ray passing through air within the
	 * model are represented in blue, while portions
	 * passing through a solid are assigned green.
	 * This will always be done single CPU,
	 * to prevent output garbling.  (See view_init).
	 */
	if (R_DEBUG & RDEBUG_RAYPLOT) {
	    vect_t     inpt;
	    vect_t     outpt;
	    VJOIN1(inpt, ap->a_ray.r_pt, pp->pt_inhit->hit_dist,
		   ap->a_ray.r_dir);
	    VJOIN1(outpt, ap->a_ray.r_pt, pp->pt_outhit->hit_dist,
		   ap->a_ray.r_dir);
	    pl_color(plotfp, 0, 255, 0);	/* green */
	    pdv_3line(plotfp, inpt, outpt);

	    if (air_thickness > 0) {
		vect_t     air_end;
		VJOIN1(air_end, ap->a_ray.r_pt,
		       pp->pt_outhit->hit_dist + air_thickness,
		       ap->a_ray.r_dir);
		pl_color(plotfp, 0, 0, 255);	/* blue */
		pdv_3cont(plotfp, air_end);
	    }
	}
	if ( nextpp == PartHeadp && air_id != 9 ) {
	    /* need to output a 111 'phantom armor' at end of shotline */
	    air_id = 9;
	    air_thickness = 0.0;
	    region_id = 111;
	    comp_thickness = 0.0;
	    goto out;
	}
    }

    /* If partway through building the line, add a newline */
    if ( card_count > 0 )  {
	/*
	 *  Note that GIFT zero-fills the unused component slots,
	 *  but neither COVART II nor COVART III require it,
	 *  so just end the line here.
	 */
	bu_vls_strcat( &str, "\n" );
    }

    /* Single-thread through file output.
     * COVART will accept non-sequential ray data provided the
     * ray header and its associated data are not separated.  CAVEAT:
     * COVART will not accept headers out of sequence.
     */
    bu_semaphore_acquire( BU_SEM_SYSCALL );

    fputs( bu_vls_addr( &str ), outfp );

    if ( shot_fp )
    {
	fprintf( shot_fp, "%.5f %.5f %.5f %.5f %.5f %.5f %.5f %.5f %ld %.5f %.5f %.5f\n",
		 azimuth, elevation, V3ARGS( ap->a_ray.r_pt ), V3ARGS( ap->a_ray.r_dir ),
		 line_num, V3ARGS( first_hit) );

	line_num +=  1 + (comp_count / 3 );
	if ( comp_count % 3 )
	    line_num++;
    }

    /* End of single-thread region */
    bu_semaphore_release( BU_SEM_SYSCALL );

    /* Release vls storage */
    bu_vls_free( &str );

    return(0);
}
Ejemplo n.º 13
0
/*
 * Given a u, v coordinate within the texture (0 <= u, v <= 1.0),
 * compute a new surface normal.
 * For now we come up with a local coordinate system, and
 * make bump perturbations from the red and blue channels of
 * an RGB image.
 *
 * Note that .pix files are stored left-to-right, bottom-to-top,
 * which works out very naturally for the indexing scheme.
 */
HIDDEN int
bmp_render(struct application *ap, const struct partition *pp, struct shadework *swp, void *dp)
{
    register struct txt_specific *tp =
	(struct txt_specific *)dp;
    unsigned char *cp=NULL;
    fastf_t pertU, pertV;
    vect_t y;		/* world coordinate axis vectors */
    vect_t u, v;		/* surface coord system vectors */
    int i, j;		/* bump map pixel indices */

    /*
     * If no texture file present, or if
     * texture isn't and can't be read, give debug color.
     */
    if ((bu_vls_strlen(&tp->tx_name) <= 0) || (!tp->tx_mp && !tp->tx_binunifp)) {
	VSET(swp->sw_color, swp->sw_uv.uv_u, 0, swp->sw_uv.uv_v);
	if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
	    (void)rr_render(ap, pp, swp);
	return 1;
    }
    /* u is left->right index, v is line number bottom->top */
    if (swp->sw_uv.uv_u < 0 || swp->sw_uv.uv_u > 1 || swp->sw_uv.uv_v < 0 || swp->sw_uv.uv_v > 1) {
	bu_log("bmp_render:  bad u, v=%g, %g du, dv=%g, %g seg=%s\n",
	       swp->sw_uv.uv_u, swp->sw_uv.uv_v,
	       swp->sw_uv.uv_du, swp->sw_uv.uv_dv,
	       pp->pt_inseg->seg_stp->st_name);
	VSET(swp->sw_color, 0, 1, 0);
	if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
	    (void)rr_render(ap, pp, swp);
	return 1;
    }

    /* Find a local coordinate system */
    VSET(y, 0, 1, 0);
    VCROSS(u, y, swp->sw_hit.hit_normal);
    VUNITIZE(u);
    VCROSS(v, swp->sw_hit.hit_normal, u);

    /* Find our RGB value */
    i = swp->sw_uv.uv_u * (tp->tx_w-1);
    j = swp->sw_uv.uv_v * (tp->tx_n-1);

    if (tp->tx_mp) {
	cp = ((unsigned char *)(tp->tx_mp->buf)) +
	    (j) * tp->tx_w * 3 + i * 3;
    } else if (tp->tx_binunifp) {
	cp = ((unsigned char *)(tp->tx_binunifp->u.uint8)) +
	    (j) * tp->tx_w * 3 + i * 3;
    } else {
	/* not reachable */
	bu_bomb("sh_text.c -- Unreachable code reached while reading datasource\n");
    }
    pertU = ((fastf_t)(*cp) - 128.0) / 128.0;
    pertV = ((fastf_t)(*(cp+2)) - 128.0) / 128.0;

    if (rdebug&RDEBUG_LIGHT) {
	VPRINT("normal", swp->sw_hit.hit_normal);
	VPRINT("u", u);
	VPRINT("v", v);
	bu_log("cu = %d, cv = %d\n", *cp, *(cp+2));
	bu_log("pertU = %g, pertV = %g\n", pertU, pertV);
    }
    VJOIN2(swp->sw_hit.hit_normal, swp->sw_hit.hit_normal, pertU, u, pertV, v);
    VUNITIZE(swp->sw_hit.hit_normal);
    if (rdebug&RDEBUG_LIGHT) {
	VPRINT("after", swp->sw_hit.hit_normal);
    }

    if (swp->sw_reflect > 0 || swp->sw_transmit > 0)
	(void)rr_render(ap, pp, swp);

    return 1;
}
Ejemplo n.º 14
0
/**
 * In theory, the grid can be specified by providing any two of
 * these sets of parameters:
 *
 * number of pixels (width, height)
 * viewsize (in model units, mm)
 * number of grid cells (cell_width, cell_height)
 *
 * however, for now, it is required that the view size always be
 * specified, and one or the other parameter be provided.
 */
void
grid_setup(void)
{
    vect_t temp;
    mat_t toEye;

    if (viewsize <= 0.0)
	bu_exit(EXIT_FAILURE, "viewsize <= 0");
    /* model2view takes us to eye_model location & orientation */
    MAT_IDN(toEye);
    MAT_DELTAS_VEC_NEG(toEye, eye_model);
    Viewrotscale[15] = 0.5*viewsize;	/* Viewscale */
    bn_mat_mul(model2view, Viewrotscale, toEye);
    bn_mat_inv(view2model, model2view);

    /* Determine grid cell size and number of pixels */
    if (cell_newsize) {
	if (cell_width <= 0.0) cell_width = cell_height;
	if (cell_height <= 0.0) cell_height = cell_width;
	width = (viewsize / cell_width) + 0.99;
	height = (viewsize / (cell_height*aspect)) + 0.99;
	cell_newsize = 0;
    } else {
	/* Chop -1.0..+1.0 range into parts */
	cell_width = viewsize / width;
	cell_height = viewsize / (height*aspect);
    }

    /*
     * Optional GIFT compatibility, mostly for RTG3.  Round coordinates
     * of lower left corner to fall on integer- valued coordinates, in
     * "gift_grid_rounding" units.
     */
    if (gift_grid_rounding > 0.0) {
	point_t v_ll;		/* view, lower left */
	point_t m_ll;		/* model, lower left */
	point_t hv_ll;		/* hv, lower left*/
	point_t hv_wanted;
	vect_t hv_delta;
	vect_t m_delta;
	mat_t model2hv;
	mat_t hv2model;

	/* Build model2hv matrix, including mm2inches conversion */
	MAT_COPY(model2hv, Viewrotscale);
	model2hv[15] = gift_grid_rounding;
	bn_mat_inv(hv2model, model2hv);

	VSET(v_ll, -1, -1, 0);
	MAT4X3PNT(m_ll, view2model, v_ll);
	MAT4X3PNT(hv_ll, model2hv, m_ll);
	VSET(hv_wanted, floor(hv_ll[X]), floor(hv_ll[Y]), floor(hv_ll[Z]));
	VSUB2(hv_delta, hv_ll, hv_wanted);

	MAT4X3PNT(m_delta, hv2model, hv_delta);
	VSUB2(eye_model, eye_model, m_delta);
	MAT_DELTAS_VEC_NEG(toEye, eye_model);
	bn_mat_mul(model2view, Viewrotscale, toEye);
	bn_mat_inv(view2model, model2view);
    }

    /* Create basis vectors dx and dy for emanation plane (grid) */
    VSET(temp, 1, 0, 0);
    MAT3X3VEC(dx_unit, view2model, temp);	/* rotate only */
    VSCALE(dx_model, dx_unit, cell_width);

    VSET(temp, 0, 1, 0);
    MAT3X3VEC(dy_unit, view2model, temp);	/* rotate only */
    VSCALE(dy_model, dy_unit, cell_height);

    if (stereo) {
	/* Move left 2.5 inches (63.5mm) */
	VSET(temp, -63.5*2.0/viewsize, 0, 0);
	bu_log("red eye: moving %f relative screen (left)\n", temp[X]);
	MAT4X3VEC(left_eye_delta, view2model, temp);
	VPRINT("left_eye_delta", left_eye_delta);
    }

    /* "Lower left" corner of viewing plane */
    if (rt_perspective > 0.0) {
	fastf_t zoomout;
	zoomout = 1.0 / tan(DEG2RAD * rt_perspective / 2.0);
	VSET(temp, -1, -1/aspect, -zoomout);	/* viewing plane */

	/*
	 * divergence is perspective angle divided by the number of
	 * pixels in that angle. Extra factor of 0.5 is because
	 * perspective is a full angle while divergence is the tangent
	 * (slope) of a half angle.
	 */
	APP.a_diverge = tan(DEG2RAD * rt_perspective * 0.5 / width);
	APP.a_rbeam = 0;
    } else {
	/* all rays go this direction */
	VSET(temp, 0, 0, -1);
	MAT4X3VEC(APP.a_ray.r_dir, view2model, temp);
	VUNITIZE(APP.a_ray.r_dir);

	VSET(temp, -1, -1/aspect, 0);	/* eye plane */
	APP.a_rbeam = 0.5 * viewsize / width;
	APP.a_diverge = 0;
    }
    if (ZERO(APP.a_rbeam) && ZERO(APP.a_diverge))
	bu_exit(EXIT_FAILURE, "zero-radius beam");
    MAT4X3PNT(viewbase_model, view2model, temp);

    if (jitter & JITTER_FRAME) {
	/* Move the frame in a smooth circular rotation in the plane */
	fastf_t ang;	/* radians */
	fastf_t dx, dy;

	ang = curframe * frame_delta_t * M_2PI / 10;	/* 10 sec period */
	dx = cos(ang) * 0.5;	/* +/- 1/4 pixel width in amplitude */
	dy = sin(ang) * 0.5;
	VJOIN2(viewbase_model, viewbase_model,
	       dx, dx_model,
	       dy, dy_model);
    }

    if (cell_width <= 0 || cell_width >= INFINITY ||
	cell_height <= 0 || cell_height >= INFINITY) {
	bu_log("grid_setup: cell size ERROR (%g, %g) mm\n",
	       cell_width, cell_height);
	bu_exit(EXIT_FAILURE, "cell size");
    }
    if (width <= 0 || height <= 0) {
	bu_log("grid_setup: ERROR bad image size (%zu, %zu)\n",
	       width, height);
	bu_exit(EXIT_FAILURE, "bad size");
    }
}
Ejemplo n.º 15
0
void
rt_superell_16pts(fastf_t *ov,
                  fastf_t *V,
                  fastf_t *A,
                  fastf_t *B)
{
    static fastf_t c, d, e, f, g, h;

    e = h = .92388;		/* cos(22.5 degrees) */
    c = d = M_SQRT1_2;		/* cos(45 degrees) */
    g = f = .382683;		/* cos(67.5 degrees) */

    /*
     * For angle theta, compute surface point as
     *
     * V + cos(theta) * A + sin(theta) * B
     *
     * note that sin(theta) is cos(90-theta); arguments in degrees.
     */

    VADD2(SUPERELLOUT(1), V, A);
    VJOIN2(SUPERELLOUT(2), V, e, A, f, B);
    VJOIN2(SUPERELLOUT(3), V, c, A, d, B);
    VJOIN2(SUPERELLOUT(4), V, g, A, h, B);
    VADD2(SUPERELLOUT(5), V, B);
    VJOIN2(SUPERELLOUT(6), V, -g, A, h, B);
    VJOIN2(SUPERELLOUT(7), V, -c, A, d, B);
    VJOIN2(SUPERELLOUT(8), V, -e, A, f, B);
    VSUB2(SUPERELLOUT(9), V, A);
    VJOIN2(SUPERELLOUT(10), V, -e, A, -f, B);
    VJOIN2(SUPERELLOUT(11), V, -c, A, -d, B);
    VJOIN2(SUPERELLOUT(12), V, -g, A, -h, B);
    VSUB2(SUPERELLOUT(13), V, B);
    VJOIN2(SUPERELLOUT(14), V, g, A, -h, B);
    VJOIN2(SUPERELLOUT(15), V, c, A, -d, B);
    VJOIN2(SUPERELLOUT(16), V, e, A, -f, B);
}
Ejemplo n.º 16
0
int
main( int argc, char *argv[] )
{
    struct application *ap;
    int c;
    int verbose = 0;
    int i, j;
    int grid_size = 64;
    fastf_t cell_size;
    vect_t model_size;
    vect_t xdir, zdir;
    int job_count=0;
    char **result_map = NULL;
    struct bu_ptbl objs;
    int my_session_id;
    int do_plot=0;
    struct timeval startTime;
    struct timeval endTime;
    double diff;
    point_t mdl_min;
    point_t mdl_max;
    struct bu_vlb *vlb;

    /* Things like bu_malloc() must have these initialized for use with parallel processing */
    bu_semaphore_init( RT_SEM_LAST );

    /* initialize the list of BRL-CAD objects to be raytraced (this is used for the "-o" option) */
    bu_ptbl_init( &objs, 64, "objects" );

    /* process command line args */
    while ( (c=bu_getopt( argc, argv, "vps:o:" ) ) != -1 ) {
	switch ( c ) {
	    case 'p': /* do print plot */
		do_plot = 1;
		break;
	    case 's':	/* set the grid size (default is 64x64) */
		grid_size = atoi( bu_optarg );
		break;
	    case 'v':	/* turn on verbose logging */
		verbose = 1;
		rts_set_verbosity( 1 );
		break;
	    case 'o':	/* add an object name to the list of BRL-CAD objects to raytrace */
		bu_ptbl_ins( &objs, (long *)bu_optarg );
		break;
	    default:	/* ERROR */
		bu_exit(1, usage, argv[0]);
	}
    }

    if (bu_debug & BU_DEBUG_MEM_CHECK) {
	bu_prmem("initial memory map");
	bu_mem_barriercheck();
    }


    /* shoot a ray ten times, cleaning and loading geometry each time */
    for(i=0 ; i<10 ; i++) {
	/* load geometry */
	my_session_id = loadGeometry( argv[bu_optind], &objs );


	if ( my_session_id < 0 ) {
	    bu_exit(2, "Failed to load geometry from file (%s)\n", argv[bu_optind] );
	}

	get_model_extents( my_session_id, mdl_min, mdl_max );
	VSET( xdir, 1, 0, 0 );
	VSET( zdir, 0, 0, 1 );
	VSUB2( model_size, mdl_max, mdl_min );

	ap = NULL;
	getApplication(&ap);
	VJOIN2( ap->a_ray.r_pt, mdl_min,
		model_size[Z]/2.0, zdir,
		model_size[X]/2.0, xdir );
	VSET( ap->a_ray.r_dir, 0, 1, 0 );
	rts_shootray(ap);

	vlb = (struct bu_vlb*)ap->a_uptr;
	printHits(vlb);

	freeApplication(ap);
	/*rts_clean( my_session_id );*/
	bu_log( "\n\n********* %d\n", i);
	if (bu_debug & BU_DEBUG_MEM_CHECK) {
	    bu_prmem("memory after shutdown");
	}
    }

    my_session_id = loadGeometry( argv[bu_optind], &objs );

    /* submit some jobs */
    fprintf( stderr, "\nfiring a grid (%dx%d) of rays at",
	     grid_size, grid_size );
    for ( i=0; i<(int)BU_PTBL_LEN( &objs ); i++ ) {
	fprintf( stderr, " %s", (char *)BU_PTBL_GET( &objs, i ) );
    }
    fprintf( stderr, "...\n" );

    if( do_plot ) {
	result_map = (char **)bu_calloc( grid_size, sizeof( char *), "result_map" );
	for ( i=0; i<grid_size; i++ ) {
	    result_map[i] = (char *)bu_calloc( (grid_size+1), sizeof( char ), "result_map[i]" );
	}
    }

    cell_size = model_size[X] / grid_size;
    gettimeofday( &startTime, NULL );
    for ( i=0; i<grid_size; i++ ) {
	if( verbose ) {
	    fprintf( stderr, "shooting row %d\n", i );
	}
	for ( j=0; j<grid_size; j++ ) {
	    int hitCount;

	    getApplication(&ap);
	    ap->a_user = my_session_id;
	    VJOIN2( ap->a_ray.r_pt,
		    mdl_min,
		    i*cell_size,
		    zdir,
		    j*cell_size,
		    xdir );
	    ap->a_ray.index = ap->a_user;
	    VSET( ap->a_ray.r_dir, 0, 1, 0 );
	    rts_shootray(ap);
	    if( do_plot ) {
		hitCount = countHits(ap->a_uptr);
		if ( hitCount == 0 ) {
		    result_map[i][j] = ' ';
		} else if ( hitCount <= 9 ) {
		    result_map[i][j] = '0' + hitCount;
		} else {
		    result_map[i][j] = '*';
		}
	    }
	    freeApplication(ap);
	    job_count++;
	}
    }
    gettimeofday( &endTime, NULL );
    diff = endTime.tv_sec - startTime.tv_sec + (endTime.tv_usec - startTime.tv_usec) / 1000000.0;
    fprintf( stderr, "time for %d individual rays: %g second\n", job_count, diff );

    if(do_plot) {
	for ( i=grid_size-1; i>=0; i-- ) {
	    fprintf( stderr, "%s\n", result_map[i] );
	}
    }
    return 0;
}
Ejemplo n.º 17
0
void
do_pixel(int cpu, int pat_num, int pixelnum)
{
    struct application a;
    struct pixel_ext pe;
    vect_t stereo_point;		/* Ref point on eye or view plane */
    vect_t point;		/* Ref point on eye or view plane */
    vect_t colorsum = {(fastf_t)0.0, (fastf_t)0.0, (fastf_t)0.0};
    int samplenum = 0;
    static const double one_over_255 = 1.0 / 255.0;
    const int pindex = (pixelnum * sizeof(RGBpixel));


    if (lightmodel == 8) {
	/* Add timer here to start pixel-time for heat
	 * graph, when asked.
	 */
	rt_prep_timer();
    }

    /* Obtain fresh copy of global application struct */
    a = APP;				/* struct copy */
    a.a_resource = &resource[cpu];

    if (incr_mode) {
	register int i = 1<<incr_level;
	a.a_y = pixelnum/i;
	a.a_x = pixelnum - (a.a_y * i);
	/* a.a_x = pixelnum%i; */
	if (incr_level != 0) {
	    /* See if already done last pass */
	    if (((a.a_x & 1) == 0) &&
		((a.a_y & 1) == 0))
		return;
	}
	a.a_x <<= (incr_nlevel-incr_level);
	a.a_y <<= (incr_nlevel-incr_level);
    } else {
	a.a_y = pixelnum/width;
	a.a_x = pixelnum - (a.a_y * width);
	/* a.a_x = pixelnum%width; */
    }

    if (Query_one_pixel) {
	if (a.a_x == query_x && a.a_y == query_y) {
	    rdebug = query_rdebug;
	    RTG.debug = query_debug;
	} else {
	    RTG.debug = rdebug = 0;
	}
    }

    if (sub_grid_mode) {
	if (a.a_x < sub_xmin || a.a_x > sub_xmax)
	    return;
	if (a.a_y < sub_ymin || a.a_y > sub_ymax)
	    return;
    }
    if (fullfloat_mode) {
	register struct floatpixel *fp;
	fp = &curr_float_frame[a.a_y*width + a.a_x];
	if (fp->ff_frame >= 0) {
	    return;	/* pixel was reprojected */
	}
    }

    /* Check the pixel map to determine if this image should be
     * rendered or not.
     */
    if (pixmap) {
	a.a_user= 1;	/* Force Shot Hit */

	if (pixmap[pindex + RED] + pixmap[pindex + GRN] + pixmap[pindex + BLU]) {
	    /* non-black pixmap pixel */

	    a.a_color[RED]= (double)(pixmap[pindex + RED]) * one_over_255;
	    a.a_color[GRN]= (double)(pixmap[pindex + GRN]) * one_over_255;
	    a.a_color[BLU]= (double)(pixmap[pindex + BLU]) * one_over_255;

	    /* we're done */
	    view_pixel(&a);
	    if ((size_t)a.a_x == width-1) {
		view_eol(&a);		/* End of scan line */
	    }
	    return;
	}
    }

    /* our starting point, used for non-jitter */
    VJOIN2 (point, viewbase_model, a.a_x, dx_model, a.a_y, dy_model);

    /* not tracing the corners of a prism by default */
    a.a_pixelext=(struct pixel_ext *)NULL;

    /* black or no pixmap, so compute the pixel(s) */

    /* LOOP BELOW IS UNROLLED ONE SAMPLE SINCE THAT'S THE COMMON CASE.
     *
     * XXX - If you edit the unrolled or non-unrolled section, be sure
     * to edit the other section.
     */
    if (hypersample == 0) {
	/* not hypersampling, so just do it */

	/****************/
	/* BEGIN UNROLL */
	/****************/

	if (jitter & JITTER_CELL) {
	    jitter_start_pt(point, &a, samplenum, pat_num);
	}

	if (a.a_rt_i->rti_prismtrace) {
	    /* compute the four corners */
	    pe.magic = PIXEL_EXT_MAGIC;
	    VJOIN2(pe.corner[0].r_pt, viewbase_model, a.a_x, dx_model, a.a_y, dy_model);
	    VJOIN2(pe.corner[1].r_pt, viewbase_model, (a.a_x+1), dx_model, a.a_y, dy_model);
	    VJOIN2(pe.corner[2].r_pt, viewbase_model, (a.a_x+1), dx_model, (a.a_y+1), dy_model);
	    VJOIN2(pe.corner[3].r_pt, viewbase_model, a.a_x, dx_model, (a.a_y+1), dy_model);
	    a.a_pixelext = &pe;
	}

	if (rt_perspective > 0.0) {
	    VSUB2(a.a_ray.r_dir, point, eye_model);
	    VUNITIZE(a.a_ray.r_dir);
	    VMOVE(a.a_ray.r_pt, eye_model);
	    if (a.a_rt_i->rti_prismtrace) {
		VSUB2(pe.corner[0].r_dir, pe.corner[0].r_pt, eye_model);
		VSUB2(pe.corner[1].r_dir, pe.corner[1].r_pt, eye_model);
		VSUB2(pe.corner[2].r_dir, pe.corner[2].r_pt, eye_model);
		VSUB2(pe.corner[3].r_dir, pe.corner[3].r_pt, eye_model);
	    }
	} else {
	    VMOVE(a.a_ray.r_pt, point);
	    VMOVE(a.a_ray.r_dir, APP.a_ray.r_dir);

	    if (a.a_rt_i->rti_prismtrace) {
		VMOVE(pe.corner[0].r_dir, a.a_ray.r_dir);
		VMOVE(pe.corner[1].r_dir, a.a_ray.r_dir);
		VMOVE(pe.corner[2].r_dir, a.a_ray.r_dir);
		VMOVE(pe.corner[3].r_dir, a.a_ray.r_dir);
	    }
	}
	if (report_progress) {
	    report_progress = 0;
	    bu_log("\tframe %d, xy=%d, %d on cpu %d, samp=%d\n", curframe, a.a_x, a.a_y, cpu, samplenum);
	}

	a.a_level = 0;		/* recursion level */
	a.a_purpose = "main ray";
	(void)rt_shootray(&a);

	if (stereo) {
	    fastf_t right, left;

	    right = CRT_BLEND(a.a_color);

	    VSUB2(stereo_point, point, left_eye_delta);
	    if (rt_perspective > 0.0) {
		VSUB2(a.a_ray.r_dir, stereo_point, eye_model);
		VUNITIZE(a.a_ray.r_dir);
		VADD2(a.a_ray.r_pt, eye_model, left_eye_delta);
	    } else {
		VMOVE(a.a_ray.r_pt, stereo_point);
	    }
	    a.a_level = 0;		/* recursion level */
	    a.a_purpose = "left eye ray";
	    (void)rt_shootray(&a);

	    left = CRT_BLEND(a.a_color);
	    VSET(a.a_color, left, 0, right);
	}
	VADD2(colorsum, colorsum, a.a_color);

	/**************/
	/* END UNROLL */
	/**************/

    } else {
	/* hypersampling, so iterate */

	for (samplenum=0; samplenum<=hypersample; samplenum++) {
	    /* shoot at a point based on the jitter pattern number */

	    /**********************/
	    /* BEGIN NON-UNROLLED */
	    /**********************/

	    if (jitter & JITTER_CELL) {
		jitter_start_pt(point, &a, samplenum, pat_num);
	    }

	    if (a.a_rt_i->rti_prismtrace) {
		/* compute the four corners */
		pe.magic = PIXEL_EXT_MAGIC;
		VJOIN2(pe.corner[0].r_pt, viewbase_model, a.a_x, dx_model, a.a_y, dy_model);
		VJOIN2(pe.corner[1].r_pt, viewbase_model, (a.a_x+1), dx_model, a.a_y, dy_model);
		VJOIN2(pe.corner[2].r_pt, viewbase_model, (a.a_x+1), dx_model, (a.a_y+1), dy_model);
		VJOIN2(pe.corner[3].r_pt, viewbase_model, a.a_x, dx_model, (a.a_y+1), dy_model);
		a.a_pixelext = &pe;
	    }

	    if (rt_perspective > 0.0) {
		VSUB2(a.a_ray.r_dir, point, eye_model);
		VUNITIZE(a.a_ray.r_dir);
		VMOVE(a.a_ray.r_pt, eye_model);
		if (a.a_rt_i->rti_prismtrace) {
		    VSUB2(pe.corner[0].r_dir, pe.corner[0].r_pt, eye_model);
		    VSUB2(pe.corner[1].r_dir, pe.corner[1].r_pt, eye_model);
		    VSUB2(pe.corner[2].r_dir, pe.corner[2].r_pt, eye_model);
		    VSUB2(pe.corner[3].r_dir, pe.corner[3].r_pt, eye_model);
		}
	    } else {
		VMOVE(a.a_ray.r_pt, point);
		VMOVE(a.a_ray.r_dir, APP.a_ray.r_dir);

		if (a.a_rt_i->rti_prismtrace) {
		    VMOVE(pe.corner[0].r_dir, a.a_ray.r_dir);
		    VMOVE(pe.corner[1].r_dir, a.a_ray.r_dir);
		    VMOVE(pe.corner[2].r_dir, a.a_ray.r_dir);
		    VMOVE(pe.corner[3].r_dir, a.a_ray.r_dir);
		}
	    }
	    if (report_progress) {
		report_progress = 0;
		bu_log("\tframe %d, xy=%d, %d on cpu %d, samp=%d\n", curframe, a.a_x, a.a_y, cpu, samplenum);
	    }

	    a.a_level = 0;		/* recursion level */
	    a.a_purpose = "main ray";
	    (void)rt_shootray(&a);

	    if (stereo) {
		fastf_t right, left;

		right = CRT_BLEND(a.a_color);

		VSUB2(stereo_point, point, left_eye_delta);
		if (rt_perspective > 0.0) {
		    VSUB2(a.a_ray.r_dir, stereo_point, eye_model);
		    VUNITIZE(a.a_ray.r_dir);
		    VADD2(a.a_ray.r_pt, eye_model, left_eye_delta);
		} else {
		    VMOVE(a.a_ray.r_pt, stereo_point);
		}
		a.a_level = 0;		/* recursion level */
		a.a_purpose = "left eye ray";
		(void)rt_shootray(&a);

		left = CRT_BLEND(a.a_color);
		VSET(a.a_color, left, 0, right);
	    }
	    VADD2(colorsum, colorsum, a.a_color);

	    /********************/
	    /* END NON-UNROLLED */
	    /********************/
	} /* for samplenum <= hypersample */

	{
	    /* scale the hypersampled results */
	    fastf_t f;
	    f = 1.0 / (hypersample+1);
	    VSCALE(a.a_color, colorsum, f);
	}
    } /* end unrolling else case */

    /* bu_log("2: [%d, %d] : [%.2f, %.2f, %.2f]\n", pixelnum%width, pixelnum/width, a.a_color[0], a.a_color[1], a.a_color[2]); */

    /* FIXME: this should work on windows after the bu_timer() is
     * created to replace the librt timing mechanism.
     */
#if !defined(_WIN32) || defined(__CYGWIN__)
    /* Add get_pixel_timer here to get total time taken to get pixel, when asked */
    if (lightmodel == 8) {
	fastf_t pixelTime;
	fastf_t **timeTable;

	pixelTime = rt_get_timer(NULL,NULL);
	/* bu_log("PixelTime = %lf X:%d Y:%d\n", pixelTime, a.a_x, a.a_y); */
	bu_semaphore_acquire(RT_SEM_LAST-2);
	timeTable = timeTable_init(width, height);
	timeTable_input(a.a_x, a.a_y, pixelTime, timeTable);
	bu_semaphore_release(RT_SEM_LAST-2);
    }
#endif
    /* we're done */
    view_pixel(&a);
    if ((size_t)a.a_x == width-1) {
	view_eol(&a);		/* End of scan line */
    }
    return;
}