Difference between revisions of "Example Application"

From BRL-CAD
m
(pre tag since source isn't rendering atm)
 
(One intermediate revision by one other user not shown)
Line 1: Line 1:
 
[[category:Code examples]]
 
[[category:Code examples]]
<source lang="c">
+
<pre lang="c">
/*
+
/*                     R T E X A M P L E . C
* R T E X A M P L E . C
+
* BRL-CAD
 +
*
 +
* Copyright (c) 2004-2013 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 rt/rtexample.c
 +
*
 +
* This is a heavily commented example of a program that uses librt to
 +
* shoot a single ray at some geometry in a .g database.
 +
*
 +
* The primary BRL-CAD ray-tracing API consists of calls to the
 +
* function rt_shootray().  This function takes a single argument, the
 +
* address of a data structure called the "application" structure.
 +
* This data structure contains crucial information, such as the
 +
* origin and direction of the ray to be traced, what to do if the ray
 +
* hits geometry, or what to do if it misses everything.  While the
 +
* application struct is a large and somewhat complex looking, (it is
 +
* defined in the raytrace.h header) there are really very few items
 +
* in it which the application programmer must know about. These are:
 +
*
 +
*  a_rt_i The "raytrace instance" obtained via rt_dirbuild()
 +
*  a_ray The ray origin and direction to be shot
 +
*  a_hit A callback function for when the ray encounters geometry
 +
*  a_miss A callback function for when the ray misses everything
 +
*
 +
* Most of the work an application performs will be done in the "hit"
 +
* routine.  This user-supplied routine gets called deep inside the
 +
* raytracing library via the rt_shootray() function.  It is provided
 +
* with 3 parameters:
 +
*
 +
*  ap Pointer to the application structure passed to rt_shootray()
 +
*  PartHeadp List of ray "partitions" which represent geometry hit
 +
*  segp List of ray "segments" that comprised partitions
 +
*
 +
* Most applications can ignore the last parameter.  The PartHeadp
 +
* parameter is a linked-list of "partition" structures (defined in
 +
* the raytrace.h header).  It is the job of the "hit" routine to
 +
* process these ray/object intersections to do the work of the
 +
* application.
 +
*
 +
* This file is part of the default compile in source distributions of
 +
* BRL-CAD and is usually installed or provided via binary and source
 +
* distributions.  To compile this example from a binary install:
 
  *
 
  *
  * A trivial example of a program that uses librt.  With comments.
+
  * cc -I/usr/brlcad/include/brlcad -L/usr/brlcad/lib -o rtexample rtexample.c -lbu -lrt -lm
 
  *
 
  *
  * cc -I/path/to/include/brlcad -o rtexample rtexample.c librt.a -lm
+
  * Jump to the START HERE section below for main().
 
  */
 
  */
 +
 
#include "common.h"
 
#include "common.h"
  
 +
#include <stdlib.h>
 +
#include <math.h>
 +
#include <string.h>
 
#include <stdio.h>
 
#include <stdio.h>
#include <math.h>
+
 
#include "machine.h" /* machine specific definitions */
 
 
#include "vmath.h" /* vector math macros */
 
#include "vmath.h" /* vector math macros */
 
#include "raytrace.h" /* librt interface definitions */
 
#include "raytrace.h" /* librt interface definitions */
  
/* every application needs one of these */
 
struct application ap;
 
  
/* routines for shootray() to call on hit or miss */
+
/**
extern int hit(struct application *ap, struct partition *PartHeadp, struct seg *segs);
+
* rt_shootray() was told to call this on a hit.
extern int miss(register struct application *ap);
+
*
 
+
* This callback routine utilizes the application structure which
char usage[] = "\
+
* describes the current state of the raytrace.
Usage:  rtexample model.g objects...\n";
+
*
 
+
* This callback routine is provided a circular linked list of
main(int argc, char **argv)
+
* partitions, each one describing one in and out segment of one
 +
* region for each region encountered.
 +
*
 +
* The 'segs' segment list is unused in this example.
 +
*/
 +
int
 +
hit(struct application *ap, struct partition *PartHeadp, struct seg *UNUSED(segs))
 
{
 
{
     static struct rt_i *rtip; /* rt_dirbuild returns this */
+
     /* iterating over partitions, this will keep track of the current
     char idbuf[132]; /* First ID record info */
+
    * partition we're working on.
 +
    */
 +
     struct partition *pp;
  
     if( argc < 3 )  {
+
     /* will serve as a pointer for the entry and exit hitpoints */
(void)fputs(usage, stderr);
+
     struct hit *hitp;
exit(1);
 
     }
 
  
     /*
+
     /* will serve as a pointer to the solid primitive we hit */
    *  Load database.
+
     struct soltab *stp;
    *  rt_dirbuild() returns an "instance" pointer which describes
 
    *  the database to be ray traced.  It also gives you back the
 
    *  title string in the header (ID) record.
 
    */
 
     if( (rtip=rt_dirbuild(argv[1], idbuf, sizeof(idbuf))) == RTI_NULL ) {
 
fprintf(stderr,"rtexample: rt_dirbuild failure\n");
 
exit(2);
 
    }
 
    ap.a_rt_i = rtip; /* your application uses this instance */
 
    fprintf(stderr, "db title: %s\n", idbuf);
 
  
     /* Walk trees.
+
     /* will contain surface curvature information at the entry */
    * Here you identify any object trees in the database that you
+
     struct curvature cur = RT_CURVATURE_INIT_ZERO;
    * want included in the ray trace.
 
    */
 
    while( argc > 2 )  {
 
if( rt_gettree(rtip, argv[2]) < 0 )
 
    fprintf(stderr,"rt_gettree(%s) FAILED\n", argv[0]);
 
argc--;
 
argv++;
 
    }
 
    /*
 
    * This next call gets the database ready for ray tracing.
 
    * (it precomputes some values, sets up space partitioning, etc.)
 
    */
 
     rt_prep_parallel(rtip,1);
 
  
     /*
+
     /* will contain our hit point coordinate */
    * Set the ray start point and direction
+
     point_t pt;
    * rt_shootray() uses these two to determine what ray to fire.
 
    * In this case we simply shoot down the z axis toward the
 
    * origin from 10 meters away [librt assumes units of millimeters.
 
    * not that is really maters here, but an MGED database made with
 
    * units=mm will have the same values in the file (and thus in
 
    * librt) that you see displayed by MGED.
 
    */
 
     VSET( ap.a_ray.r_pt, 0, 0, 10000 );
 
    VSET( ap.a_ray.r_dir, 0, 0, -1 );
 
  
     VPRINT( "Pnt", ap.a_ray.r_pt );
+
     /* will contain normal vector where ray enters geometry */
    VPRINT( "Dir", ap.a_ray.r_dir );
+
    vect_t inormal;
  
     /* Shoot Ray */
+
     /* will contain normal vector where ray exits geometry */
    ap.a_hit = hit; /* where to go on a hit */
+
     vect_t onormal;
     ap.a_miss = miss; /* where to go on a miss */
 
    (void)rt_shootray( &ap ); /* do it */
 
  
     /*
+
     /* iterate over each partition until we get back to the head.
     * A real application would probably set up another
+
     * each partition corresponds to a specific homogeneous region of
     * ray and fire again.
+
     * material.
 
     */
 
     */
 +
    for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) {
  
    return(0);
+
/* print the name of the region we hit as well as the name of
}
+
* the primitives encountered on entry and exit.
 
+
*/
/*
 
*  rt_shootray() was told to call this on a hit.  He gives up the
 
*  application structure which describes the state of the world
 
*  (see raytrace.h), and a circular linked list of partitions,
 
* each one describing one in and out segment of one region.
 
*/
 
hit(register struct application *ap, struct partition *PartHeadp, struct seg *segs)
 
{
 
    /* see raytrace.h for all of these guys */
 
    register struct partition *pp;
 
    register struct hit *hitp;
 
    register struct soltab *stp;
 
    struct curvature cur;
 
    point_t pt;
 
    vect_t inormal;
 
    vect_t onormal;
 
 
 
    /* examine each partition until we get back to the head */
 
    for( pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw )  {
 
 
bu_log("\n--- Hit region %s (in %s, out %s)\n",
 
bu_log("\n--- Hit region %s (in %s, out %s)\n",
 
      pp->pt_regionp->reg_name,
 
      pp->pt_regionp->reg_name,
Line 117: Line 127:
 
      pp->pt_outseg->seg_stp->st_name );
 
      pp->pt_outseg->seg_stp->st_name );
  
/* inhit info */
+
/* entry hit point, so we type less */
 
hitp = pp->pt_inhit;
 
hitp = pp->pt_inhit;
 +
 +
/* construct the actual (entry) hit-point from the ray and the
 +
* distance to the intersection point (i.e., the 't' value).
 +
*/
 +
VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
 +
 +
/* primitive we encountered on entry */
 
stp = pp->pt_inseg->seg_stp;
 
stp = pp->pt_inseg->seg_stp;
  
VJOIN1( pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir );
+
/* compute the normal vector at the entry point, flipping the
 +
* normal if necessary.
 +
*/
 +
RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip);
  
/* This macro takes care of the flip flag and all that */
+
/* print the entry hit point info */
RT_HIT_NORMAL( inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip );
+
rt_pr_hit("  In", hitp);
 +
VPRINT(  "  Ipoint", pt);
 +
VPRINT(   "  Inormal", inormal);
  
rt_pr_hit( "  In", hitp );
+
/* This next macro fills in the curvature information which
VPRINT(    "  Ipoint", pt );
+
* consists on a principle direction vector, and the inverse
VPRINT(    "  Inormal", inormal );
+
* radii of curvature along that direction and perpendicular
/*
+
* to it.  Positive curvature bends toward the outward
* This next macro fills in the curvature information
+
* pointing normal.
* which consists on a principle direction vector, and
 
* the inverse radii of curvature along that direction
 
* and perpendicular to it.  Positive curvature bends
 
* toward the outward pointing normal.
 
 
*/
 
*/
RT_CURVATURE( &cur, hitp, pp->pt_inflip, stp );
+
RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp);
VPRINT("PDir", cur.crv_pdir );
+
 
 +
/* print the entry curvature information */
 +
VPRINT("PDir", cur.crv_pdir);
 
bu_log(" c1=%g\n", cur.crv_c1);
 
bu_log(" c1=%g\n", cur.crv_c1);
 
bu_log(" c2=%g\n", cur.crv_c2);
 
bu_log(" c2=%g\n", cur.crv_c2);
  
/* outhit info */
+
/* exit point, so we type less */
 
hitp = pp->pt_outhit;
 
hitp = pp->pt_outhit;
 +
 +
/* construct the actual (exit) hit-point from the ray and the
 +
* distance to the intersection point (i.e., the 't' value).
 +
*/
 +
VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);
 +
 +
/* primitive we exited from */
 
stp = pp->pt_outseg->seg_stp;
 
stp = pp->pt_outseg->seg_stp;
VJOIN1( pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir );
 
RT_HIT_NORMAL( onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip );
 
  
rt_pr_hit( "  Out", hitp );
+
/* compute the normal vector at the exit point, flipping the
VPRINT(   "  Opoint", pt );
+
* normal if necessary.
VPRINT(   "  Onormal", onormal );
+
*/
 +
RT_HIT_NORMAL(onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip);
 +
 
 +
/* print the exit hit point info */
 +
rt_pr_hit("  Out", hitp);
 +
VPRINT(   "  Opoint", pt);
 +
VPRINT(   "  Onormal", onormal);
 
     }
 
     }
  
     /*
+
     /* A more complicated application would probably fill in a new
    * A more complicated application would probably fill in a
+
     * local application structure and describe, for example, a
     * new local application structure and describe say a reflected
+
     * reflected or refracted ray, and then call rt_shootray() for
     * or refracted ray, and then call rt_shootray with it.
+
    * those rays.
 
     */
 
     */
  
     /*
+
     /* Hit routine callbacks generally return 1 on hit or 0 on miss.
     * This value is returned by rt_shootray
+
     * This value is returned by rt_shootray().
    * a hit usually returns 1, miss 0.
 
 
     */
 
     */
     return(1);
+
     return 1;
 
}
 
}
  
