home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume21 / rayshade / part07 < prev    next >
Encoding:
Internet Message Format  |  1990-03-21  |  22.6 KB

  1. Subject:  v21i014:  A ray tracing program, Part07/08
  2. Newsgroups: comp.sources.unix
  3. Sender: sources
  4. Approved: rsalz@uunet.UU.NET
  5.  
  6. Submitted-by: Craig Kolb <craig@weedeater.math.yale.edu>
  7. Posting-number: Volume 21, Issue 14
  8. Archive-name: rayshade/part07
  9.  
  10. #! /bin/sh
  11. # This is a shell archive.  Remove anything before this line, then unpack
  12. # it by saving it into a file and typing "sh file".  To overwrite existing
  13. # files, type "sh file -c".  You can also feed this as standard input via
  14. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  15. # will see the following message at the end:
  16. #        "End of archive 7 (of 8)."
  17. # Contents:  doc/primitive.ms
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'doc/primitive.ms' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'doc/primitive.ms'\"
  21. else
  22. echo shar: Extracting \"'doc/primitive.ms'\" \(20923 characters\)
  23. sed "s/^X//" >'doc/primitive.ms' <<'END_OF_FILE'
  24. X
  25. X.\"
  26. X.\" Brief tutorial on adding new primitives to rayshade.
  27. X.\" Craig Kolb 10/89
  28. X.\"
  29. X.\" $Id: primitive.ms,v 3.0 89/10/24 18:07:30 craig Exp $
  30. X.\"
  31. X.\" $Log:    primitive.ms,v $
  32. X.\" Revision 3.0  89/10/24  18:07:30  craig
  33. X.\" Baseline for first official release.
  34. X.\" 
  35. X.de D(
  36. X.DS
  37. X.nr PS 8 
  38. X.ps 8 
  39. X.nr VS 12p
  40. X.vs 12p
  41. X.cs 1 20 
  42. X..
  43. X.de D)
  44. X.DE
  45. X.nr PS 10
  46. X.ps 10
  47. X.nr VS 18p
  48. X.vs 18p
  49. X.cs 1
  50. X..
  51. X.DS
  52. X.ND October, 1989
  53. X.RP
  54. X.de ]H
  55. X.nr PS 10
  56. X.ps 10
  57. X'sp |0.5i-1
  58. X.tl 'Rayshade Primitive Tutorial'-%-'Draft'
  59. X.ps
  60. X.ft
  61. X'sp |1.0i
  62. X.ns
  63. X..
  64. X.wh0 ]H
  65. X.pn 2
  66. X.LP
  67. X.TL
  68. XAdding Primitives to Rayshade
  69. X.TL
  70. X\fR\fIDraft\fR
  71. X.AU
  72. XCraig Kolb
  73. X.AI
  74. XDepartment of Mathematics
  75. XYale University
  76. XNew Haven, CT  06520
  77. X.sp .5i
  78. X.nr VS 18pts
  79. X.PP
  80. XThis tutorial describes the process of adding new primitives to
  81. Xrayshade.  Although the hooks for adding primitives are relatively
  82. Xstraight-forward, it is difficult to see the "big picture" by 
  83. Xstudying the source code.  While this tutorial is primarily
  84. Xmeant for those interested getting their hands dirty, it
  85. Xprovides a overview of the design of at least one portion
  86. Xof rayshade and thus may be of interest even if you are not
  87. Xplanning on making modifications.
  88. X.LP
  89. XAdding a new primitive involves modifying at least six source
  90. Xfiles and creating at least one new file:
  91. X.NH
  92. Xprimobj.h
  93. X.LP
  94. XA datatype for the new primitive is added, and a pointer for
  95. Xthe new type is added to the Primitive type.
  96. X.NH
  97. Xconstants.h
  98. X.LP
  99. XA numerical type is reserved for the primitive.
  100. X.NH
  101. Xintersect.c
  102. X.LP
  103. XVarious arrays of pointers to functions are modified to include
  104. Xnew functions which will be written for the new primitive.
  105. XThe name of the new primitive is added to a list of names,
  106. Xand an array of flags is modified to reflect the addition of
  107. Xthe new primitive.
  108. X.NH
  109. Xfuncdefs.h
  110. X.LP
  111. XThe ray-primitive intersection function, primitive creation
  112. Xfunction, normal calculation function, and bounding-box 
  113. Xcalculation function are declared.
  114. X.NH
  115. X<primitive-type>.c
  116. X.LP
  117. XThis file contains
  118. Xall of the code needed to perform
  119. Xray-primitive intersection tests, find normals, and compute
  120. Xbounding boxes for the new primitive type.
  121. X.NH
  122. Xinput_lex.l
  123. X.LP
  124. XThe keyword used to identify the new primitive is added to
  125. Xthe list of recognized keywords.
  126. X.NH
  127. Xinput_yacc.y
  128. X.LP
  129. XThe new primitive is added to the list of primitives recognized by
  130. Xthe yacc grammar.  The added code will call the routine
  131. Xwhich creates and returns a reference to the primitive
  132. Xwhich was defined in <primitive-type>.c
  133. X.LP
  134. XIn addition, the Makefile must be updated to reflect the existence of the
  135. Xnew source file.
  136. X.sp 1
  137. X.LP
  138. XIn this tutorial, a new primitive
  139. X.I disc,
  140. Xis added to rayshade.  A disc is specified by its center, radius,
  141. Xand normal.
  142. X.br
  143. X.NR PS 12
  144. X.ps 12
  145. X.sp .5
  146. X\fBThe Primitive type\fR
  147. X.nr PS 10
  148. X.ps 10
  149. X.sp .5
  150. X.LP
  151. XAll Primitives in rayshade are referenced using a single Primitive structure.
  152. XThis structure is defined as:
  153. X.D(
  154. Xtypedef struct Primitive {
  155. X        char type;                      /* object type */
  156. X        struct Surface *surf;           /* default surface */
  157. X        union {
  158. X                Sphere          *p_sphere;
  159. X                Box             *p_box;
  160. X                Triangle        *p_triangle;
  161. X                Superq          *p_superq;
  162. X                Plane           *p_plane;
  163. X                Cylinder        *p_cylinder;
  164. X                Polygon         *p_poly;
  165. X                Cone            *p_cone;
  166. X                Hf              *p_hf;
  167. X        } objpnt;                      /* Pointer to primitive */
  168. X} Primitive;
  169. X.D)
  170. X.LP
  171. XThe
  172. X.I type
  173. Xfield is used by various routines in intersect.c to determine
  174. Xwhich elements in a number of arrays should be used when dealing with
  175. Xa given Primitive structure.
  176. XThe
  177. X.I surf
  178. Xfield points to the surface associated with the primitive.
  179. XThe
  180. X.I objpnt
  181. Xfield is a union of pointers to different primitive types.
  182. XThe
  183. X.I type
  184. Xof the Primitive is used to determine which pointer to
  185. Xdereference.
  186. X.NH 0
  187. XModifying primobj.h
  188. X.LP
  189. XPrimobj contains structures describing each primitive type.  For example,
  190. Xa sphere is defined as:
  191. X.D(
  192. Xtypedef struct {
  193. X        double r;               /* radius   */
  194. X        double x, y, z;         /* position */
  195. X} Sphere;
  196. X.D)
  197. XWe must define a similar structure for the disc primitive.  After the
  198. Xdefinition of the Hf type, we add:
  199. X.D(
  200. X/*
  201. X * Disc
  202. X */
  203. Xtypedef struct {
  204. X        Vector  center,         /* Center of the disc */
  205. X                normal;         /* Normal to disc */
  206. X        double  d,              /* Plane constant */
  207. X                radius;         /* Radius of disc */
  208. X} Disc;
  209. X.D)
  210. X.LP
  211. XWe must also add a pointer for the Disc type to the Primitive type.
  212. XSo, we add a line to the \fIobjpnt\fR union in the Primitive definition,
  213. Xgiving us: 
  214. X.D(
  215. Xtypedef struct Primitive {
  216. X        char type;             /* object type */
  217. X        struct Surface *surf;  /* default surface */
  218. X        union {
  219. X                Sphere          *p_sphere;
  220. X                Box             *p_box;
  221. X                Triangle        *p_triangle;
  222. X                Superq          *p_superq;
  223. X                Plane           *p_plane;
  224. X                Cylinder        *p_cylinder;
  225. X                Polygon         *p_poly;
  226. X                Cone            *p_cone;
  227. X                Hf              *p_hf;
  228. X                Disc            *p_disc;
  229. X        } objpnt;             /* Pointer to primitive */
  230. X} Primitive;
  231. X.D)
  232. X.NH
  233. XModifying constants.h 
  234. X.LP
  235. XIn constants.h, there are a series of lines resemblin:
  236. X.D(
  237. X#define SPHERE          0
  238. X#define BOX             1
  239. X#define TRIANGLE        2
  240. X#define SUPERQ          3
  241. X#define PLANE           4
  242. X#define CYL             5
  243. X#define POLY            6
  244. X#define PHONGTRI        7
  245. X#define CONE            8
  246. X#define HF              9
  247. X#define LIST            10
  248. X#define GRID            11
  249. X.D)
  250. X.LP
  251. XThese lines define the values assigned to the 'type' field in each
  252. XPrimitive and Object.  (Actually, a Primitive can never be of type
  253. XLIST or GRID, but an Object may be.)  We must add a similar line for
  254. Xthe new primitive.
  255. X.LP
  256. XWhen adding new values, we
  257. X.I must
  258. Xadd the primitive
  259. X.I before
  260. Xthe
  261. Xlines defining the types for LIST and GRID.  This is due to the way
  262. Xarrays are indexed in intersect.c  So, below the HF type, we add a line
  263. Xfor the Disc type and increment the LIST and GRID types:
  264. X.D(
  265. X#define CONE            8
  266. X#define HF              9
  267. X#define DISC            10
  268. X#define LIST            11
  269. X#define GRID            12
  270. X.D)
  271. XWe must also increment PRIMTYPES, the total number of primitives types:
  272. X.D(
  273. X#define PRIMTYPES       11
  274. X.D)
  275. X.NH
  276. XModifying intersect.c
  277. X.LP
  278. XIn intersect.c, several arrays are declared and initialized which are indexed
  279. Xby Primitive or Object type.  We must modify these array declarations
  280. Xto reflect the addition of the new primitive type.  The first array to
  281. Xbe modified is :
  282. X.D(
  283. Xdouble (*objint[])() = {intsph, intbox, inttri, intsup, intplane, intcyl,
  284. X                        intpoly, inttri, intcone, inthf};
  285. X.D)
  286. XThis array of pointers to functions contains the names of the functions
  287. Xwhich perform ray/primitive intersection tests.  Here,
  288. X.I intsph,
  289. Xthe
  290. X0th element in the array, is the name of the intersection routine
  291. Xfor the Sphere primitive, which is declared as type 0 in constants.h.
  292. XSimilarly,
  293. X.I intplane
  294. Xis the 4th element in the array, and the Plane
  295. Xprimitive is defined to be type 4.  This is due to the fact that a
  296. XPrimitive's type field is used as an index into this array.
  297. X.LP
  298. XSo, we must add the name of the new ray/disc intersection test, which
  299. Xwe will name "intdisc", to the objint[] array:
  300. X.D(
  301. Xdouble (*objint[])() = {intsph, intbox, inttri, intsup, intplane, intcyl,
  302. X                        intpoly, inttri, intcone, inthf, intdisc};
  303. X.D)
  304. XSimilarly, we must modify the objnrm[] and objextent[] arrays to contain
  305. Xthe names of the functions that compute a specific disc's normal and
  306. Xbounding box:
  307. X.D(
  308. Xint (*objnrm[])() = {nrmsph, nrmbox, nrmtri, nrmsup, nrmplane, nrmcyl,
  309. X                     nrmpoly, nrmtri, nrmcone, nrmhf, nrmdisc};
  310. X
  311. Xint (*objextent[])() = {sphextent, boxextent, triextent, supextent,
  312. X                        planeextent, cylextent, polyextent, triextent,
  313. X                        coneextent, hfextent, discextent};
  314. X.D)
  315. X.LP
  316. XIn addition, there is an array of Primitive names which is used when
  317. Xprinting statistics.  Again, we need to modify the array to include
  318. Xthe name of the Disc primitive:
  319. X.D(
  320. Xchar *primnames[PRIMTYPES] = {  "Sphere", "Box", "Triangle", "Superq", "Plane",
  321. X                                "Cylinder", "Polygon", "Phongtri", "Cone",
  322. X                                "Heightfield", "Disc"};
  323. X.D)
  324. X.LP
  325. XLastly, there is an array of flags named CheckBounds[] which is indexed
  326. Xby Object type.  This array is used by intersect() to determine if
  327. Xa ray/bounding-box intersection test should be performed before a ray/Object
  328. Xintersection test.  If the element in CheckBounds[] corresponding to
  329. Xan Object's type is TRUE, a ray/Object intersection test will only occur
  330. Xif a ray/bounding-box intersection test succeeds.  (Even if ray/bounding-box
  331. Xtests are not performed for a given primitive, the bounding box is still
  332. Xused to determine the extent of the object when it is included in compound 
  333. XObjects.)
  334. X.LP
  335. XWe will set the flag corresponding to the Disc primitive to be TRUE.   Note
  336. Xthat the CheckBounds array is indexed by \fIObject\fR type, so we add the
  337. Xentry for the Disc type before the final two entries in the array:
  338. X.D(
  339. Xchar CheckBounds[] = {TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, TRUE, TRUE,
  340. X                      TRUE, FALSE, TRUE, FALSE, FALSE};
  341. X.D)
  342. X.NH
  343. XModifying funcdefs.h
  344. X.LP
  345. XThe file funcdefs.h contains a number of function declarations.  We must add
  346. Xdeclarations for the four new functions to be written.  Firstly,
  347. Xwe add the declaration of "nrmdisc" to the normal-finding functions:
  348. X.D(
  349. Xint    nrmsph(), nrmbox(), nrmtri(), nrmsup(),nrmplane(), nrmcyl(),
  350. X        nrmpoly(), nrmcone(), nrmhf(), nrmdisc();
  351. X.D)
  352. X.LP
  353. XNext, we declare "intdisc" with the other ray/primitive intersection
  354. Xtest functions:
  355. X.D(
  356. X/*
  357. X * Intersection routines
  358. X */
  359. Xdouble  intsph(), intbox(), inttri(), intsup(),intplane(), crossp(), intcyl(),
  360. X          intpoly(), intcone(), inthf(), intdisc();
  361. X.D)
  362. XAnd the bounding-box routine:
  363. X.D(
  364. X/*
  365. X * Extent-box finding routines
  366. X */
  367. Xint     sphextent(),boxextent(),triextent(),supextent(),planeextent(),
  368. X        cylextent(), polyextent(), coneextent(), hfextent(),
  369. X        discextent();
  370. X.D)
  371. X.LP
  372. XAnd lastly, we add "makdisc", the routine which will create a reference
  373. Xto a particular disc, to the list of object creation functions:
  374. X.D(
  375. X/*
  376. X * Object creation routines
  377. X */
  378. XObject *maksph(), *makbox(), *maktri(), *maksup(), *makplane(), *makcyl(),
  379. X         *makpoly(), *makcone(), *makhf(), *makdisc(), *new_object()
  380. X.D)
  381. X.NH
  382. XWriting disc.c
  383. X.LP
  384. XAnd now we must write the four functions makdisc(), intdisc(), nrmdisc()
  385. Xand discextent().  The first thing you should do is copy
  386. Xthe Copyright
  387. Xtemplate to the top of disc.c.
  388. X.LP
  389. XNext, we need to #include the necessary header files.  In addition to math.h
  390. Xand stdio.h, you will need "constants.h" (which includes the definition
  391. Xof DISC), "typedefs.h" (which includes all sorts of useful structure
  392. Xdefinitions), and "funcdefs.h" (which includes all sorts of useful
  393. Xfunction declarations).
  394. X.NH 2
  395. Xmakdisc()
  396. X.LP
  397. XEvery primitive-creation function must take a least one argument -- the
  398. Xname of the surface to be associated with the primitive.  Besides this
  399. Xargument, these functions will be passed any parameters needed to define
  400. Xa particular primitive.  For us, this means two vectors (the center of
  401. Xthe disc and its normal) and one double (the radius of the disc).
  402. X.LP
  403. XThe makdisc() routine will do several things.  In addition to creating a new
  404. XDisc, it must allocate a Primitive structure and set its fields
  405. Xappropriately -- it must point to the new Disc, have its "type" field
  406. Xset correctly, and it must point to the surface associated with the
  407. Xprimitive.  In addition, an Object which points to this new Primitive
  408. Xmust be created and initialized properly.  It is this Object structure
  409. Xwhich is returned by makdisc().
  410. X.LP
  411. XSo, we write:
  412. X.D(
  413. XObject *
  414. Xmakdisc(surf, center, radius, norm)
  415. Xchar *surf;
  416. XVector center, norm;
  417. Xdouble radius;
  418. X{
  419. X        Disc *disc;             /* Pointer to new disc. */
  420. X        Primitive *prim;        /* Pointer to new Primitive */
  421. X        Object *newobj;         /* Pointer to new Object */
  422. X        Vector tmpnorm;         /* normalized normal */
  423. X        extern int Quiet;       /* True if we shouldn't complain */
  424. X        extern int yylineno;    /* Current line # in input file. */
  425. X
  426. X        if (radius < EPSILON) {
  427. X                if (!Quiet)
  428. X                        fprintf(stderr,"Degenerate disc (line %d).\\n",
  429. X                                        yylineno);
  430. X                /*
  431. X                 * Don't create this primitive.
  432. X                 */
  433. X                return (Object *)0;
  434. X        }
  435. X
  436. X        tmpnorm = norm;
  437. X        if (normalize(&tmpnorm) == 0.) {
  438. X                if (!Quiet)
  439. X                        fprintf(stderr,"Degenerate disc normal (line %d).\\n",
  440. X                                        yylineno);
  441. X                return (Object *)0;
  442. X        }
  443. X        /*
  444. X         * Allocate new Disc.
  445. X         */
  446. X        disc = (Disc *)Malloc(sizeof(Disc));
  447. X        /*
  448. X         * Initialize new disc.
  449. X         * We store the square of the radius to save us a sqrt().
  450. X         */
  451. X        disc->radius = radius*radius;
  452. X        disc->center = center;
  453. X        disc->normal = tmpnorm;
  454. X        /*
  455. X         * Compute plane constant.
  456. X         */
  457. X        disc->d = dotp(¢er, &tmpnorm);
  458. X        /*
  459. X         * Allocate new Primitive
  460. X         */
  461. X        prim = mallocprim();
  462. X        /*
  463. X         * Set Primitive type and pointer to new Disc.
  464. X         */
  465. X        prim->type = DISC;
  466. X        prim->objpnt.p_disc = disc;
  467. X        /*
  468. X         * Search for named surface in list of defined surfaces.
  469. X         * find_surface() will exit if the surface is not found.
  470. X         */
  471. X        prim->surf = find_surface(surf);
  472. X        /*
  473. X         * Create and return new object with NULL name, of type DISC,
  474. X         * which points to the new Primitive and has no transformation
  475. X         * associated with it.
  476. X         */
  477. X        return new_object(NULL, DISC, (char *)prim, (Trans *)NULL);
  478. X}
  479. X.D)
  480. X.LP
  481. XIn this case, our primitive creation function is straight-forward.  In
  482. Xsome cases, in order to facilitate ray-primitive intersection tests,
  483. Xa more general version of the primitive is created, and a transformation
  484. Xmatrix is computed to transform the generic primitive to the specific
  485. Xprimitive requested by the user.  Then, one need only perform
  486. Xintersection tests against the generic version of the primitive.  Examples
  487. Xof these types of primitives are the cone and cylinder.  The generic
  488. Xversions of both of these primitives have their main axes coincident
  489. Xwith the Z axis and their base at the origin.  Transformations are
  490. Xcomputed in makcyl() and makcone() to transform the generic case to
  491. Xthe specific case.  See "cone.c", "cylinder.c" and "input_yacc.y" for
  492. Xdetails.
  493. X.NH 2
  494. Xintdisc()
  495. X.LP
  496. XEach primitive/ray intersection routine is passed three values:
  497. Xa pointer to a Primitive, the origin of the ray, and the direction of
  498. Xthe ray.  Each intersection function must do two things.  Firstly,
  499. Xit must increment an element in the primtests[] array to reflect the
  500. Xfact that a ray/primitive intersection test has occurred.  Most importantly,
  501. Xeach function must return the distance from the ray origin along the
  502. Xray direction to the closest point of ray/primitive intersection.  This
  503. Xdistance must be greater than EPSILON.  If it is less than EPSILON, it is
  504. Xassumed that no intersection occurs between the ray and the given primitive.
  505. XIf not valid intersection exists, 0 is returned.
  506. X.LP
  507. XSo, we write:
  508. X.D(
  509. Xdouble
  510. Xintdisc(pos, ray, obj)
  511. XVector *pos, *ray;
  512. XPrimitive *obj;
  513. X{
  514. X        Disc *disc;
  515. X        Vector hit;
  516. X        double denom, dist;
  517. X        extern unsigned long primtests[];
  518. X
  519. X        primtests[DISC]++;
  520. X        disc = obj->objpnt.p_disc;
  521. X
  522. X        denom = dotp(&disc->normal, ray);
  523. X        if (denom == 0.)
  524. X                return 0.;
  525. X        dist = (disc->d - dotp(&disc->normal, pos)) / denom;
  526. X        if (dist > FAR_AWAY || dist < EPSILON)
  527. X                return 0.;
  528. X        /*
  529. X         *  Find difference between point of intersection and center of disc.
  530. X         */
  531. X        vecsub(addscaledvec(*pos, dist, *ray), disc->center, &hit);
  532. X        /*
  533. X         * If hit point is <= disc->radius from center, we've hit the disc.
  534. X         */
  535. X        if (dotp(&hit, &hit) <= disc->radius)
  536. X                return dist;
  537. X        return 0.;
  538. X}
  539. X.D)
  540. X.NH 2
  541. Xnrmdisc()
  542. X.LP
  543. XEach primitive normal routine is passed a location to a primitive, a pointer
  544. Xto a point on the surface of the primitive, and a pointer to a vector
  545. Xwhich must be set to the normal to the primitive at the point of intersection.
  546. XFor the disc, this is very simple, as the disc is planar:
  547. X.D(
  548. XVector
  549. Xnrmdisc(pos, prim, nrm)
  550. XVector *pos, *nrm;
  551. XPrimitive *prim;
  552. X{
  553. X        *nrm = prim->objpnt.p_disc->normal;
  554. X}
  555. X.D)
  556. X.NH 2
  557. Xdiscextent()
  558. X.LP
  559. XThe discextent() routine is passed a pointer to a disc Primitive as well
  560. Xas a bounding
  561. Xbox stored as a 2 by 3 array of doubles.  The routine computes the extent
  562. Xof the disc along each axis and fills the bounding box array appropriately.
  563. X.LP
  564. XNote that the bounding box of all primitives should be at least
  565. X2*EPSILON along each axis to avoid problems with roundoff error.
  566. XFortunately, primextent(),
  567. Xroutine which calls the primitive bounding box functions, will check
  568. Xfor and "widen" degenerate bounding boxes.
  569. XThus, the
  570. Xbounding box volumes are allowed to compute degenerate boxes.
  571. XAlso, if a primitive is unbounded (e.g., a plane),
  572. Xthe maximum X extent should be set to be less than the minimum X extent.
  573. X.LP
  574. XSo, discextent is written as:
  575. X.D(
  576. Xdiscextent(prim, bounds)
  577. XPrimitive *prim;
  578. Xdouble bounds[2][3];
  579. X{
  580. X        Disc *disc;
  581. X        double extent, rad;
  582. X
  583. X        disc = prim->objpnt.p_disc;
  584. X
  585. X        rad = sqrt(disc->radius);
  586. X        /*
  587. X         * Project disc along each of X, Y and Z axes.
  588. X         */
  589. X        extent = 1. - disc->normal.x * disc->normal.x;
  590. X        extent *= rad;
  591. X        bounds[LOW][X] = disc->center.x - extent;
  592. X        bounds[HIGH][X] = disc->center.x + extent;
  593. X        extent = 1. - disc->normal.y * disc->normal.y;
  594. X        extent *= rad;
  595. X        bounds[LOW][Y] = disc->center.y - extent;
  596. X        bounds[HIGH][Y] = disc->center.y + extent;
  597. X        extent = 1. - disc->normal.z * disc->normal.z;
  598. X        extent *= rad; 
  599. X        bounds[LOW][Z] = disc->center.z - extent;
  600. X        bounds[HIGH][Z] = disc->center.z + extent;
  601. X}
  602. X.D)
  603. X.NH
  604. Xinput_lex.l
  605. X.LP
  606. XAmong other things, input_lex.l contains a list of all the keywords
  607. Xrecognized by rayshade.  To this list we must add the keyword for
  608. Xthe new primitive type.  Following the example of other keywords,
  609. Xwe add:
  610. X.D(
  611. Xdisc                            {return(tDISC);}
  612. X.D)
  613. X.NH
  614. Xinput_yacc.y
  615. X.LP
  616. XNear the top of input_yacc.y are the declarations for the tokens
  617. Xreturned by lex.  We must add the new token, tDISC, to this list:
  618. X.D(
  619. X%token tBACKGROUND tBLOTCH tBOX tBUMP tCONE tCYL tDIRECTIONAL tDISC
  620. X.D)
  621. XFinally, we need to add the production to the yacc grammar which will
  622. Xcall makdisc().  We first modify the Primtype production to include
  623. Xa new production named Disc:
  624. X.D(
  625. XPrimtype        : Plane
  626. X                | Sphere
  627. X                | Box
  628. X                | Triangle
  629. X                | Cylinder
  630. X                | Cone
  631. X                | Superq
  632. X                | Poly
  633. X                | HeightField
  634. X                | Disc
  635. X                ;
  636. X.D)
  637. X.LP
  638. XNext, near the productions for the other primitives, we add:
  639. X.D(
  640. XDisc            : tDISC tSTRING Vector Fnumber Vector
  641. X                {
  642. X                        /*
  643. X                         * disc surfname center.x center.y center.z
  644. X                         * radius norm.x norm.y norm.z
  645. X                         */
  646. X                        LastObj = maksph($2, $3, $4, $5);
  647. X                }
  648. X                ;
  649. X.D)
  650. X.NH
  651. XTesting
  652. X.LP
  653. XOnce you add "disc.o" to the OBJS list in the Makefile, you should be
  654. Xable to re-compile rayshade.  A good input file for testing the disc
  655. Xprimitive might be:
  656. X.D(
  657. X/*
  658. X * Demo picture of a textured ground plane with a sphere, cone
  659. X * and disc.  The disc is situated on the top of the cone and faces
  660. X * up and towards the viewer.
  661. X */
  662. Xeyep 0. 25. 7.
  663. Xscreen 256 256
  664. Xlight 1.4 point -15. 20. 15.
  665. Xsurface red .02 0 0 .5 0 0 .2 .2 .2 32. 0.0 0 0
  666. Xsurface blacktile 0.01 0.015 0.01 0.02 0.03 0.02 0.3 0.35 0.3 30 0. 0 0
  667. Xsurface white .02 .02 .008 .5 .5 .25 0.8 0.8 0.8 18 0. 0 0
  668. Xsurface glass 0.02 0.02 0.02  0. 0. 0.  0.8 0.8 0.8  25 0. 0. 1.15
  669. X
  670. Xdisc white -5. 3. 4. 3. 0. 1. 1.
  671. Xsphere red 4. 3 0 0
  672. X/*
  673. X * Cone actually sticks through ground plane.  This solves problems
  674. X * that arise when the bottom of the cone and the plane are coincident.
  675. X */
  676. Xcone glass -5. 3 -4.1 -5. 3. 4. 4. 0.
  677. X
  678. X
  679. Xplane white 0. 0. 1. 0. 0. -4. 
  680. X        texture marble scale 4. 4. 4.
  681. X        texture checker blacktile translate 0. 0. 0.3 scale 4. 4. 4.
  682. X.D)
  683. END_OF_FILE
  684. if test 20923 -ne `wc -c <'doc/primitive.ms'`; then
  685.     echo shar: \"'doc/primitive.ms'\" unpacked with wrong size!
  686. fi
  687. # end of 'doc/primitive.ms'
  688. fi
  689. echo shar: End of archive 7 \(of 8\).
  690. cp /dev/null ark7isdone
  691. MISSING=""
  692. for I in 1 2 3 4 5 6 7 8 ; do
  693.     if test ! -f ark${I}isdone ; then
  694.     MISSING="${MISSING} ${I}"
  695.     fi
  696. done
  697. if test "${MISSING}" = "" ; then
  698.     echo You have unpacked all 8 archives.
  699.     rm -f ark[1-9]isdone
  700. else
  701.     echo You still need to unpack the following archives:
  702.     echo "        " ${MISSING}
  703. fi
  704. ##  End of shell archive.
  705. exit 0
  706.  
  707.  
  708.