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

  1. Subject:  v21i012:  A ray tracing program, Part05/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 12
  8. Archive-name: rayshade/part05
  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 5 (of 8)."
  17. # Contents:  doc/texture.ms src/grid.c src/matrix.c src/shade.c
  18. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  19. if test -f 'doc/texture.ms' -a "${1}" != "-c" ; then 
  20.   echo shar: Will not clobber existing file \"'doc/texture.ms'\"
  21. else
  22. echo shar: Extracting \"'doc/texture.ms'\" \(13859 characters\)
  23. sed "s/^X//" >'doc/texture.ms' <<'END_OF_FILE'
  24. X.\"
  25. X.\" Brief tutorial on adding textures to rayshade.
  26. X.\" Craig Kolb 10/89
  27. X.\"
  28. X.\" $Id: texture.ms,v 3.0 89/10/23 16:42:57 craig Exp $
  29. X.\"
  30. X.\" $Log:    texture.ms,v $
  31. X.\" Revision 3.0  89/10/23  16:42:57  craig
  32. X.\" Baseline for first official release.
  33. X.\" 
  34. X.de D(
  35. X.DS
  36. X.nr PS 8 
  37. X.ps 8 
  38. X.nr VS 12p
  39. X.vs 12p
  40. X.cs 1 20 
  41. X..
  42. X.de D)
  43. X.DE
  44. X.nr PS 10
  45. X.ps 10
  46. X.nr VS 18p
  47. X.vs 18p
  48. X.cs 1
  49. X..
  50. X.DS
  51. X.ND October, 1989
  52. X.RP
  53. X.de ]H
  54. X.nr PS 10
  55. X.ps 10
  56. X'sp |0.5i-1
  57. X.tl 'Rayshade Texture Tutorial'-%-'Draft'
  58. X.ps
  59. X.ft
  60. X'sp |1.0i
  61. X.ns
  62. X..
  63. X.wh0 ]H
  64. X.pn 2
  65. X.LP
  66. X.TL
  67. XAdding Textures to Rayshade
  68. X.TL
  69. X\fR\fIDraft\fR
  70. X.AU
  71. XCraig Kolb
  72. X.AI
  73. XDepartment of Mathematics
  74. XYale University
  75. XNew Haven, CT  06520
  76. X.sp .5i
  77. X.nr VS 18pts
  78. X.PP
  79. XThis tutorial describes the process of adding new textures to
  80. Xrayshade.  Although the texturing interface is relatively
  81. Xstraight-forward, it is difficult to see the "big picture" by 
  82. Xstudying the source code, as changes must be made in a
  83. Xnumber of different files.  While this tutorial is primarily 
  84. Xmeant for those interested getting their hands dirty, and
  85. Xassumes familiarity with solid texturing,
  86. Xit provides a overview of the design of at least one portion
  87. Xof rayshade and thus may be of interest even if you are not
  88. Xplanning on making modifications.
  89. X.LP
  90. XAdding new textures to rayshade involves modifying at least
  91. Xfour source files:
  92. X.NH texture.h
  93. Xtexture.h
  94. X.LP
  95. XA numerical type is given to the texture.  The routines to
  96. Xcreate a reference to the new texture and the texturing function
  97. Xitself are declared.
  98. X.NH
  99. Xtexture.c
  100. X.LP
  101. XAt least two new routines are added.  The first creates and
  102. Xreturns a reference to a texture of the given type, and the
  103. Xsecond performs the actual texturing.  In addition, an
  104. Xarray of pointers to functions is modified to include the
  105. Xnew texturing function.
  106. X.NH
  107. Xinput_lex.l
  108. X.LP
  109. XThe keyword used to identify the new texture is added to
  110. Xthe list of recognized keywords.
  111. X.NH
  112. Xinput_yacc.y
  113. X.LP
  114. XThe new texture is added to the list of textures parsed by
  115. Xthe yacc grammar.  The added code will call the routine
  116. Xwhich creates and returns a reference to the texture type
  117. Xwhich was defined in texture.c
  118. X.PP
  119. XIn this tutorial, a new texture, 
  120. X.I mountain,
  121. Xis added to rayshade.  This
  122. Xtexture will modify the diffuse component of a surface as a function of the
  123. XZ component of the point of intersection.  If the name of a colormap
  124. Xis given, an index into
  125. Xthe colormap is used to a color to be used as the diffuse component the
  126. Xsurface.
  127. XOtherwise, the diffuse component of the surface is simply scaled.
  128. XTo avoid strictly horizontal boundries
  129. Xbetween colors when using a colormap, we add a bit of "noise" to the
  130. XZ component of the point of intersection.  The magnitude and nature of the
  131. Xnoise
  132. Xis defined by the user.
  133. X.br
  134. X.NR PS 12
  135. X.ps 12
  136. X.sp .5
  137. X\fBThe Texture type\fR
  138. X.nr PS 10
  139. X.ps 10
  140. X.sp .5
  141. X.LP
  142. XAll textures in rayshade are referenced using a single Texture structure.
  143. XThis structure is defined as:
  144. X.D(
  145. Xtypedef struct Texture {
  146. X        char type;              /* Texture type */
  147. X        Surface *surf1;         /* Alternate surface */
  148. X        double size;            /* Scale/size factor */
  149. X        double *args;           /* Random arguments. */
  150. X        Color *colormap;        /* Colormap */
  151. X        Trans *trans;           /* Transformation matrices. */
  152. X        struct Texture *next;   /* Pointer to next texture. */
  153. X} Texture;
  154. X.D)
  155. X.LP
  156. XThe 
  157. X.I type
  158. Xfield is used by apply_textures() to determine which texturing
  159. Xfunction to call.  The
  160. X.I trans
  161. Xfield and 
  162. X.I next
  163. Xfield are used internally
  164. Xby rayshade.
  165. X.LP
  166. XThe rest of the fields are for use by the texturing functions.
  167. X.LP
  168. XThe
  169. X.I args
  170. Xfield provides a pointer to space for storing an arbitrary
  171. Xnumber of floating-point parameters.  The
  172. X.I size
  173. Xfield is a handy
  174. Xgeneral-purpose floating-point value (the idea being that you get
  175. Xone parameter "free"
  176. Xwith every Texture structure).
  177. XThe
  178. X.I colormap
  179. Xfield is generally used to store an array of Colors read from
  180. Xan ascii colormap file.
  181. XThe
  182. X.I surf1
  183. Xfield is often set to point to a secondary surface.  This is
  184. Xuseful if the texture performs some sort of interpolation between two
  185. Xsurfaces -- the first being the surface assigned to the object being textured
  186. Xand the second specified as an argument to the texture
  187. X(e.g., the blotch texture). 
  188. Xfor an example).
  189. X.NH 0
  190. XModifying texture.h
  191. X.LP
  192. XThe file texture.h contains a list of #defines which look something like:
  193. X.D(
  194. X#define CHECKER         0       /* Checkerboard */
  195. X#define BLOTCH          1       /* Color blotches */
  196. X#define BUMP            2       /* Bump mapping */
  197. X#define MARBLE          3       /* marble texture */
  198. X#define FBM             4       /* fBm texture */
  199. X#define FBMBUMP         5       /* fBm bump map */
  200. X#define WOOD            6       /* wood-like texture */
  201. X.D)
  202. X.LP
  203. XThese numerical types are used to identify the type of a given
  204. Xtexture structure (via the
  205. X.I type
  206. Xfield in the Texture structure).
  207. XWe need to add a similar definition for our new texture.
  208. XAfter the WOOD definition, we add:
  209. X.D(
  210. X#define MOUNTAIN        7       /* bad mountain texture */
  211. X.D)
  212. X.LP
  213. XIn addition, we must declare the two new functions which we will
  214. Xadd to texture.c.  The first function, NewMountainText(), will
  215. Xreturn a pointer to a Texture structure:
  216. X.D(
  217. XTexture *NewMountainText();
  218. X.D)
  219. XThe second routine, MountainText, returns nothing, but needs to be
  220. Xdeclared:
  221. X.D(
  222. Xint MountainText();
  223. X.D)
  224. X.NH
  225. XModifying texture.c
  226. X.LP
  227. XFirstly, we must include the new texturing function in the array of
  228. Xtexturing functions used by rayshade.  This array, indexed by texture
  229. Xtype, is used by apply_textures() to call the correct texturing function.
  230. X.LP
  231. XSo, we modify the textures[] definition to read:
  232. X.D(
  233. Xint (*textures[])() =
  234. X        {CheckerText, BlotchText, BumpText, MarbleText, fBmText, fBmBumpText,
  235. X         WoodText, MountainText};
  236. X.D)
  237. X.LP
  238. XNote that MOUNTAIN was defined to be 7, and that MountainText is texture
  239. Xnumber 7 (starting from 0) in the array.
  240. X.LP
  241. XNext, we need to write NewMountainText(), which will create and return a
  242. Xreference to the texture.  Our new texture will be a function of 5 parameters:
  243. X.D(
  244. X        scale           amount to scale \fINoise()\fR by
  245. X        omega, lambda   fBm parameters
  246. X        octaves         number of octaves of \fINoise()\fR in fBm
  247. X        colormap        name of colormap file, if any
  248. X.D)
  249. XThus, we add to the end of texture.c:
  250. X.D(
  251. XTexture *
  252. XNewMountainText(scale, omega, lambda, octaves, mapname)
  253. Xdouble scale, omega, lambda;
  254. Xint octaves;
  255. Xchar *mapname;
  256. X{
  257. X        /*
  258. X         * Pointer to new texture.
  259. X         */
  260. X        Texture *text;
  261. X
  262. X        /*
  263. X         * Allocate new texture of type MOUNTAIN
  264. X         */
  265. X        text = new_texture(MOUNTAIN);
  266. X        /*
  267. X         * Allocate space to store omega, lambda and octaves.
  268. X         */
  269. X        text->args = (double *)Malloc(3 * sizeof(double));
  270. X        text->args[0] = omega;
  271. X        text->args[1] = lambda;
  272. X        text->args[2] = (double)octaves;
  273. X        /*
  274. X         * scale is stored in 'size'.
  275. X         */
  276. X        text->size = scale;
  277. X        /*
  278. X         * If a colormap name was specified, read it into 'colormap'.
  279. X         */
  280. X        if (mapname != (char *)0)
  281. X                text->colormap = read_colormap(mapname);
  282. X        /*
  283. X         * All done -- return new texture.
  284. X         */
  285. X        return text;
  286. X}
  287. X.D)
  288. X.LP
  289. XThus, NewMountainText is called with the desired parameters and a
  290. Xnew Texture is returned.
  291. X.LP
  292. XFinally, we must write the routine which actually performs the texturing.
  293. XEach texturing function is called by apply_textures() with the following
  294. Xarguments:
  295. X.D(
  296. X        text
  297. X                a pointer to the Texture being applied
  298. X        pos
  299. X                a pointer to the coordinates of the point of intersection
  300. X        norm
  301. X                a pointer to the surface normal at the point of intersection
  302. X        surf
  303. X                the pointer to a copy of the surface of the object being
  304. X                textured  (a copy is used so that the surface can be
  305. X                modified for a given shading calculation without affecting
  306. X                subsequent calculations).
  307. X.D)
  308. X.LP
  309. XThus, we write:
  310. X.D(
  311. XMountainText(text, pos, norm, surf)
  312. XTexture *text;
  313. XVector *pos, *norm;
  314. XSurface *surf;
  315. X{
  316. X        double val;
  317. X        int index;
  318. X
  319. X        /*
  320. X         * Compute value of fBm (fractional Brownian motion) for
  321. X         * the given point.
  322. X         */
  323. X        val = fBm(pos, text->args[0], text->args[1], (int)text->args[2]); 
  324. X        /*
  325. X         * Scale the result as requested and add in the Z component of
  326. X         * the point of intersection.  Note that in a better texture
  327. X         * we'd probably have additional parameters to afford
  328. X         * greater control of val.
  329. X         */
  330. X        val = pos->z + text->size * val;
  331. X
  332. X        if (text->colormap) {
  333. X                /*
  334. X                 * If we're using a colormap, compute an index into
  335. X                 * the colormap and use the appropriate color as the
  336. X                 * diffuse component of the surface.
  337. X                 */
  338. X                index = 255. * val;
  339. X                if (index > 255)
  340. X                        index = 255;
  341. X                if (index < 0)
  342. X                        index = 0;
  343. X                surf->diff = text->colormap[index];
  344. X        } else {
  345. X                /*
  346. X                 * If there's no colormap, simply scale the diffuse
  347. X                 * component. 
  348. X                 */
  349. X                surf->diff = ScaleColor(val, surf->diff);
  350. X        }
  351. X}
  352. X.D)
  353. X.LP
  354. X.NH
  355. Xinput_lex.l
  356. X.LP
  357. XNow that we have the hard parts written, all that is left is making
  358. Xthe parser recognize the new texture.  To do this, we first need to 
  359. Xadd a keyword for our texture to the list of keywords recognized by
  360. Xrayshade.  This is done by editing input_lex.l.
  361. X.LP
  362. XThe file input_lex.l contains, among other things, an alphabetical list of
  363. Xrayshade's keywords.  To add a new keyword, one simply follows the
  364. Xexample of the other keywords.  Thus, we add the line:
  365. X.D(
  366. Xmountain                     {return(tMOUNTAIN);}
  367. X.D)
  368. Xbetween the lines defining 'mist' and 'object'.  This line directs
  369. Xlex to return the token tMOUNTAIN whenever the string "mountain" is
  370. Xencountered in an input file.
  371. X.NH
  372. Xinput_yacc.y
  373. X.LP
  374. XFinally, we need to write the code which will actually create an instance
  375. Xof the new texture by calling NewMountainText().  This is done in
  376. Xinput_yacc.y.
  377. X.LP
  378. XIn input_yacc.y, there are a series of lines which look something like:
  379. X.D(
  380. X%token tBACKGROUND tBLOTCH tBOX tBUMP tCONE tCYL tDIRECTIONAL 
  381. X%token tENDDEF tEXTENDED tEYEP tFBM tFBMBUMP tFOG tFOV tGRID
  382. X%token tHEIGHTFIELD tLIGHT tLIST tLOOKP tMARBLE tMAXDEPTH tMIST
  383. X%token tOBJECT tOUTFILE
  384. X%token tPLANE tPOINT tPOLY tROTATE
  385. X%token tSCALE tSCREEN tSPHERE tSTARTDEF tSUPERQ tSURFACE tRESOLUTION
  386. X%token tTHRESH tTRANSLATE tTRANSFORM tTRIANGLE tUP tENDFILE
  387. X%token tTEXTURE tCHECKER tWOOD
  388. X.D)
  389. X.LP
  390. XThese lines declare the tokens returned by lex.  We need to declare
  391. XtMOUNTAIN in a similar manner.  So, we change the last line to
  392. Xread:
  393. X.D(
  394. X%token tTEXTURE tCHECKER tWOOD tMOUNTAIN
  395. X.D)
  396. XNext, we need to call NewMountainText() in the proper place.  In input_yacc.y,
  397. Xthere is a production which reads something like:
  398. X.D(
  399. XTexturetype     : tCHECKER String
  400. X                {
  401. X                        $$ = NewCheckText($2);
  402. X                }
  403. X                | ...
  404. X                ...
  405. X                | tWOOD
  406. X                {
  407. X                        $$ = NewWoodText();
  408. X                }
  409. X                ;
  410. X.D)
  411. X.LP
  412. XThese productions invoke the proper texture creation routine when appropriate.
  413. XFor example, when the keyword corresponding to tCHECKER is followed by
  414. Xa String, yacc will invoke NewCheckText() with the string (the name of
  415. Xa surface, in this case) as an argument.  The Yacc grammar understands
  416. Xthe following datatypes, among others:
  417. X.D(
  418. X        String          a series of alphanumerics surrounded by
  419. X                        white space (i.e., the string need not be quoted)
  420. X        Fnumber         a floating-point number
  421. X        tINT            an integer
  422. X        Vector          a vector (x, y, z)
  423. X        Color           a color (r, g, b)
  424. X.D)
  425. XTo add a texture to the list of recognized textures, we change:
  426. X.D(
  427. X                ...
  428. X                | tWOOD
  429. X                {
  430. X                        $$ = NewWoodText();
  431. X                }
  432. X                ;
  433. X.D)
  434. Xto:
  435. X.D(
  436. X                | tWOOD
  437. X                {
  438. X                        $$ = NewWoodText();
  439. X                }
  440. X                | tMOUNTAIN Fnumber Fnumber Fnumber tINT
  441. X                {
  442. X                        $$ = NewMountainText($2, $3, $4, $5, (char *)0);
  443. X                }
  444. X                | tMOUNTAIN Fnumber Fnumber Fnumber tINT String
  445. X                {
  446. X                        $$ = NewMountainText($2, $3, $4, $5, $6);
  447. X                }
  448. X                ;
  449. X.D)
  450. X.LP
  451. XThe first new production invokes NewMountainText() when the keyword
  452. Xassociated with tMOUNTAIN ("mountain") appears in an appropriate place
  453. Xin the input file followed by
  454. X.I four
  455. Xparameters (scale, omega,
  456. Xlambda, and octaves).  In this case, NewMountainText is passed a
  457. XNULL pointer as the name of the colormap to use.
  458. XThis code creates a reference to a mountain texture that does
  459. X.I not
  460. Xmake
  461. Xuse of a colormap.  So, this production is invoked whenever a line
  462. Xsuch as the following is encountered in the input file:
  463. X.D(
  464. X        texture mountain 0.2 0.5 2.0 6
  465. X.D)
  466. X.LP
  467. XThe second production works in a similar manner, except that it passes
  468. Xa colormap name to NewMountainText().  It handles lines such as:
  469. X.D(
  470. X        texture mountain 0.2 0.5 2.0 6 mountain.map
  471. X.D)
  472. X.NH
  473. XCompiling
  474. X.LP
  475. XThat, in theory, is all there is to it.  Run 'make' to recompile
  476. Xinput_lex.o, input_yacc.o, and texture.o.
  477. X.NH
  478. XTesting
  479. X.LP
  480. XA good test input file for the new texture might be something like:
  481. X.D(
  482. Xscreen 512 512
  483. Xeyep 0 -10 0
  484. Xlookp 0 0 0
  485. X
  486. Xfov 20.
  487. X
  488. Xlight 1.0 directional 1. -1. 1.
  489. Xsurface boring .1 .1 .1 .8 .8 .8 0 0 0 0 0 0 0
  490. X
  491. Xsphere boring 1. 0. 0. 0. texture mountain 0.2 0.5 2.0 6 planet.map
  492. X.D)
  493. END_OF_FILE
  494. if test 13859 -ne `wc -c <'doc/texture.ms'`; then
  495.     echo shar: \"'doc/texture.ms'\" unpacked with wrong size!
  496. fi
  497. # end of 'doc/texture.ms'
  498. fi
  499. if test -f 'src/grid.c' -a "${1}" != "-c" ; then 
  500.   echo shar: Will not clobber existing file \"'src/grid.c'\"
  501. else
  502. echo shar: Extracting \"'src/grid.c'\" \(9938 characters\)
  503. sed "s/^X//" >'src/grid.c' <<'END_OF_FILE'
  504. X/*
  505. X * grid.c
  506. X *
  507. X * Copyright (C) 1989, Craig E. Kolb
  508. X *
  509. X * This software may be freely copied, modified, and redistributed,
  510. X * provided that this copyright notice is preserved on all copies.
  511. X *
  512. X * There is no warranty or other guarantee of fitness for this software,
  513. X * it is provided solely .  Bug reports or fixes may be sent
  514. X * to the author, who may or may not act on them as he desires.
  515. X *
  516. X * You may not include this software in a program or other software product
  517. X * without supplying the source, or without informing the end-user that the
  518. X * source is available for no extra charge.
  519. X *
  520. X * If you modify this software, you should include a notice giving the
  521. X * name of the person performing the modification, the date of modification,
  522. X * and the reason for such modification.
  523. X *
  524. X * $Id: grid.c,v 3.0 89/10/27 02:05:50 craig Exp $
  525. X *
  526. X * $Log:    grid.c,v $
  527. X * Revision 3.0  89/10/27  02:05:50  craig
  528. X * Baseline for first official release.
  529. X * 
  530. X */
  531. X#include <stdio.h>
  532. X#include "constants.h"
  533. X#include "typedefs.h"
  534. X#include "funcdefs.h"
  535. X
  536. Xextern double CheckVoxel(), intersect();
  537. Xunsigned long    raynumber = 1;        /* Current "ray number". */
  538. X                    /* (should be "grid number") */
  539. X/*
  540. X * Intersect ray with grid, returning distance from "pos" to
  541. X * nearest intersection with an object in the grid.  Returns 0.
  542. X * if no intersection.
  543. X */
  544. Xdouble
  545. Xint_grid(grid, source, ray, hitinfo)
  546. XGrid *grid;
  547. XPrimitive *source;
  548. XRay *ray;
  549. XHitInfo *hitinfo;
  550. X{
  551. X    ObjList *list;
  552. X    Object *tmpobj;
  553. X    double dist, mindist, offset, tMaxX, tMaxY, tMaxZ;
  554. X    double tDeltaX, tDeltaY, tDeltaZ, *raybounds[2][3];
  555. X    int stepX, stepY, stepZ, outX, outY, outZ, x, y, z;
  556. X    HitInfo infotmp;
  557. X    Vector curpos, nXp, nYp, nZp, np, pDeltaX, pDeltaY, pDeltaZ;
  558. X    unsigned long counter;
  559. X
  560. X    mindist = FAR_AWAY;
  561. X
  562. X    /*
  563. X     * The "raynumber" scheme prevents us from performing unnecessary
  564. X     * ray/object intersection tests. Since an object may span more than
  565. X     * one voxel, it is possible that such an object will be tested more
  566. X     * than once as we move from voxel-to-voxel. The idea here is to
  567. X     * increment "raynumber" once when we begin a ray/grid intersection
  568. X     * test. Whenever we check for intersection with an object in
  569. X     * the grid, we assign that object's "counter" field the current value
  570. X     * of "raynumber".  On subsequent calls to CheckVoxel, if the object's
  571. X     * "counter" is greater than or equal to the value "raynumber" had
  572. X     * when we started tracing the current grid, we know that we've already
  573. X     * checked that object.  This isn't as straight-forward as one
  574. X     * might think due to instantiation -- one may have several
  575. X     * instances of the same object in a grid.  By incrementing raynumber
  576. X     * whenever we being a new ray/grid int. test, we guarantee that
  577. X     * we will check for intersection with the objects in the grid
  578. X     * at most once.
  579. X     */
  580. X    infotmp.totaltrans = hitinfo->totaltrans;
  581. X    /*
  582. X     * Check unbounded objects.
  583. X     */
  584. X    for (list = grid->unbounded ; list; list = list->next) {
  585. X        tmpobj = list->data;
  586. X        dist = intersect(tmpobj, source, ray, &infotmp);
  587. X        if (dist > 0. && dist < mindist) {
  588. X            *hitinfo = infotmp;
  589. X            mindist = dist;
  590. X        }
  591. X    }
  592. X
  593. X    /*
  594. X     * If outside of the bounding box, check to see if we
  595. X     * hit it.
  596. X     */
  597. X    if (OutOfBounds(&ray->pos, grid->bounds)) {
  598. X        offset = IntBounds(ray, grid->bounds);
  599. X        if (offset <= 0.)
  600. X            /*
  601. X             * Ray never hit grid space.
  602. X             */
  603. X            return (mindist == FAR_AWAY ? 0. : mindist);
  604. X        else if (mindist < offset)
  605. X            /*
  606. X             * Hit an unbounded object closer than grid.
  607. X             */
  608. X            return mindist;
  609. X        /*
  610. X         * else
  611. X         *    The ray enters voxels space before it hits
  612. X         *     an unbounded object.
  613. X         */
  614. X        addscaledvec(ray->pos, offset, ray->dir, &curpos);
  615. X    } else {
  616. X        offset = 0.;
  617. X        curpos = ray->pos;
  618. X    }
  619. X
  620. X    counter = raynumber++;
  621. X    /*
  622. X     * Kludge:  Voxel space is mapped as [start, end),
  623. X     * and we want it to be [start, end].
  624. X     */
  625. X    x = x2voxel(grid, curpos.x);
  626. X    if (x == grid->xsize)
  627. X        x = grid->xsize -1;
  628. X    y = y2voxel(grid, curpos.y);
  629. X    if (y == grid->ysize)
  630. X        y = grid->ysize -1;
  631. X    z = z2voxel(grid, curpos.z);
  632. X    if (z == grid->zsize)
  633. X        z = grid->zsize -1;
  634. X
  635. X    /*
  636. X     * tMaxX is the absolute distance from the ray origin we must move
  637. X     *        to get to the next voxel in the X
  638. X     *        direction.  It is incrementally updated
  639. X     *         by DDA as we move from voxel-to-voxel.
  640. X     * tDeltaX is the relative amount along the ray we move to
  641. X     *        get to the next voxel in the X direction. Thus,
  642. X     *        when we decide to move in the X direction,
  643. X     *         we increment tMaxX by tDeltaX.
  644. X     */
  645. X    if (ray->dir.x < 0.) {
  646. X        stepX = outX = -1;
  647. X        tMaxX = (voxel2x(grid, x) - curpos.x) / ray->dir.x;
  648. X        tDeltaX = grid->voxsize[X] / - ray->dir.x;
  649. X        raybounds[LOW][X] = &np.x;
  650. X        raybounds[HIGH][X] = &curpos.x;
  651. X    } else if (ray->dir.x > 0.) {
  652. X        stepX = 1;
  653. X        outX = grid->xsize;
  654. X        tMaxX = (voxel2x(grid, x+1) - curpos.x) / ray->dir.x;
  655. X        tDeltaX = grid->voxsize[X] / ray->dir.x;
  656. X        raybounds[LOW][X] = &curpos.x;
  657. X        raybounds[HIGH][X] = &np.x;
  658. X    } else {
  659. X        tMaxX = FAR_AWAY;
  660. X        raybounds[LOW][X] = &curpos.x;
  661. X        raybounds[HIGH][X] = &np.x;
  662. X        tDeltaX = 0.;
  663. X    }
  664. X
  665. X    if (ray->dir.y < 0.) {
  666. X        stepY = outY = -1;
  667. X        tMaxY = (voxel2y(grid, y) - curpos.y) / ray->dir.y;
  668. X        tDeltaY = grid->voxsize[Y] / - ray->dir.y;
  669. X        raybounds[LOW][Y] = &np.y;
  670. X        raybounds[HIGH][Y] = &curpos.y;
  671. X    } else if (ray->dir.y > 0.) {
  672. X        stepY = 1;
  673. X        outY = grid->ysize;
  674. X        tMaxY = (voxel2y(grid, y+1) - curpos.y) / ray->dir.y;
  675. X        tDeltaY = grid->voxsize[Y] / ray->dir.y;
  676. X        raybounds[LOW][Y] = &curpos.y;
  677. X        raybounds[HIGH][Y] = &np.y;
  678. X    } else {
  679. X        tMaxY = FAR_AWAY;
  680. X        raybounds[LOW][Y] = &curpos.y;
  681. X        raybounds[HIGH][Y] = &np.y;
  682. X        tDeltaY = 0.;
  683. X    }
  684. X
  685. X    if (ray->dir.z < 0.) {
  686. X        stepZ = outZ = -1;
  687. X        tMaxZ = (voxel2z(grid, z) - curpos.z) / ray->dir.z;
  688. X        tDeltaZ = grid->voxsize[Z] / - ray->dir.z;
  689. X        raybounds[LOW][Z] = &np.z;
  690. X        raybounds[HIGH][Z] = &curpos.z;
  691. X    } else if (ray->dir.z > 0.) {
  692. X        stepZ = 1;
  693. X        outZ = grid->zsize;
  694. X        tMaxZ = (voxel2z(grid, z+1) - curpos.z) / ray->dir.z;
  695. X        tDeltaZ = grid->voxsize[Z] / ray->dir.z;
  696. X        raybounds[LOW][Z] = &curpos.z;
  697. X        raybounds[HIGH][Z] = &np.z;
  698. X    } else {
  699. X        tMaxZ = FAR_AWAY;
  700. X        raybounds[LOW][Z] = &curpos.z;
  701. X        raybounds[HIGH][Z] = &np.z;
  702. X        tDeltaZ = 0.;
  703. X    }
  704. X
  705. X    /*
  706. X     * We've already moved from the ray origin along the ray to "hitpoint"
  707. X     * by "offset" units in order to reach the grid.
  708. X     */
  709. X    tMaxX += offset;
  710. X    tMaxY += offset;
  711. X    tMaxZ += offset;
  712. X
  713. X    pDeltaX.x = tDeltaX * ray->dir.x;
  714. X    pDeltaX.y = tDeltaX * ray->dir.y;
  715. X    pDeltaX.z = tDeltaX * ray->dir.z;
  716. X    pDeltaY.x = tDeltaY * ray->dir.x;
  717. X    pDeltaY.y = tDeltaY * ray->dir.y;
  718. X    pDeltaY.z = tDeltaY * ray->dir.z;
  719. X    pDeltaZ.x = tDeltaZ * ray->dir.x;
  720. X    pDeltaZ.y = tDeltaZ * ray->dir.y;
  721. X    pDeltaZ.z = tDeltaZ * ray->dir.z;
  722. X
  723. X    nXp.x = ray->pos.x + tMaxX * ray->dir.x;
  724. X    nXp.y = ray->pos.y + tMaxX * ray->dir.y;
  725. X    nXp.z = ray->pos.z + tMaxX * ray->dir.z;
  726. X    nYp.x = ray->pos.x + tMaxY * ray->dir.x;
  727. X    nYp.y = ray->pos.y + tMaxY * ray->dir.y;
  728. X    nYp.z = ray->pos.z + tMaxY * ray->dir.z;
  729. X    nZp.x = ray->pos.x + tMaxZ * ray->dir.x;
  730. X    nZp.y = ray->pos.y + tMaxZ * ray->dir.y;
  731. X    nZp.z = ray->pos.z + tMaxZ * ray->dir.z;
  732. X
  733. X    while (1) {
  734. X        if (tMaxX < tMaxY) {
  735. X            if (tMaxX < tMaxZ) {
  736. X                np = nXp;
  737. X                if ((list = grid->cells[x][y][z]))
  738. X                    mindist = CheckVoxel(list,source,ray,
  739. X                    raybounds,hitinfo,counter,mindist);
  740. X                x += stepX;
  741. X                if (mindist < tMaxX || x == outX)
  742. X                    break;
  743. X                tMaxX += tDeltaX;
  744. X                curpos = nXp;
  745. X                nXp.x += pDeltaX.x;
  746. X                nXp.y += pDeltaX.y;
  747. X                nXp.z += pDeltaX.z;
  748. X            } else {
  749. X                np = nZp;
  750. X                if ((list = grid->cells[x][y][z]))
  751. X                    mindist = CheckVoxel(list,source,ray,
  752. X                    raybounds, hitinfo,counter,mindist);
  753. X                z += stepZ;
  754. X                if (mindist < tMaxZ || z == outZ)
  755. X                    break;
  756. X                tMaxZ += tDeltaZ;
  757. X                curpos = nZp;
  758. X                nZp.x += pDeltaZ.x;
  759. X                nZp.y += pDeltaZ.y;
  760. X                nZp.z += pDeltaZ.z;
  761. X            }
  762. X        } else {
  763. X            if (tMaxY < tMaxZ) {
  764. X                np = nYp;
  765. X                if ((list = grid->cells[x][y][z]))
  766. X                    mindist = CheckVoxel(list,source,ray,
  767. X                    raybounds,hitinfo,counter,mindist);
  768. X                y += stepY;
  769. X                if (mindist < tMaxY || y == outY)
  770. X                    break;
  771. X                tMaxY += tDeltaY;
  772. X                curpos = nYp;
  773. X                nYp.x += pDeltaY.x;
  774. X                nYp.y += pDeltaY.y;
  775. X                nYp.z += pDeltaY.z;
  776. X            } else {
  777. X                np = nZp;
  778. X                if ((list = grid->cells[x][y][z]))
  779. X                    mindist = CheckVoxel(list,source,ray,
  780. X                    raybounds, hitinfo,counter,mindist);
  781. X                z += stepZ;
  782. X                if (mindist < tMaxZ || z == outZ)
  783. X                    break;
  784. X                tMaxZ += tDeltaZ;
  785. X                curpos = nZp;
  786. X                nZp.x += pDeltaZ.x;
  787. X                nZp.y += pDeltaZ.y;
  788. X                nZp.z += pDeltaZ.z;
  789. X            }
  790. X        }
  791. X
  792. X    }
  793. X    if (mindist == FAR_AWAY)
  794. X        return 0.;
  795. X    return mindist;
  796. X
  797. X}
  798. X
  799. X/*
  800. X * Intersect ray with objects in grid cell.  Note that there are a many ways
  801. X * to speed up this routine, all of which uglify the code to a large extent.
  802. X */
  803. Xdouble
  804. XCheckVoxel(list,source,ray,raybounds,hitinfo,counter,mindist)
  805. XObjList *list;
  806. XPrimitive *source;
  807. XRay *ray;
  808. Xdouble *raybounds[2][3];
  809. XHitInfo *hitinfo;
  810. Xunsigned long counter;
  811. Xdouble mindist;
  812. X{
  813. X    Object *obj;
  814. X    HitInfo tmpinfo;
  815. X    double dist, lx, hx, ly, hy, lz, hz;
  816. X
  817. X    tmpinfo.totaltrans = hitinfo->totaltrans;
  818. X
  819. X    lx = *raybounds[LOW][X];
  820. X    hx = *raybounds[HIGH][X];
  821. X    ly = *raybounds[LOW][Y];
  822. X    hy = *raybounds[HIGH][Y];
  823. X    lz = *raybounds[LOW][Z];
  824. X    hz = *raybounds[HIGH][Z];
  825. X
  826. X    for (; list; list = list->next) {
  827. X        obj = list->data;
  828. X        /*
  829. X         * If object's counter is greater than or equal to the
  830. X         * number associated with the current grid,
  831. X         * don't bother checking again.  In addition, if the
  832. X         * bounding box of the ray's extent in the voxel does
  833. X         * not intersect the bounding box of the object, don't bother.
  834. X         */
  835. X#ifdef LINDA
  836. X        if (*obj->counter >= counter ||
  837. X#else
  838. X        if (obj->counter >= counter ||
  839. X#endif
  840. X            obj->bounds[LOW][X] > hx ||
  841. X            obj->bounds[HIGH][X] < lx ||
  842. X            obj->bounds[LOW][Y] > hy ||
  843. X            obj->bounds[HIGH][Y] < ly ||
  844. X            obj->bounds[LOW][Z] > hz ||
  845. X            obj->bounds[HIGH][Z] < lz)
  846. X            continue;
  847. X#ifdef LINDA
  848. X        *obj->counter = counter;
  849. X#else
  850. X        obj->counter = counter;
  851. X#endif
  852. X        dist = intersect(obj, source, ray, &tmpinfo);
  853. X        if (dist > 0. && dist < mindist) {
  854. X            *hitinfo = tmpinfo;
  855. X            mindist = dist;
  856. X        }
  857. X    }
  858. X
  859. X    return mindist;
  860. X}
  861. END_OF_FILE
  862. if test 9938 -ne `wc -c <'src/grid.c'`; then
  863.     echo shar: \"'src/grid.c'\" unpacked with wrong size!
  864. fi
  865. # end of 'src/grid.c'
  866. fi
  867. if test -f 'src/matrix.c' -a "${1}" != "-c" ; then 
  868.   echo shar: Will not clobber existing file \"'src/matrix.c'\"
  869. else
  870. echo shar: Extracting \"'src/matrix.c'\" \(9704 characters\)
  871. sed "s/^X//" >'src/matrix.c' <<'END_OF_FILE'
  872. X/*
  873. X * matrix.c
  874. X *
  875. X * Copyright (C) 1989, Craig E. Kolb
  876. X *
  877. X * This software may be freely copied, modified, and redistributed,
  878. X * provided that this copyright notice is preserved on all copies.
  879. X *
  880. X * There is no warranty or other guarantee of fitness for this software,
  881. X * it is provided solely .  Bug reports or fixes may be sent
  882. X * to the author, who may or may not act on them as he desires.
  883. X *
  884. X * You may not include this software in a program or other software product
  885. X * without supplying the source, or without informing the end-user that the
  886. X * source is available for no extra charge.
  887. X *
  888. X * If you modify this software, you should include a notice giving the
  889. X * name of the person performing the modification, the date of modification,
  890. X * and the reason for such modification.
  891. X *
  892. X * $Id: matrix.c,v 3.0 89/10/27 02:05:56 craig Exp $
  893. X *
  894. X * $Log:    matrix.c,v $
  895. X * Revision 3.0  89/10/27  02:05:56  craig
  896. X * Baseline for first official release.
  897. X * 
  898. X */
  899. X#include <math.h>
  900. X#include <stdio.h>
  901. X#include "typedefs.h"
  902. X#include "constants.h"
  903. X#include "funcdefs.h"
  904. X
  905. X/*
  906. X * Matrices are indexed row-first; that is:
  907. X * matrix[ROW][COLUMN]
  908. X */
  909. X/*
  910. X * Allocate new structure which holds both object-to-world and
  911. X * world-to-object space transformation structures.  It probably
  912. X * should hold pointers to these structures.
  913. X */
  914. XTrans *
  915. Xnew_trans(t, it)
  916. XTransInfo *t, *it;
  917. X{
  918. X    Trans *res;
  919. X
  920. X    res = (Trans *)Malloc(sizeof(Trans));
  921. X    res->obj2world = *t;
  922. X    res->world2obj = *it;
  923. X    return res;
  924. X}
  925. X
  926. X/*
  927. X * Allocate new transformation structure.
  928. X */
  929. XTransInfo *
  930. Xnew_transinfo()
  931. X{
  932. X    TransInfo *res;
  933. X
  934. X    res = (TransInfo *)Malloc(sizeof(TransInfo));
  935. X    init_trans(res);
  936. X    return res;
  937. X}
  938. X
  939. X/*
  940. X * Set up matrix for counter-clockwise rotation about vector (x, y, z) by
  941. X * theta radians.
  942. X */
  943. Xrotate_trans(trans, x, y, z, theta)
  944. XTransInfo *trans;
  945. Xdouble x, y, z, theta;
  946. X{
  947. X    double n1, n2, n3, sintheta, costheta;
  948. X    Vector vector;
  949. X
  950. X    vector.x = x;
  951. X    vector.y = y;
  952. X    vector.z = z;
  953. X    (void)normalize(&vector);
  954. X
  955. X    sintheta = sin(theta);
  956. X    costheta = cos(theta);
  957. X
  958. X    n1 = vector.x; n2 = vector.y; n3 = vector.z;
  959. X    trans->matrix[0][0] = (double)(n1*n1 + (1. - n1*n1)*costheta);
  960. X    trans->matrix[1][0] = (double)(n1*n2*(1 - costheta) + n3*sintheta);
  961. X    trans->matrix[2][0] = (double)(n1*n3*(1 - costheta) - n2*sintheta);
  962. X    trans->matrix[0][1] = (double)(n1*n2*(1 - costheta) - n3*sintheta);
  963. X    trans->matrix[1][1] = (double)(n2*n2 + (1 - n2*n2)*costheta);
  964. X    trans->matrix[2][1] = (double)(n2*n3*(1 - costheta) + n1*sintheta);
  965. X    trans->matrix[0][2] = (double)(n1*n3*(1 - costheta) + n2*sintheta);
  966. X    trans->matrix[1][2] = (double)(n2*n3*(1 - costheta) - n1*sintheta);
  967. X    trans->matrix[2][2] = (double)(n3*n3 + (1 - n3*n3)*costheta);
  968. X    trans->translate.x = trans->translate.y = trans->translate.z = 0.;
  969. X}
  970. X
  971. X/*
  972. X * Apply translation by (vec) to trans.
  973. X */
  974. Xtranslate(trans, vec)
  975. XTransInfo *trans;
  976. XVector *vec;
  977. X{
  978. X    trans->translate.x += vec->x;
  979. X    trans->translate.y += vec->y;
  980. X    trans->translate.z += vec->z;
  981. X}
  982. X
  983. X/*
  984. X * Apply rotation about (dir) to matrix.
  985. X */
  986. Xrotate(trans, dir, radians)
  987. XTransInfo *trans;
  988. Xdouble radians;
  989. XVector *dir;
  990. X{
  991. X    TransInfo ttmp;
  992. X
  993. X    rotate_trans(&ttmp, dir->x, dir->y, dir->z, radians);
  994. X    mmult(trans, &ttmp, trans);
  995. X}
  996. X
  997. X/*
  998. X * Apply scale of (x, y, z) to trans.
  999. X */
  1000. Xscale(trans, x, y, z)
  1001. XTransInfo *trans;
  1002. Xdouble x, y, z;
  1003. X{
  1004. X    trans->matrix[0][0] *= x;
  1005. X    trans->matrix[1][0] *= x;
  1006. X    trans->matrix[2][0] *= x;
  1007. X    trans->matrix[0][1] *= y;
  1008. X    trans->matrix[1][1] *= y;
  1009. X    trans->matrix[2][1] *= y;
  1010. X    trans->matrix[0][2] *= z;
  1011. X    trans->matrix[1][2] *= z;
  1012. X    trans->matrix[2][2] *= z;
  1013. X
  1014. X    trans->translate.x *= x;
  1015. X    trans->translate.y *= y;
  1016. X    trans->translate.z *= z;
  1017. X
  1018. X}
  1019. X
  1020. X/*
  1021. X * Multiply m1 and m2, copy result into "res".
  1022. X */
  1023. Xmmult(t1, t2, res)
  1024. XTransInfo *t1, *t2, *res;
  1025. X{
  1026. X    register int i, j, k;
  1027. X    TransInfo tmp;
  1028. X
  1029. X    for(i = 0; i < 3; i++) {
  1030. X        for(j = 0; j < 3;j++) {
  1031. X            tmp.matrix[i][j] = 0.;
  1032. X            for(k = 0; k < 3;k++)
  1033. X                tmp.matrix[i][j] += t1->matrix[i][k] *
  1034. X                            t2->matrix[k][j];
  1035. X
  1036. X        }
  1037. X    }
  1038. X    tmp.translate.x = t1->translate.x * t2->matrix[0][0] +
  1039. X                t1->translate.y * t2->matrix[1][0] +
  1040. X                t1->translate.z * t2->matrix[2][0] +
  1041. X                    t2->translate.x;
  1042. X    tmp.translate.y = t1->translate.x * t2->matrix[0][1] +
  1043. X                t1->translate.y * t2->matrix[1][1] +
  1044. X                t1->translate.z * t2->matrix[2][1] +
  1045. X                    t2->translate.y;
  1046. X    tmp.translate.z = t1->translate.x * t2->matrix[0][2] +
  1047. X                t1->translate.y * t2->matrix[1][2] +
  1048. X                t1->translate.z * t2->matrix[2][2] +
  1049. X                    t2->translate.z;
  1050. X    copy_trans(res, &tmp);
  1051. X}
  1052. X
  1053. X/*
  1054. X * Copy a given transformation structure.
  1055. X */
  1056. Xcopy_trans(into, from)
  1057. XTransInfo *into, *from;
  1058. X{
  1059. X    register int i;
  1060. X
  1061. X    for(i = 0;i < 3;i++) {
  1062. X        into->matrix[i][0] = from->matrix[i][0];
  1063. X        into->matrix[i][1] = from->matrix[i][1];
  1064. X        into->matrix[i][2] = from->matrix[i][2];
  1065. X    }
  1066. X
  1067. X    into->translate = from->translate;
  1068. X}
  1069. X
  1070. X/*
  1071. X * Initialize transformation structure.
  1072. X */
  1073. Xinit_trans(trans)
  1074. XTransInfo *trans;
  1075. X{
  1076. X    register int i, j;
  1077. X
  1078. X    for(i = 0;i < 3;i++)
  1079. X        for(j = 0;j < 3;j++)
  1080. X            trans->matrix[i][j] = (double)(i == j);
  1081. X
  1082. X    trans->translate.x = trans->translate.y = trans->translate.z = 0.;
  1083. X}
  1084. X
  1085. X/*
  1086. X * Calculate inverse of the given transformation structure.
  1087. X */
  1088. Xinvert_trans(inverse, trans)
  1089. XTransInfo *inverse, *trans;
  1090. X{
  1091. X    TransInfo ttmp;
  1092. X    int i;
  1093. X    double d;
  1094. X    extern int yylineno;
  1095. X
  1096. X    ttmp.matrix[0][0] = trans->matrix[1][1]*trans->matrix[2][2] -
  1097. X                trans->matrix[1][2]*trans->matrix[2][1];
  1098. X    ttmp.matrix[1][0] = trans->matrix[1][0]*trans->matrix[2][2] -
  1099. X                trans->matrix[1][2]*trans->matrix[2][0];
  1100. X    ttmp.matrix[2][0] = trans->matrix[1][0]*trans->matrix[2][1] -
  1101. X                trans->matrix[1][1]*trans->matrix[2][0];
  1102. X
  1103. X    ttmp.matrix[0][1] = trans->matrix[0][1]*trans->matrix[2][2] -
  1104. X                trans->matrix[0][2]*trans->matrix[2][1];
  1105. X    ttmp.matrix[1][1] = trans->matrix[0][0]*trans->matrix[2][2] -
  1106. X                trans->matrix[0][2]*trans->matrix[2][0];
  1107. X    ttmp.matrix[2][1] = trans->matrix[0][0]*trans->matrix[2][1] -
  1108. X                trans->matrix[0][1]*trans->matrix[2][0];
  1109. X
  1110. X    ttmp.matrix[0][2] = trans->matrix[0][1]*trans->matrix[1][2] -
  1111. X                trans->matrix[0][2]*trans->matrix[1][1];
  1112. X    ttmp.matrix[1][2] = trans->matrix[0][0]*trans->matrix[1][2] -
  1113. X                trans->matrix[0][2]*trans->matrix[1][0];
  1114. X    ttmp.matrix[2][2] = trans->matrix[0][0]*trans->matrix[1][1] -
  1115. X                trans->matrix[0][1]*trans->matrix[1][0];
  1116. X
  1117. X    d = trans->matrix[0][0]*ttmp.matrix[0][0] -
  1118. X        trans->matrix[0][1]*ttmp.matrix[1][0] +
  1119. X        trans->matrix[0][2]*ttmp.matrix[2][0];
  1120. X
  1121. X    if (abs(d) < EPSILON*EPSILON) {
  1122. X        fprintf(stderr,"Singular matrix (line %d):\n",yylineno);
  1123. X        for (i = 0; i < 3; i++)
  1124. X            fprintf(stderr,"%g %g %g\n", trans->matrix[i][0],
  1125. X                trans->matrix[i][1], trans->matrix[i][2]);
  1126. X        exit(0);
  1127. X    }
  1128. X
  1129. X    ttmp.matrix[0][0] /= d;
  1130. X    ttmp.matrix[0][2] /= d;
  1131. X    ttmp.matrix[1][1] /= d;
  1132. X    ttmp.matrix[2][0] /= d;
  1133. X    ttmp.matrix[2][2] /= d;
  1134. X
  1135. X    d = -d;
  1136. X
  1137. X    ttmp.matrix[0][1] /= d;
  1138. X    ttmp.matrix[1][0] /= d;
  1139. X    ttmp.matrix[1][2] /= d;
  1140. X    ttmp.matrix[2][1] /= d;
  1141. X
  1142. X    ttmp.translate.x = -(ttmp.matrix[0][0]*trans->translate.x +
  1143. X                 ttmp.matrix[1][0]*trans->translate.y +
  1144. X                 ttmp.matrix[2][0]*trans->translate.z);
  1145. X    ttmp.translate.y = -(ttmp.matrix[0][1]*trans->translate.x +
  1146. X                 ttmp.matrix[1][1]*trans->translate.y +
  1147. X                 ttmp.matrix[2][1]*trans->translate.z);
  1148. X    ttmp.translate.z = -(ttmp.matrix[0][2]*trans->translate.x +
  1149. X                 ttmp.matrix[1][2]*trans->translate.y +
  1150. X                 ttmp.matrix[2][2]*trans->translate.z);
  1151. X
  1152. X    copy_trans(inverse, &ttmp);
  1153. X}
  1154. X
  1155. X/*
  1156. X * Apply a transformation to a point (translation affects the point).
  1157. X */
  1158. Xtransform_point(vec, trans)
  1159. XVector *vec;
  1160. XTransInfo *trans;
  1161. X{
  1162. X    Vector tmp;
  1163. X
  1164. X    tmp.x = vec->x * trans->matrix[0][0] + vec->y * trans->matrix[1][0] +
  1165. X            vec->z * trans->matrix[2][0] + trans->translate.x;
  1166. X    tmp.y = vec->x * trans->matrix[0][1] + vec->y * trans->matrix[1][1] +
  1167. X            vec->z * trans->matrix[2][1] + trans->translate.y;
  1168. X    tmp.z = vec->x * trans->matrix[0][2] + vec->y * trans->matrix[1][2] +
  1169. X            vec->z * trans->matrix[2][2] + trans->translate.z;
  1170. X    *vec = tmp;
  1171. X}
  1172. X
  1173. X/*
  1174. X * Apply an explicit transformation to the given transformation structure.
  1175. X * 'c1x' is the X (0th) component of the first column, and so on.
  1176. X */
  1177. Xexplicit_trans(trans, c1x,c1y,c1z, c2x,c2y,c2z, c3x,c3y,c3z, tx, ty, tz, res)
  1178. XTransInfo *trans, *res;
  1179. Xdouble c1x, c1y, c1z, c2x, c2y, c2z, c3x, c3y, c3z, tx, ty, tz;
  1180. X{
  1181. X    TransInfo tmp;
  1182. X
  1183. X    tmp.matrix[0][0] = c1x;
  1184. X    tmp.matrix[1][0] = c1y;
  1185. X    tmp.matrix[2][0] = c1z;
  1186. X
  1187. X    tmp.matrix[0][1] = c2x;
  1188. X    tmp.matrix[1][1] = c2y;
  1189. X    tmp.matrix[2][1] = c2z;
  1190. X
  1191. X    tmp.matrix[0][2] = c3x;
  1192. X    tmp.matrix[1][2] = c3y;
  1193. X    tmp.matrix[2][2] = c3z;
  1194. X
  1195. X    tmp.translate.x = tx;
  1196. X    tmp.translate.y = ty;
  1197. X    tmp.translate.z = tz;
  1198. X
  1199. X    mmult(trans, &tmp, res);
  1200. X}
  1201. X
  1202. X/*
  1203. X * Apply transformation to a vector (translations have no effect).
  1204. X */
  1205. Xtransform_vector(vec, trans)
  1206. XVector *vec;
  1207. XTransInfo *trans;
  1208. X{
  1209. X    Vector tmp;
  1210. X
  1211. X    tmp.x = vec->x*trans->matrix[0][0] +
  1212. X        vec->y*trans->matrix[1][0] + vec->z*trans->matrix[2][0];
  1213. X    tmp.y = vec->x*trans->matrix[0][1] +
  1214. X        vec->y*trans->matrix[1][1] + vec->z*trans->matrix[2][1];
  1215. X    tmp.z = vec->x*trans->matrix[0][2] +
  1216. X        vec->y*trans->matrix[1][2] + vec->z*trans->matrix[2][2];
  1217. X
  1218. X    *vec = tmp;
  1219. X}
  1220. X
  1221. X/*
  1222. X * Transform "ray" by transforming the origin point and direction vector.
  1223. X */
  1224. Xdouble
  1225. XTransformRay(ray, trans)
  1226. XRay *ray;
  1227. XTransInfo *trans;
  1228. X{
  1229. X    transform_point(&ray->pos, trans);
  1230. X    transform_vector(&ray->dir, trans);
  1231. X    return normalize(&ray->dir);
  1232. X}
  1233. X
  1234. X/*
  1235. X * Transform normal -- multiply by the transpose of the given
  1236. X * matrix (which is the inverse of the desired transformation).
  1237. X */
  1238. XTransformNormal(norm, it)
  1239. XVector *norm;
  1240. XTransInfo *it;
  1241. X{
  1242. X    Vector onorm;
  1243. X
  1244. X    onorm = *norm;
  1245. X
  1246. X    norm->x = onorm.x*it->matrix[0][0] + onorm.y*it->matrix[0][1] +
  1247. X                onorm.z*it->matrix[0][2];
  1248. X    norm->y = onorm.x*it->matrix[1][0] + onorm.y*it->matrix[1][1] +
  1249. X                onorm.z*it->matrix[1][2];
  1250. X    norm->z = onorm.x*it->matrix[2][0] + onorm.y*it->matrix[2][1] +
  1251. X                onorm.z*it->matrix[2][2];
  1252. X}
  1253. END_OF_FILE
  1254. if test 9704 -ne `wc -c <'src/matrix.c'`; then
  1255.     echo shar: \"'src/matrix.c'\" unpacked with wrong size!
  1256. fi
  1257. # end of 'src/matrix.c'
  1258. fi
  1259. if test -f 'src/shade.c' -a "${1}" != "-c" ; then 
  1260.   echo shar: Will not clobber existing file \"'src/shade.c'\"
  1261. else
  1262. echo shar: Extracting \"'src/shade.c'\" \(10618 characters\)
  1263. sed "s/^X//" >'src/shade.c' <<'END_OF_FILE'
  1264. X/*
  1265. X * shade.c
  1266. X *
  1267. X * Copyright (C) 1989, Craig E. Kolb
  1268. X *
  1269. X * This software may be freely copied, modified, and redistributed,
  1270. X * provided that this copyright notice is preserved on all copies.
  1271. X *
  1272. X * There is no warranty or other guarantee of fitness for this software,
  1273. X * it is provided solely .  Bug reports or fixes may be sent
  1274. X * to the author, who may or may not act on them as he desires.
  1275. X *
  1276. X * You may not include this software in a program or other software product
  1277. X * without supplying the source, or without informing the end-user that the
  1278. X * source is available for no extra charge.
  1279. X *
  1280. X * If you modify this software, you should include a notice giving the
  1281. X * name of the person performing the modification, the date of modification,
  1282. X * and the reason for such modification.
  1283. X *
  1284. X * $Id: shade.c,v 3.0 89/10/27 02:06:03 craig Exp $
  1285. X *
  1286. X * $Log:    shade.c,v $
  1287. X * Revision 3.0  89/10/27  02:06:03  craig
  1288. X * Baseline for first official release.
  1289. X * 
  1290. X */
  1291. X#include <math.h>
  1292. X#include <stdio.h>
  1293. X#include "constants.h"
  1294. X#include "typedefs.h"
  1295. X#include "funcdefs.h"
  1296. X
  1297. Xint    level, maxlevel;    /* Current tree depth, max depth */
  1298. Xdouble    DefIndex = 1.0;        /* Default index of refraction. */
  1299. Xdouble    TreeCutoff = UNSET;    /* Minimum contribution of any ray. */
  1300. X
  1301. X/*
  1302. X * Calculate color of ray.
  1303. X */
  1304. XShadeRay(hitinfo, ray, dist, back, color, contrib)
  1305. XHitInfo *hitinfo;        /* Information about point of intersection. */
  1306. XRay *ray;            /* Direction and origin of ray. */
  1307. Xdouble dist;            /* Distance from origin of intersection. */
  1308. XColor *back;            /* "Background" color */
  1309. XColor *color;            /* Color to assign current ray. */
  1310. Xdouble contrib;            /* Contribution of this ray to final color */
  1311. X{
  1312. X    Vector hit;
  1313. X    extern unsigned long HitRays;
  1314. X    extern Fog *GlobalFog;
  1315. X    extern Mist *GlobalMist;
  1316. X
  1317. X    /*
  1318. X     * If we got here, then a ray hit something, so...
  1319. X     */
  1320. X    HitRays++;
  1321. X
  1322. X    (void)normalize(&hitinfo->norm);
  1323. X    /*
  1324. X      * "hit" is the location of intersection in world space.
  1325. X     * hitinfo->pos is the intersection point in object space.
  1326. X     */
  1327. X    addscaledvec(ray->pos, dist, ray->dir, &hit);
  1328. X    /*
  1329. X     * Calculate ray color.
  1330. X     */
  1331. X    shade(&hit, ray, &hitinfo->norm, hitinfo->prim, &hitinfo->surf,
  1332. X            back, color, contrib);
  1333. X    /*
  1334. X     * If fog or mist is present, modify computed color.
  1335. X     */
  1336. X    if (GlobalFog)
  1337. X        ComputeFog(GlobalFog, dist, color);
  1338. X    if (GlobalMist)
  1339. X        ComputeMist(GlobalMist, &ray->pos, &hit, dist, color);
  1340. X}
  1341. X
  1342. Xshade(pos, ray, nrm, prim, surf, back, color, contrib)
  1343. XVector *pos, *nrm;
  1344. XRay *ray;
  1345. XPrimitive *prim;
  1346. XSurface *surf;
  1347. XColor *back, *color;
  1348. Xdouble contrib;
  1349. X{
  1350. X    int lnum, entering;
  1351. X    double dist, k;
  1352. X    Color newcol;
  1353. X    Ray NewRay;
  1354. X    HitInfo hitinfo;
  1355. X    Vector refl;
  1356. X    Light *lp;
  1357. X    extern int nlight;
  1358. X    extern Light light[];
  1359. X    extern unsigned long ReflectRays, RefractRays;
  1360. X    extern double TraceRay();
  1361. X
  1362. X    /*
  1363. X     * Ambient color is always included.
  1364. X     */
  1365. X    *color = surf->amb;
  1366. X
  1367. X    /*
  1368. X     * Calculate direction of reflected ray.
  1369. X     */
  1370. X    k = -dotp(&ray->dir, nrm);
  1371. X    addscaledvec(ray->dir, 2.*k, *nrm, &refl);
  1372. X
  1373. X    /*
  1374. X     * Calculate intensity contributed by each light source.
  1375. X     */
  1376. X    for(lnum = 0, lp = light;lnum < nlight; lnum++, lp++) {
  1377. X        if (lp->type == EXTENDED)
  1378. X            extended_lightray(pos, nrm, &refl, lp,
  1379. X                      prim, surf, color);
  1380. X        else
  1381. X            generic_lightray(pos, nrm, &refl, lp,
  1382. X                     prim, surf, color);
  1383. X    }
  1384. X
  1385. X
  1386. X    if (level >= maxlevel)
  1387. X        /*
  1388. X         * Don't spawn any refracted/reflected rays.
  1389. X         */
  1390. X        return;
  1391. X    /*
  1392. X     * Specular reflection.
  1393. X     */
  1394. X    if(surf->refl > 0. && contrib * surf->refl > TreeCutoff) {
  1395. X        level++;
  1396. X        NewRay.shadow = FALSE;
  1397. X        NewRay.pos = *pos;        /* Origin == hit point */
  1398. X        NewRay.dir = refl;        /* Direction == reflection */
  1399. X        NewRay.media = ray->media;    /* Medium == old medium */
  1400. X        ReflectRays++;
  1401. X        dist = TraceRay(prim, &NewRay, &hitinfo);
  1402. X        if (dist > EPSILON) {
  1403. X            ShadeRay(&hitinfo, &NewRay, dist, back, &newcol,
  1404. X                    contrib*surf->refl);
  1405. X            AddScaledColor(*color, surf->refl, newcol, color);
  1406. X        } else
  1407. X            AddScaledColor(*color, surf->refl, *back, color);
  1408. X        level--;
  1409. X    }
  1410. X    /*
  1411. X     * Specular transmission (refraction).
  1412. X     */
  1413. X    if(surf->transp > 0. && contrib * surf->transp > TreeCutoff) {
  1414. X        NewRay.shadow = FALSE;
  1415. X        NewRay.pos = *pos;        /* Origin == hit point */
  1416. X        NewRay.media = ray->media;    /* Media == old media */
  1417. X        if (k < 0.) {
  1418. X            /*
  1419. X             * Normal points "away" from incoming ray.
  1420. X             * Hit "inside" surface -- assume we're exiting.
  1421. X             * Pop medium from stack.
  1422. X             */
  1423. X            if (NewRay.media == (SurfaceList *)0)
  1424. X                /*
  1425. X                 * We had a funky intersection at some
  1426. X                 * point -- e.g. we hit at the intersection
  1427. X                 * of two refracting surfaces. Skip it.
  1428. X                 */
  1429. X                return;
  1430. X            free((char *)NewRay.media);
  1431. X            NewRay.media = NewRay.media->next;
  1432. X            if (refract(&NewRay.dir, surf->kref,
  1433. X                NewRay.media ? NewRay.media->surf->kref :
  1434. X                DefIndex, ray->dir, *nrm, k))
  1435. X                return;
  1436. X            entering = FALSE;
  1437. X        } else {
  1438. X            /*
  1439. X             * Entering surface.
  1440. X             */
  1441. X            if (refract(&NewRay.dir,
  1442. X                NewRay.media ? NewRay.media->surf->kref :
  1443. X                DefIndex, surf->kref, ray->dir, *nrm, k))
  1444. X                return;
  1445. X            NewRay.media = add_surface(surf, NewRay.media);
  1446. X            entering = TRUE;
  1447. X        }
  1448. X        level++;
  1449. X        RefractRays++;
  1450. X        dist = TraceRay((Primitive *)NULL, &NewRay, &hitinfo);
  1451. X        if (dist > EPSILON) {
  1452. X            ShadeRay(&hitinfo, &NewRay, dist, back, &newcol,
  1453. X                contrib * surf->transp);
  1454. X            AddScaledColor(*color, surf->transp, newcol, color);
  1455. X        } else
  1456. X            AddScaledColor(*color, surf->transp, *back, color);
  1457. X        if (entering)
  1458. X            free((char *)NewRay.media);
  1459. X        level--;
  1460. X    }
  1461. X}
  1462. X
  1463. X/*
  1464. X * Sample an extended (area) light source.
  1465. X */
  1466. Xextended_lightray(pos, norm, refl, lp, obj, surf, color)
  1467. XVector *pos, *norm, *refl;
  1468. XLight *lp;
  1469. XPrimitive *obj;
  1470. XSurface *surf;
  1471. XColor *color;
  1472. X{
  1473. X    int uSample, vSample;
  1474. X    double jit, vbase, ubase, vpos, upos;
  1475. X    Color newcol;
  1476. X    Vector Uaxis, Vaxis, toLight, SampleDir;
  1477. X    extern double lightdist, JitterWeight, SampleSpacing;
  1478. X    extern int JitSamples, Jittered, SampleNumber;
  1479. X
  1480. X    /*
  1481. X     * Determinte two orthoganal vectors which line in the plane
  1482. X     * whose normal is defined by the vector from the center
  1483. X     * of the light source to the point of intersection and
  1484. X     * which passes through the center of the light source.
  1485. X     */
  1486. X    LightCoordSys(lp, pos, &toLight, &Uaxis, &Vaxis);
  1487. X    jit = 2. * lp->radius * SampleSpacing;
  1488. X
  1489. X    if (Jittered) {
  1490. X        /*
  1491. X         * Sample a single point, determined by SampleNumber,
  1492. X         * on the extended source.
  1493. X         */
  1494. X        vpos = -lp->radius + (SampleNumber % JitSamples) * jit;
  1495. X        upos = -lp->radius + (SampleNumber / JitSamples) * jit;
  1496. X        vpos += nrand() * jit;
  1497. X        upos += nrand() * jit;
  1498. X        veccomb(upos, Uaxis, vpos, Vaxis, &SampleDir);
  1499. X        vecadd(toLight, SampleDir, &SampleDir);
  1500. X        /*
  1501. X         * Lightdist, the distance to the light source, is
  1502. X         * used by inshadow(), called from Lighting().
  1503. X         */
  1504. X        lightdist = normalize(&SampleDir);
  1505. X        Lighting(pos,norm,refl,lp,obj,surf,&SampleDir,color);
  1506. X        return;
  1507. X    }
  1508. X
  1509. X    newcol.r = newcol.g = newcol.b = 0.;
  1510. X
  1511. X    /*
  1512. X     * Sample JitSamples^2 -4 points arranged in a square lying on the
  1513. X     * plane calculated above.  The size of the square is equal to
  1514. X     * the diameter of the light source.  We sample the square at equal
  1515. X     * intervals in the U and V direction, with "jitter" thrown in to mask
  1516. X     * aliasing.  The corners of the square are skipped to speed up
  1517. X     * the calculation and to more closely model a circular source.
  1518. X     */
  1519. X    ubase = -lp->radius;
  1520. X    for(uSample = 1;uSample <= JitSamples;uSample++, ubase += jit) {
  1521. X        vbase = -lp->radius;
  1522. X        for(vSample=1;vSample <= JitSamples;vSample++,vbase += jit) {
  1523. X            /*
  1524. X             * Skip corners.
  1525. X             */
  1526. X            if ((uSample == 1 || uSample == JitSamples) &&
  1527. X                (vSample == 1 || vSample == JitSamples))
  1528. X                continue;
  1529. X            vpos = vbase + nrand() * jit;
  1530. X            upos = ubase + nrand() * jit;
  1531. X            veccomb(upos, Uaxis, vpos, Vaxis, &SampleDir);
  1532. X            vecadd(toLight, SampleDir, &SampleDir);
  1533. X            lightdist = normalize(&SampleDir);
  1534. X            Lighting(pos, norm, refl, lp, obj, surf,
  1535. X                &SampleDir, &newcol);
  1536. X        }
  1537. X    }
  1538. X
  1539. X    AddScaledColor(*color, JitterWeight, newcol, color);
  1540. X}
  1541. X
  1542. X/*
  1543. X * Lighting calculations for a point or directional light source.
  1544. X */
  1545. Xgeneric_lightray(pos, norm, reflect, lp, obj, surf, color)
  1546. XVector *pos, *norm, *reflect;
  1547. XLight *lp;
  1548. XPrimitive *obj;
  1549. XSurface *surf;
  1550. XColor *color;
  1551. X{
  1552. X    Vector Nlightray;
  1553. X
  1554. X    lightray(lp, pos, &Nlightray);
  1555. X
  1556. X    Lighting(pos, norm, reflect, lp, obj, surf, &Nlightray, color);
  1557. X}
  1558. X
  1559. X/*
  1560. X * Compute shading function (diffuse reflection and specular highlight)
  1561. X * given the point of intersection, incident ray, normal to the surface,
  1562. X * direction of the reflected ray,
  1563. X * the current light source, the object hit, the surface hit, and
  1564. X * the ray to the current light source.
  1565. X *
  1566. X * This function *adds* the computed color to "color".
  1567. X */
  1568. XLighting(pos, norm, refl, lp, obj, surf, tolight, color)
  1569. XVector *pos, *norm, *refl, *tolight;
  1570. XLight *lp;
  1571. XPrimitive *obj;
  1572. XSurface *surf;
  1573. XColor *color;
  1574. X{
  1575. X    Color bright;
  1576. X    double intens;
  1577. X
  1578. X    /*
  1579. X     * Diffuse reflection.
  1580. X     * Falls off as the cosine of the angle between
  1581. X     * the normal and the ray to the light.
  1582. X     */
  1583. X    intens = dotp(norm, tolight);
  1584. X    if(intens <= 0.) {
  1585. X        /*
  1586. X         * Object does not face light source.
  1587. X         * If the surface is translucent, add in
  1588. X         * diffuse and specular components due to
  1589. X         * light hitting the other side of the surface.
  1590. X         * (This is a "poor man's" diffuse transmission
  1591. X         * and specularly transmitted highlights.  Note
  1592. X         * that we ignore index of refraction here...)
  1593. X         */
  1594. X        if (surf->translucency == 0.)
  1595. X            return;
  1596. X        if (inshadow(&bright, obj, lp, pos, tolight))
  1597. X            return;
  1598. X        /*
  1599. X         * We use -translucency to counter the fact
  1600. X         * that intens is < 0.
  1601. X         */
  1602. X        intens *= -surf->translucency;
  1603. X        color->r += surf->diff.r * intens * bright.r;
  1604. X        color->g += surf->diff.g * intens * bright.g;
  1605. X        color->b += surf->diff.b * intens * bright.b;
  1606. X        intens = -dotp(refl, tolight);
  1607. X        if (intens <= 0.)
  1608. X            return;
  1609. X        intens = surf->translucency * pow(intens, surf->stcoef);
  1610. X        color->r += surf->spec.r * intens * bright.r;
  1611. X        color->g += surf->spec.g * intens * bright.g;
  1612. X        color->b += surf->spec.b * intens * bright.b;
  1613. X        return;
  1614. X    }
  1615. X    /*
  1616. X     * Add diffuse reflection component.
  1617. X     */
  1618. X    if (inshadow(&bright, obj, lp, pos, tolight))
  1619. X        return;        /* Object in shadow. */
  1620. X    color->r += surf->diff.r * intens * bright.r;
  1621. X    color->g += surf->diff.g * intens * bright.g;
  1622. X    color->b += surf->diff.b * intens * bright.b;
  1623. X    /*
  1624. X     * Specularly reflected highlights.
  1625. X     * Fall off as the cosine of the angle
  1626. X     * between the reflected ray and the ray to the light source.
  1627. X     */
  1628. X    if (surf->coef < EPSILON)
  1629. X        return;
  1630. X    intens = dotp(refl, tolight);
  1631. X    if(intens <= 0.)
  1632. X        return;
  1633. X    /*
  1634. X     * Specular highlight = cosine of the angle raised to the
  1635. X     * appropriate power.
  1636. X     */
  1637. X    intens = pow(intens, surf->coef);
  1638. X    color->r += surf->spec.r * intens * bright.r;
  1639. X    color->g += surf->spec.g * intens * bright.g;
  1640. X    color->b += surf->spec.b * intens * bright.b;
  1641. X}
  1642. END_OF_FILE
  1643. if test 10618 -ne `wc -c <'src/shade.c'`; then
  1644.     echo shar: \"'src/shade.c'\" unpacked with wrong size!
  1645. fi
  1646. # end of 'src/shade.c'
  1647. fi
  1648. echo shar: End of archive 5 \(of 8\).
  1649. cp /dev/null ark5isdone
  1650. MISSING=""
  1651. for I in 1 2 3 4 5 6 7 8 ; do
  1652.     if test ! -f ark${I}isdone ; then
  1653.     MISSING="${MISSING} ${I}"
  1654.     fi
  1655. done
  1656. if test "${MISSING}" = "" ; then
  1657.     echo You have unpacked all 8 archives.
  1658.     rm -f ark[1-9]isdone
  1659. else
  1660.     echo You still need to unpack the following archives:
  1661.     echo "        " ${MISSING}
  1662. fi
  1663. ##  End of shell archive.
  1664. exit 0
  1665.  
  1666.  
  1667.