/*
+
 
  * rt_shootray() was told to call this on a miss.
+
/**
 +
* This is a callback routine that is invoked for every ray that
 +
* entirely misses hitting any geometry.  This function is invoked by
 +
  * rt_shootray() if the ray encounters nothing.
 
  */
 
  */
miss(register struct application *ap)
+
int
 +
miss(struct application *UNUSED(ap))
 
{
 
{
 
     bu_log("missed\n");
 
     bu_log("missed\n");
     return(0);
+
     return 0;
 +
}
 +
 
 +
 
 +
/**
 +
* START HERE
 +
*
 +
* This is where it all begins.
 +
*/
 +
int
 +
main(int argc, char **argv)
 +
{
 +
    /* Every application needs one of these.  The "application"
 +
    * structure carries information about how the ray-casting should
 +
    * be performed.  Defined in the raytrace.h header.
 +
    */
 +
    struct application ap;
 +
 
 +
    /* The "raytrace instance" structure contains definitions for
 +
    * librt which are specific to the particular model being
 +
    * processed.  One copy exists for each model.  Defined in
 +
    * the raytrace.h header and is returned by rt_dirbuild().
 +
    */
 +
    static struct rt_i *rtip;
 +
 
 +
    /* optional parameter to rt_dirbuild() that can be used to capture
 +
    * a title if the geometry database has one set.
 +
    */
 +
    char title[1024] = {0};
 +
 
 +
    /* Check for command-line arguments.  Make sure we have at least a
 +
    * geometry file and one geometry object on the command line.
 +
    */
 +
    if (argc < 3) {
 +
bu_exit(1, "Usage: %s model.g objects...\n", argv[0]);
 +
    }
 +
 
 +
    /* Load the specified geometry database (i.e., a ".g" file).
 +
    * rt_dirbuild() returns an "instance" pointer which describes the
 +
    * database to be raytraced.  It also gives you back the title
 +
    * string if you provide a buffer.  This builds a directory of the
 +
    * geometry (i.e., a table of contents) in the file.
 +
    */
 +
    rtip = rt_dirbuild(argv[1], title, sizeof(title));
 +
    if (rtip == RTI_NULL) {
 +
bu_exit(2, "Building the database directory for [%s] FAILED\n", argv[1]);
 +
    }
 +
 
 +
    /* Display the geometry database title obtained during
 +
    * rt_dirbuild if a title is set.
 +
    */
 +
    if (title[0]) {
 +
bu_log("Title:\n%s\n", title);
 +
    }
 +
 
 +
    /* Walk the geometry trees.  Here you identify any objects in the
 +
    * database that you want included in the ray trace by iterating
 +
    * of the object names that were specified on the command-line.
 +
    */
 +
    while (argc > 2)  {
 +
if (rt_gettree(rtip, argv[2]) < 0)
 +
    bu_log("Loading the geometry for [%s] FAILED\n", argv[2]);
 +
argc--;
 +
argv++;
 +
    }
 +
 
 +
    /* This next call gets the database ready for ray tracing.  This
 +
    * causes some values to be precomputed, sets up space
 +
    * partitioning, computes bounding volumes, etc.
 +
    */
 +
    rt_prep_parallel(rtip, 1);
 +
 
 +
    /* initialize all values in application structure to zero */
 +
    RT_APPLICATION_INIT(&ap);
 +
 
 +
    /* your application uses the raytrace instance containing the
 +
    * geometry we loaded.  this describes what we're shooting at.
 +
    */
 +
    ap.a_rt_i = rtip;
 +
 
 +
    /* stop at the first point of intersection or shoot all the way
 +
    * through (defaults to 0 to shoot all the way through).
 +
    */
 +
    ap.a_onehit = 0;
 +
 
 +
    /* Set the ray start point and direction rt_shootray() uses these
 +
    * two to determine what ray to fire.  In this case we simply
 +
    * shoot down the z axis toward the origin from 10 meters away.
 +
    *
 +
    * It's worth nothing that librt assumes units of millimeters.
 +
    * All geometry is stored as millimeters regardless of the units
 +
    * set during editing.  There are libbu routines for performing
 +
    * unit conversions if desired.
 +
    */
 +
    VSET(ap.a_ray.r_pt, 0.0, 0.0, 10000.0);
 +
    VSET(ap.a_ray.r_dir, 0.0, 0.0, -1.0);
 +
 
 +
    /* Simple debug printing */
 +
    VPRINT("Pnt", ap.a_ray.r_pt);
 +
    VPRINT("Dir", ap.a_ray.r_dir);
 +
 
 +
    /* This is what callback to perform on a hit. */
 +
    ap.a_hit = hit;
 +
 
 +
    /* This is what callback to perform on a miss. */
 +
    ap.a_miss = miss;
 +
 
 +
    /* Shoot the ray. */
 +
    (void)rt_shootray(&ap);
 +
 
 +
    /* A real application would probably set up another ray and fire
 +
    * again or do something a lot more complex in the callbacks.
 +
    */
 +
 
 +
    return 0;
 
}
 
}
  
Line 178: Line 326:
 
  * mode: C
 
  * mode: C
 
  * tab-width: 8
 
  * tab-width: 8
* c-basic-offset: 4
 
 
  * indent-tabs-mode: t
 
  * indent-tabs-mode: t
 +
* c-file-style: "stroustrup"
 
  * End:
 
  * End:
 
  * ex: shiftwidth=4 tabstop=8
 
  * ex: shiftwidth=4 tabstop=8
 
  */
 
  */
</source>
+
</pre>

Latest revision as of 01:26, 3 December 2019

/*                     R T E X A M P L E . C
 * BRL-CAD
 *
 * Copyright (c) 2004-2013 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 rt/rtexample.c
 *
 * This is a heavily commented example of a program that uses librt to
 * shoot a single ray at some geometry in a .g database.
 *
 * The primary BRL-CAD ray-tracing API consists of calls to the
 * function rt_shootray().  This function takes a single argument, the
 * address of a data structure called the "application" structure.
 * This data structure contains crucial information, such as the
 * origin and direction of the ray to be traced, what to do if the ray
 * hits geometry, or what to do if it misses everything.  While the
 * application struct is a large and somewhat complex looking, (it is
 * defined in the raytrace.h header) there are really very few items
 * in it which the application programmer must know about. These are:
 *
 *   a_rt_i	The "raytrace instance" obtained via rt_dirbuild()
 *   a_ray	The ray origin and direction to be shot
 *   a_hit	A callback function for when the ray encounters geometry
 *   a_miss	A callback function for when the ray misses everything
 *
 * Most of the work an application performs will be done in the "hit"
 * routine.  This user-supplied routine gets called deep inside the
 * raytracing library via the rt_shootray() function.  It is provided
 * with 3 parameters:
 *
 *   ap		Pointer to the application structure passed to rt_shootray()
 *   PartHeadp	List of ray "partitions" which represent geometry hit
 *   segp	List of ray "segments" that comprised partitions
 *
 * Most applications can ignore the last parameter.  The PartHeadp
 * parameter is a linked-list of "partition" structures (defined in
 * the raytrace.h header).  It is the job of the "hit" routine to
 * process these ray/object intersections to do the work of the
 * application.
 *
 * This file is part of the default compile in source distributions of
 * BRL-CAD and is usually installed or provided via binary and source
 * distributions.  To compile this example from a binary install:
 *
 * cc -I/usr/brlcad/include/brlcad -L/usr/brlcad/lib -o rtexample rtexample.c -lbu -lrt -lm
 *
 * Jump to the START HERE section below for main().
 */

#include "common.h"

#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdio.h>

#include "vmath.h"		/* vector math macros */
#include "raytrace.h"		/* librt interface definitions */


/**
 * rt_shootray() was told to call this on a hit.
 *
 * This callback routine utilizes the application structure which
 * describes the current state of the raytrace.
 *
 * This callback routine is provided a circular linked list of
 * partitions, each one describing one in and out segment of one
 * region for each region encountered.
 *
 * The 'segs' segment list is unused in this example.
 */
int
hit(struct application *ap, struct partition *PartHeadp, struct seg *UNUSED(segs))
{
    /* iterating over partitions, this will keep track of the current
     * partition we're working on.
     */
    struct partition *pp;

    /* will serve as a pointer for the entry and exit hitpoints */
    struct hit *hitp;

    /* will serve as a pointer to the solid primitive we hit */
    struct soltab *stp;

    /* will contain surface curvature information at the entry */
    struct curvature cur = RT_CURVATURE_INIT_ZERO;

    /* will contain our hit point coordinate */
    point_t pt;

    /* will contain normal vector where ray enters geometry */
     vect_t inormal;

    /* will contain normal vector where ray exits geometry */
    vect_t onormal;

    /* iterate over each partition until we get back to the head.
     * each partition corresponds to a specific homogeneous region of
     * material.
     */
    for (pp=PartHeadp->pt_forw; pp != PartHeadp; pp = pp->pt_forw) {

	/* print the name of the region we hit as well as the name of
	 * the primitives encountered on entry and exit.
	 */
	bu_log("\n--- Hit region %s (in %s, out %s)\n",
	       pp->pt_regionp->reg_name,
	       pp->pt_inseg->seg_stp->st_name,
	       pp->pt_outseg->seg_stp->st_name );

	/* entry hit point, so we type less */
	hitp = pp->pt_inhit;

	/* construct the actual (entry) hit-point from the ray and the
	 * distance to the intersection point (i.e., the 't' value).
	 */
	VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);

	/* primitive we encountered on entry */
	stp = pp->pt_inseg->seg_stp;

	/* compute the normal vector at the entry point, flipping the
	 * normal if necessary.
	 */
	RT_HIT_NORMAL(inormal, hitp, stp, &(ap->a_ray), pp->pt_inflip);

	/* print the entry hit point info */
	rt_pr_hit("  In", hitp);
	VPRINT(   "  Ipoint", pt);
	VPRINT(   "  Inormal", inormal);

	/* This next macro fills in the curvature information which
	 * consists on a principle direction vector, and the inverse
	 * radii of curvature along that direction and perpendicular
	 * to it.  Positive curvature bends toward the outward
	 * pointing normal.
	 */
	RT_CURVATURE(&cur, hitp, pp->pt_inflip, stp);

	/* print the entry curvature information */
	VPRINT("PDir", cur.crv_pdir);
	bu_log(" c1=%g\n", cur.crv_c1);
	bu_log(" c2=%g\n", cur.crv_c2);

	/* exit point, so we type less */
	hitp = pp->pt_outhit;

	/* construct the actual (exit) hit-point from the ray and the
	 * distance to the intersection point (i.e., the 't' value).
	 */
	VJOIN1(pt, ap->a_ray.r_pt, hitp->hit_dist, ap->a_ray.r_dir);

	/* primitive we exited from */
	stp = pp->pt_outseg->seg_stp;

	/* compute the normal vector at the exit point, flipping the
	 * normal if necessary.
	 */
	RT_HIT_NORMAL(onormal, hitp, stp, &(ap->a_ray), pp->pt_outflip);

	/* print the exit hit point info */
	rt_pr_hit("  Out", hitp);
	VPRINT(   "  Opoint", pt);
	VPRINT(   "  Onormal", onormal);
    }

    /* A more complicated application would probably fill in a new
     * local application structure and describe, for example, a
     * reflected or refracted ray, and then call rt_shootray() for
     * those rays.
     */

    /* Hit routine callbacks generally return 1 on hit or 0 on miss.
     * This value is returned by rt_shootray().
     */
    return 1;
}


/**
 * This is a callback routine that is invoked for every ray that
 * entirely misses hitting any geometry.  This function is invoked by
 * rt_shootray() if the ray encounters nothing.
 */
int
miss(struct application *UNUSED(ap))
{
    bu_log("missed\n");
    return 0;
}


/**
 * START HERE
 *
 * This is where it all begins.
 */
int
main(int argc, char **argv)
{
    /* Every application needs one of these.  The "application"
     * structure carries information about how the ray-casting should
     * be performed.  Defined in the raytrace.h header.
     */
    struct application	ap;

    /* The "raytrace instance" structure contains definitions for
     * librt which are specific to the particular model being
     * processed.  One copy exists for each model.  Defined in
     * the raytrace.h header and is returned by rt_dirbuild().
     */
    static struct rt_i *rtip;

    /* optional parameter to rt_dirbuild() that can be used to capture
     * a title if the geometry database has one set.
     */
    char title[1024] = {0};

    /* Check for command-line arguments.  Make sure we have at least a
     * geometry file and one geometry object on the command line.
     */
    if (argc < 3) {
	bu_exit(1, "Usage: %s model.g objects...\n", argv[0]);
    }

    /* Load the specified geometry database (i.e., a ".g" file).
     * rt_dirbuild() returns an "instance" pointer which describes the
     * database to be raytraced.  It also gives you back the title
     * string if you provide a buffer.  This builds a directory of the
     * geometry (i.e., a table of contents) in the file.
     */
    rtip = rt_dirbuild(argv[1], title, sizeof(title));
    if (rtip == RTI_NULL) {
	bu_exit(2, "Building the database directory for [%s] FAILED\n", argv[1]);
    }

    /* Display the geometry database title obtained during
     * rt_dirbuild if a title is set.
     */
    if (title[0]) {
	bu_log("Title:\n%s\n", title);
    }

    /* Walk the geometry trees.  Here you identify any objects in the
     * database that you want included in the ray trace by iterating
     * of the object names that were specified on the command-line.
     */
    while (argc > 2)  {
	if (rt_gettree(rtip, argv[2]) < 0)
	    bu_log("Loading the geometry for [%s] FAILED\n", argv[2]);
	argc--;
	argv++;
    }

    /* This next call gets the database ready for ray tracing.  This
     * causes some values to be precomputed, sets up space
     * partitioning, computes bounding volumes, etc.
     */
    rt_prep_parallel(rtip, 1);

    /* initialize all values in application structure to zero */
    RT_APPLICATION_INIT(&ap);

    /* your application uses the raytrace instance containing the
     * geometry we loaded.  this describes what we're shooting at.
     */
    ap.a_rt_i = rtip;

    /* stop at the first point of intersection or shoot all the way
     * through (defaults to 0 to shoot all the way through).
     */
    ap.a_onehit = 0;

    /* Set the ray start point and direction rt_shootray() uses these
     * two to determine what ray to fire.  In this case we simply
     * shoot down the z axis toward the origin from 10 meters away.
     *
     * It's worth nothing that librt assumes units of millimeters.
     * All geometry is stored as millimeters regardless of the units
     * set during editing.  There are libbu routines for performing
     * unit conversions if desired.
     */
    VSET(ap.a_ray.r_pt, 0.0, 0.0, 10000.0);
    VSET(ap.a_ray.r_dir, 0.0, 0.0, -1.0);

    /* Simple debug printing */
    VPRINT("Pnt", ap.a_ray.r_pt);
    VPRINT("Dir", ap.a_ray.r_dir);

    /* This is what callback to perform on a hit. */
    ap.a_hit = hit;

    /* This is what callback to perform on a miss. */
    ap.a_miss = miss;

    /* Shoot the ray. */
    (void)rt_shootray(&ap);

    /* A real application would probably set up another ray and fire
     * again or do something a lot more complex in the callbacks.
     */

    return 0;
}

/*
 * Local Variables:
 * mode: C
 * tab-width: 8
 * indent-tabs-mode: t
 * c-file-style: "stroustrup"
 * End:
 * ex: shiftwidth=4 tabstop=8
 */