home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume21 / sipp / part04 < prev    next >
Text File  |  1991-07-23  |  51KB  |  1,681 lines

  1. Newsgroups: comp.sources.misc
  2. From: Jonas Yngvesson <jonas-y@isy.liu.se>
  3. Subject:  v21i029:  sipp - A 3D rendering library v2.1, Part04/08
  4. Message-ID: <1991Jul23.181700.27805@sparky.IMD.Sterling.COM>
  5. X-Md4-Signature: b09f7aedec58793386724d8ce2f19af1
  6. Date: Tue, 23 Jul 1991 18:17:00 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: Jonas Yngvesson <jonas-y@isy.liu.se>
  10. Posting-number: Volume 21, Issue 29
  11. Archive-name: sipp/part04
  12. Supersedes: sipp2.0: Volume 16, Issue 5-10
  13. Environment: UNIX
  14.  
  15. #!/bin/sh
  16. # This is part 04 of sipp-2.1
  17. # ============= libsipp/rendering.c ==============
  18. if test ! -d 'libsipp'; then
  19.     echo 'x - creating directory libsipp'
  20.     mkdir 'libsipp'
  21. fi
  22. if test -f 'libsipp/rendering.c' -a X"$1" != X"-c"; then
  23.     echo 'x - skipping libsipp/rendering.c (File already exists)'
  24. else
  25. echo 'x - extracting libsipp/rendering.c (Text)'
  26. sed 's/^X//' << 'SHAR_EOF' > 'libsipp/rendering.c' &&
  27. /**
  28. X ** sipp - SImple Polygon Processor
  29. X **
  30. X **  A general 3d graphic package
  31. X **
  32. X **  Copyright Jonas Yngvesson  (jonas-y@isy.liu.se) 1988/89/90/91
  33. X **            Inge Wallin      (ingwa@isy.liu.se)         1990/91
  34. X **
  35. X ** This program is free software; you can redistribute it and/or modify
  36. X ** it under the terms of the GNU General Public License as published by
  37. X ** the Free Software Foundation; either version 1, or any later version.
  38. X ** This program is distributed in the hope that it will be useful,
  39. X ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  40. X ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  41. X ** GNU General Public License for more details.
  42. X ** You can receive a copy of the GNU General Public License from the
  43. X ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  44. X **/
  45. X
  46. /**
  47. X ** rendering.c - Functions that handles rendering of the scene.
  48. X **/
  49. X
  50. #include <stdio.h>
  51. #ifndef NOMEMCPY
  52. #include <memory.h>
  53. #endif
  54. X
  55. #include <xalloca.h>
  56. #include <smalloc.h>
  57. X
  58. #include <lightsource.h>
  59. #include <geometric.h>
  60. #include <rendering.h>
  61. #include <objects.h>
  62. #include <sipp.h>
  63. #include <sipp_bitmap.h>
  64. #include <viewpoint.h>
  65. #include <patchlevel.h>
  66. X
  67. char *SIPP_VERSION = "2.1";
  68. X
  69. /*
  70. X * Static global variables.
  71. X */
  72. static bool          show_backfaces;  /* Don't do backface culling */
  73. static Edge        **y_bucket;        /* Y-bucket for edge lists. */
  74. static FILE         *image_file;      /* File to store image in      */
  75. X                                      /* when rendering into a file. */
  76. static void         *image_pm;        /* Pixmap to store image in when */
  77. X                                      /* rendering into a pix/bitmap.  */
  78. static void        (*pixmap_set)();   /* Pointer to function for setting    */
  79. X                                      /* a pixel or draw a line in image_pm */
  80. X
  81. X
  82. /*
  83. X * Stack of transformation matrices used
  84. X * when traversing an object hierarchy.
  85. X */
  86. static struct tm_stack_t {
  87. X    Transf_mat         mat;
  88. X    struct tm_stack_t *next;
  89. } *tm_stack;
  90. X
  91. static Transf_mat      curr_mat;     /* Current transformation matrix */
  92. X
  93. X
  94. X
  95. /*
  96. X * Calculate the normal vector for all polygons in the polygon list PSTART.
  97. X *
  98. X * Check if the polygon is backfacing with respect to the current
  99. X * viewpoint.
  100. X *
  101. X * The normalized normal is added to a normal kept at each vertex
  102. X * in the polygon. This will produce, at each vertex, an average of the
  103. X * normals of the adjectent plygons.
  104. X */
  105. static void
  106. calc_normals(pstart, eyepoint)
  107. X    Polygon *pstart;    /* Head of polygon list */
  108. X    Vector   eyepoint;  /* Viewpoint transformed to local coordinate system */
  109. {
  110. X    Vector      normal;
  111. X    Vertex_ref *vref1, *vref2;
  112. X    Polygon    *polyref;
  113. X    double      plane_const;
  114. X
  115. X    for (polyref = pstart; polyref != NULL; polyref = polyref->next) {
  116. X        vref1 = polyref->vertices;
  117. X        vref2 = vref1->next;
  118. X
  119. X        normal.x = normal.y = normal.z = 0.0;
  120. X        do {
  121. X            normal.x += ((vref1->vertex->y - vref2->vertex->y)
  122. X                         * (vref1->vertex->z + vref2->vertex->z));
  123. X            normal.y += ((vref1->vertex->z - vref2->vertex->z)
  124. X                         * (vref1->vertex->x + vref2->vertex->x));
  125. X            normal.z += ((vref1->vertex->x - vref2->vertex->x)
  126. X                         * (vref1->vertex->y + vref2->vertex->y));
  127. X            vref1 = vref1->next;
  128. X            vref2 = ((vref2->next == NULL)?polyref->vertices:vref2->next);
  129. X        } while (vref1 != NULL);
  130. X        vecnorm(&normal);
  131. X
  132. X        /*
  133. X         * Take care of backfacing polygons.
  134. X         */
  135. X        plane_const = -(normal.x * vref2->vertex->x
  136. X                        + normal.y * vref2->vertex->y
  137. X                        + normal.z * vref2->vertex->z);
  138. X        if (VecDot(eyepoint, normal) + plane_const <= 0.0) {
  139. X            if (show_backfaces) {
  140. X                polyref->backface = FALSE;
  141. X                VecNegate(normal);
  142. X            } else {
  143. X                polyref->backface = TRUE;
  144. X            }
  145. X        } else {
  146. X            polyref->backface = FALSE;
  147. X        }
  148. X            
  149. X        /*
  150. X         * Add the calculated normal to all vertices
  151. X         * in the poygon. This will result in an avaraged normal
  152. X         * at each vertex after all polygons have been pprocessed.
  153. X         */
  154. X        for (vref1 = polyref->vertices; vref1 != NULL; vref1 = vref1->next) {
  155. X            vref1->vertex->a += normal.x;
  156. X            vref1->vertex->b += normal.y;
  157. X            vref1->vertex->c += normal.z;
  158. X        }
  159. X    }
  160. }
  161. X
  162. X
  163. X
  164. /*
  165. X * Walk around a polygon, create the surrounding
  166. X * edges and sort them into the y-bucket.
  167. X */
  168. static void
  169. create_edges(view_vert, polygon, surface, render_mode)
  170. X    View_coord *view_vert;
  171. X    int         polygon;
  172. X    Surface    *surface;
  173. X    int         render_mode;
  174. {
  175. X    Edge       *edge;
  176. X    View_coord *view_ref, *last;
  177. X    int         nderiv, y1, y2;
  178. X    double      deltay;
  179. X    double      x1, x2, xstep;
  180. X    double      z1, z2, zstep;
  181. X    double      nx1, nx2, nxstep;
  182. X    double      ny1, ny2, nystep;
  183. X    double      nz1, nz2, nzstep;
  184. X    double      u1, u2, ustep;
  185. X    double      v1, v2, vstep;
  186. X    double      w1, w2, wstep;
  187. X
  188. X
  189. X    view_ref = last = view_vert;
  190. X
  191. X    do {
  192. X        view_ref = view_ref->next;
  193. X
  194. X        /*
  195. X         * If we are drawing a line image we dont need
  196. X         * to build a complete edgelist. We draw the
  197. X         * lines directly instead.
  198. X         *
  199. X         * Since many lines are drawn twice (edges shared between
  200. X         * two polygons) and many line drawing algorithms are unsymmetrical
  201. X         * we need to make sure lines are always drawn in the same
  202. X         * direction
  203. X         */
  204. X        if (render_mode == LINE) {
  205. X            if (view_ref->y < view_ref->next->y) {
  206. X                (*pixmap_set)(image_pm, 
  207. X                              (int)(view_ref->x + 0.5), 
  208. X                              (int)(view_ref->y + 0.5),
  209. X                              (int)(view_ref->next->x + 0.5), 
  210. X                              (int)(view_ref->next->y + 0.5));
  211. X            } else {
  212. X                (*pixmap_set)(image_pm, 
  213. X                              (int)(view_ref->next->x + 0.5), 
  214. X                              (int)(view_ref->next->y + 0.5), 
  215. X                              (int)(view_ref->x + 0.5), 
  216. X                              (int)(view_ref->y + 0.5));
  217. X            }
  218. X            continue;
  219. X        }
  220. X
  221. X        /*
  222. X         * Check if the slope of the edge is positive or negative
  223. X         * or zero.
  224. X         */
  225. X        y1 = (int)(view_ref->y + 0.5);
  226. X        y2 = (int)(view_ref->next->y + 0.5);
  227. X        deltay = (double)(y2 - y1);
  228. X
  229. X        if (deltay > 0.0)
  230. X            nderiv = 1;
  231. X        else if (deltay < 0.0)
  232. X            nderiv = -1;
  233. X        else
  234. X            nderiv = 0;
  235. X
  236. X        /*
  237. X         * Check if the edge is horizontal. In that case we
  238. X         * just skip it.
  239. X         */
  240. X        if (nderiv != 0) {
  241. X
  242. X            edge = (Edge *)smalloc(sizeof(Edge));
  243. X
  244. X            x1 = view_ref->x;
  245. X            x2 = view_ref->next->x;
  246. X            z1 = view_ref->z;
  247. X            z2 = view_ref->next->z;
  248. X            nx1 = view_ref->nx;
  249. X            nx2 = view_ref->next->nx;
  250. X            ny1 = view_ref->ny;
  251. X            ny2 = view_ref->next->ny;
  252. X            nz1 = view_ref->nz;
  253. X            nz2 = view_ref->next->nz;
  254. X            u1 = view_ref->u;
  255. X            u2 = view_ref->next->u;
  256. X            v1 = view_ref->v;
  257. X            v2 = view_ref->next->v;
  258. X            w1 = view_ref->w;
  259. X            w2 = view_ref->next->w;
  260. X
  261. X            deltay = fabs(deltay);
  262. X            xstep = (x2 - x1) / deltay;
  263. X            zstep = (z2 - z1) / deltay;
  264. X            if (render_mode != FLAT) {
  265. X                nxstep = (nx2 - nx1) / deltay;
  266. X                nystep = (ny2 - ny1) / deltay;
  267. X                nzstep = (nz2 - nz1) / deltay;
  268. X                if (render_mode == PHONG) {
  269. X                    ustep = (u2 - u1) / deltay;
  270. X                    vstep = (v2 - v1) / deltay;
  271. X                    wstep = (w2 - w1) / deltay;
  272. X                }
  273. X            }
  274. X
  275. X            if (nderiv > 0) {       
  276. X
  277. X                /*
  278. X                 * The edge has positive slope
  279. X                 */
  280. X                edge->y = y2;
  281. X                edge->y_stop = y1;
  282. X                edge->x = x2;
  283. X                edge->z = z2;
  284. X                edge->nx = nx2;
  285. X                edge->ny = ny2;
  286. X                edge->nz = nz2;
  287. X                edge->u = u2;
  288. X                edge->v = v2;
  289. X                edge->w = w2;
  290. X                edge->xstep = -xstep;
  291. X                edge->zstep = -zstep;
  292. X                if (render_mode != FLAT) {
  293. X                    edge->nxstep = -nxstep;
  294. X                    edge->nystep = -nystep;
  295. X                    edge->nzstep = -nzstep;
  296. X                    if (render_mode == PHONG) {
  297. X                        edge->ustep = -ustep;
  298. X                        edge->vstep = -vstep;
  299. X                        edge->wstep = -wstep;
  300. X                    }
  301. X                }
  302. X
  303. X            } else {
  304. X
  305. X                /*
  306. X                 * The edge has negative slope.
  307. X                 */
  308. X                edge->y = y1;
  309. X                edge->y_stop = y2;
  310. X                edge->x = x1;
  311. X                edge->z = z1;
  312. X                edge->nx = nx1;
  313. X                edge->ny = ny1;
  314. X                edge->nz = nz1;
  315. X                edge->u = u1;
  316. X                edge->v = v1;
  317. X                edge->w = w1;
  318. X                edge->xstep = xstep;
  319. X                edge->zstep = zstep;
  320. X                if (render_mode != FLAT) {
  321. X                    edge->nxstep = nxstep;
  322. X                    edge->nystep = nystep;
  323. X                    edge->nzstep = nzstep;
  324. X                    if (render_mode == PHONG) {
  325. X                        edge->ustep = ustep;
  326. X                        edge->vstep = vstep;
  327. X                        edge->wstep = wstep;
  328. X                    }
  329. X                }
  330. X            }
  331. X            edge->polygon = polygon;
  332. X            edge->surface = surface;
  333. X            edge->next = y_bucket[edge->y];
  334. X            y_bucket[edge->y] = edge;
  335. X        }
  336. X    } while (view_ref != last);
  337. }
  338. X
  339. X
  340. X
  341. /*
  342. X * Calculate a new vertex by interpolation between
  343. X * V1 and V2.
  344. X */
  345. static View_coord *
  346. interpolate(v1, v2, ratio)
  347. X    View_coord *v1, *v2;
  348. X    double      ratio;
  349. {
  350. X    View_coord *tmp;
  351. X
  352. X    tmp = (View_coord *)smalloc(sizeof(View_coord));
  353. X
  354. X    tmp->x = v1->x + ratio * (v2->x - v1->x);
  355. X    tmp->y = v1->y + ratio * (v2->y - v1->y);
  356. X    tmp->z = v1->z + ratio * (v2->z - v1->z);
  357. X    tmp->nx = v1->nx + ratio * (v2->nx - v1->nx);
  358. X    tmp->ny = v1->ny + ratio * (v2->ny - v1->ny);
  359. X    tmp->nz = v1->nz + ratio * (v2->nz - v1->nz);
  360. X    tmp->u = v1->u + ratio * (v2->u - v1->u);
  361. X    tmp->v = v1->v + ratio * (v2->v - v1->v);
  362. X    tmp->w = v1->w + ratio * (v2->w - v1->w);
  363. X    tmp->next = NULL;
  364. X
  365. X    return tmp;
  366. }
  367. X
  368. X
  369. X
  370. /*
  371. X * Clip a polygon using the Sutherland-Hodgeman algorithm for
  372. X * reentrant clipping;
  373. X */
  374. #define XMIN 0
  375. #define XMAX 1
  376. #define YMIN 2
  377. #define YMAX 3
  378. #define ZMIN 4
  379. #define ZMAX 5
  380. X
  381. static View_coord *
  382. polygon_clip(vlist, plane, first_vert)
  383. X    View_coord *vlist;
  384. X    int         plane;
  385. X    bool        first_vert;
  386. {
  387. X    static View_coord   *first;
  388. X    static View_coord   *curr;
  389. X    View_coord          *out1;
  390. X    View_coord          *out2;
  391. X    double               curr_limit;
  392. X    double               first_limit;
  393. X    double               vlist_limit;
  394. X    double               ratio;
  395. X    bool                 visible;
  396. X
  397. X    out1 = out2 = NULL;
  398. X
  399. X    if (vlist == NULL) {
  400. X
  401. X        /*
  402. X         * Did we get an empty list from the start?
  403. X         */
  404. X        if (first_vert) {
  405. X            return NULL;
  406. X        }
  407. X
  408. X        /*
  409. X         * Last vertex, close the polygon.
  410. X         */
  411. X        ratio = 0.0;
  412. X        curr_limit = curr->z * camera.focal_ratio;
  413. X        first_limit = first->z * camera.focal_ratio;
  414. X
  415. X        switch (plane) {
  416. X
  417. X          case XMIN:
  418. X            if ((curr->x < -curr_limit && first->x >= -first_limit)
  419. X                || (curr->x >= -curr_limit && first->x < -first_limit)) {
  420. X                ratio = fabs(curr->x + curr_limit);
  421. X                ratio /= (ratio + fabs(first->x + first_limit)); 
  422. X            }
  423. X            break;
  424. X
  425. X          case XMAX:
  426. X            if ((curr->x <= curr_limit && first->x > first_limit)
  427. X                || (curr->x > curr_limit && first->x <= first_limit)) {
  428. X                ratio = fabs(curr->x - curr_limit);
  429. X                ratio /= (ratio + fabs(first->x - first_limit));
  430. X            }
  431. X            break;
  432. X
  433. X          case YMIN:
  434. X            if ((curr->y < -curr_limit && first->y >= -first_limit)
  435. X                || (curr->y >= -curr_limit && first->y < -first_limit)) {
  436. X                ratio = fabs(curr->y + curr_limit);
  437. X                ratio /= (ratio + fabs(first->y + first_limit));
  438. X            }
  439. X            break;
  440. X
  441. X          case YMAX:
  442. X            if ((curr->y <= curr_limit && first->y > first_limit)
  443. X                || (curr->y > curr_limit && first->y <= first_limit)) {
  444. X                ratio = fabs(curr->y - curr_limit);
  445. X                ratio /= (ratio + fabs(first->y - first_limit));
  446. X            }
  447. X            break;
  448. X
  449. X          case ZMIN:
  450. X            if ((curr->z < hither && first->z >= hither)
  451. X                || (curr->z >= hither && first->z < hither)) {
  452. X                ratio = fabs(curr->z - hither);
  453. X                ratio = ratio / (ratio + fabs(first->z - hither));
  454. X            }
  455. X            break;
  456. X
  457. X          case ZMAX:
  458. X            if ((curr->z <= yon && first->z > yon)
  459. X                || (curr->z > yon && first->z <= yon)) {
  460. X                ratio = fabs(curr->z - yon);
  461. X                ratio = ratio / (ratio + fabs(first->z - yon));
  462. X            }
  463. X            break;
  464. X        }
  465. X
  466. X        if (ratio != 0.0) {
  467. X            out1 = interpolate(curr, first, ratio);
  468. X            return out1;
  469. X        } else {
  470. X            return NULL;
  471. X        }
  472. X    }
  473. X
  474. X    vlist_limit = vlist->z * camera.focal_ratio;
  475. X    
  476. X    if (first_vert) {
  477. X        first = vlist;
  478. X    } else {
  479. X        ratio = 0.0;
  480. X        curr_limit = curr->z * camera.focal_ratio;
  481. X
  482. X        switch (plane) {
  483. X
  484. X          case XMIN:
  485. X            if ((curr->x < -curr_limit && vlist->x >= -vlist_limit)
  486. X                || (curr->x >= -curr_limit && vlist->x < -vlist_limit)) {
  487. X                ratio = fabs(curr->x + curr_limit);
  488. X                ratio /= (ratio + fabs(vlist->x + vlist_limit));
  489. X            }
  490. X            break;
  491. X
  492. X          case XMAX:
  493. X            if ((curr->x <= curr_limit && vlist->x > vlist_limit)
  494. X                || (curr->x > curr_limit && vlist->x <= vlist_limit)) {
  495. X                ratio = fabs(curr->x - curr_limit);
  496. X                ratio /= (ratio + fabs(vlist->x - vlist_limit));
  497. X            }
  498. X            break;
  499. X
  500. X          case YMIN:
  501. X            if ((curr->y < -curr_limit && vlist->y >= -vlist_limit)
  502. X                || (curr->y >= -curr_limit && vlist->y < -vlist_limit)) {
  503. X                ratio = fabs(curr->y + curr_limit);
  504. X                ratio /= (ratio + fabs(vlist->y + vlist_limit));
  505. X            }
  506. X            break;
  507. X
  508. X          case YMAX:
  509. X            if ((curr->y <= curr_limit && vlist->y > vlist_limit)
  510. X                || (curr->y > curr_limit && vlist->y <= vlist_limit)) {
  511. X                ratio = fabs(curr->y - curr_limit);
  512. X                ratio /= (ratio + fabs(vlist->y - vlist_limit));
  513. X            }
  514. X            break;
  515. X
  516. X          case ZMIN:
  517. X            if ((curr->z < hither && vlist->z >= hither)
  518. X                || (curr->z >= hither && vlist->z < hither)) {
  519. X                ratio = fabs(curr->z - hither);
  520. X                ratio = ratio / (ratio + fabs(vlist->z - hither));
  521. X            }
  522. X            break;
  523. X
  524. X          case ZMAX:
  525. X            if ((curr->z <= yon && vlist->z > yon)
  526. X                || (curr->z > yon && vlist->z <= yon)) {
  527. X                ratio = fabs(curr->z - yon);
  528. X                ratio = ratio / (ratio + fabs(vlist->z - yon));
  529. X            }
  530. X            break;
  531. X        }
  532. X
  533. X        if (ratio != 0.0) {
  534. X            out1 = interpolate(curr, vlist, ratio);
  535. X            out1->next = vlist;
  536. X        }
  537. X    }
  538. X
  539. X    curr = vlist;
  540. X    visible = FALSE;
  541. X    switch (plane) {
  542. X
  543. X      case XMIN:
  544. X        visible = (curr->x >= -vlist_limit);
  545. X        break;
  546. X
  547. X      case XMAX:
  548. X        visible = (curr->x <= vlist_limit);
  549. X        break;
  550. X
  551. X      case YMIN:
  552. X        visible = (curr->y >= -vlist_limit);
  553. X        break;
  554. X
  555. X      case YMAX:
  556. X        visible = (curr->y <= vlist_limit);
  557. X        break;
  558. X
  559. X      case ZMIN:
  560. X        visible = (curr->z >= hither);
  561. X        break;
  562. X
  563. X      case ZMAX:
  564. X        visible = (curr->z <= yon);
  565. X        break;
  566. X    }
  567. X
  568. X    if (visible) {
  569. X        out2 = curr;
  570. X        out2->next = polygon_clip(curr->next, plane, FALSE);
  571. X        return ((out1) ? (out1) : (out2));
  572. X
  573. X    } else {
  574. X        if (out1) {
  575. X            out1->next = polygon_clip(curr->next, plane, FALSE);
  576. X        } else {
  577. X            out1 = polygon_clip(curr->next, plane, FALSE);
  578. X        }
  579. X        free(vlist);
  580. X        return out1;
  581. X    }
  582. }
  583. X
  584. X
  585. X
  586. /*
  587. X * Transform vertices into view coordinates. The transform is
  588. X * defined in MATRIX. Store the transformed vertices in a
  589. X * temporary list, create edges in the y_bucket.
  590. X */
  591. static void
  592. transf_vertices(vertex_list, surface, view_mat, tr_mat, 
  593. X                xsiz, ysiz, render_mode)
  594. X    Vertex_ref *vertex_list;
  595. X    Surface    *surface;
  596. X    Transf_mat *view_mat;
  597. X    Transf_mat *tr_mat;
  598. X    double      xsiz, ysiz;
  599. X    int         render_mode;
  600. {
  601. X    static int  polygon = 0;        /* incremented for each call to provide */
  602. X                                    /* unique polygon id numbers */
  603. X    Vertex_ref *vref;
  604. X    View_coord *nhead;
  605. X    View_coord *view_ref;
  606. X    View_coord *mark;
  607. X    Color       color;                    
  608. X    double      minsize;
  609. X    double      tmp;
  610. X
  611. X    vref = vertex_list;
  612. X    nhead = NULL;
  613. X
  614. X    minsize = ((xsiz > ysiz) ? ysiz : xsiz);
  615. X
  616. X    while (vref != NULL) {
  617. X
  618. X        view_ref = (View_coord *)smalloc(sizeof(View_coord));
  619. X
  620. X
  621. X        /*
  622. X         * Transform the normal (world coordinates).
  623. X         */
  624. X        view_ref->nx = (vref->vertex->a * tr_mat->mat[0][0] 
  625. X                        + vref->vertex->b * tr_mat->mat[1][0] 
  626. X                        + vref->vertex->c * tr_mat->mat[2][0]);
  627. X        view_ref->ny = (vref->vertex->a * tr_mat->mat[0][1] 
  628. X                        + vref->vertex->b * tr_mat->mat[1][1] 
  629. X                        + vref->vertex->c * tr_mat->mat[2][1]);
  630. X        view_ref->nz = (vref->vertex->a * tr_mat->mat[0][2] 
  631. X                        + vref->vertex->b * tr_mat->mat[1][2] 
  632. X                        + vref->vertex->c * tr_mat->mat[2][2]);
  633. X
  634. X        /*
  635. X         * Transform the vertex into view coordinates.
  636. X         */
  637. X        view_ref->x = (vref->vertex->x * view_mat->mat[0][0] 
  638. X                       + vref->vertex->y * view_mat->mat[1][0] 
  639. X                       + vref->vertex->z * view_mat->mat[2][0]
  640. X                       + view_mat->mat[3][0]);
  641. X        view_ref->y = (vref->vertex->x * view_mat->mat[0][1] 
  642. X                       + vref->vertex->y * view_mat->mat[1][1] 
  643. X                       + vref->vertex->z * view_mat->mat[2][1]
  644. X                       + view_mat->mat[3][1]);
  645. X        view_ref->z = (vref->vertex->x * view_mat->mat[0][2] 
  646. X                       + vref->vertex->y * view_mat->mat[1][2] 
  647. X                       + vref->vertex->z * view_mat->mat[2][2]
  648. X                       + view_mat->mat[3][2]);
  649. X
  650. X        /*
  651. X         * Texture coordinates is not affected by transformations.
  652. X         */
  653. X        view_ref->u = vref->vertex->u;
  654. X        view_ref->v = vref->vertex->v;
  655. X        view_ref->w = vref->vertex->w;
  656. X
  657. X        view_ref->next = nhead;
  658. X        nhead = view_ref;
  659. X
  660. X        vref = vref->next;
  661. X    }
  662. X
  663. X    /* 
  664. X     * Clip the resulting polygon. We need to do this
  665. X     * before the perpective transformation to keep texture
  666. X     * coordinates correct.
  667. X     */
  668. X    nhead = polygon_clip(nhead, ZMIN, TRUE);
  669. X    nhead = polygon_clip(nhead, ZMAX, TRUE);
  670. X    if (xsiz > ysiz) {
  671. X        tmp = camera.focal_ratio;
  672. X        camera.focal_ratio *= xsiz / ysiz;
  673. X        nhead = polygon_clip(nhead, XMIN, TRUE);
  674. X        nhead = polygon_clip(nhead, XMAX, TRUE);
  675. X        camera.focal_ratio = tmp;
  676. X        nhead = polygon_clip(nhead, YMIN, TRUE);
  677. X        nhead = polygon_clip(nhead, YMAX, TRUE);
  678. X    } else {
  679. X        tmp = camera.focal_ratio;
  680. X        camera.focal_ratio *= ysiz / xsiz;
  681. X        nhead = polygon_clip(nhead, YMIN, TRUE);
  682. X        nhead = polygon_clip(nhead, YMAX, TRUE);
  683. X        camera.focal_ratio = tmp;
  684. X        nhead = polygon_clip(nhead, XMIN, TRUE);
  685. X        nhead = polygon_clip(nhead, XMAX, TRUE);
  686. X    }
  687. X
  688. X    if (nhead == NULL) {    /* Nothing left? */
  689. X        return;
  690. X    }
  691. X
  692. X
  693. X    
  694. X    /*
  695. X     * If we are flat shading, we need a color for the polygon.
  696. X     * We call the shader at the first vertex to get this.
  697. X     * (This is not quite correct since the normal here is
  698. X     * an averaged normal of the surrounding polygons)
  699. X     */
  700. X    if (render_mode == FLAT) {
  701. X        (*surface->shader)
  702. X            (nhead->nx, nhead->ny, nhead->nz, 
  703. X             nhead->u, nhead->v, nhead->w,
  704. X             camera.vec, lightsrc_stack, 
  705. X             surface->surface, &color);
  706. X    }
  707. X
  708. X
  709. X    /*
  710. X     * Walk around the new (clipped and transformed) polygon and 
  711. X     * transform it into perspective screen coordinates.
  712. X     * We have to transform the texture coordinates too in order
  713. X     * to interpolate them linearly in "screen space". This
  714. X     * transformation is inverted in render_line().
  715. X     * If we are doing gouraud shading we call the shader at each
  716. X     * vertex.
  717. X     * Last we tie the head and tail together forming a cirkular
  718. X     * list, this simplifies edge creation.
  719. X     */
  720. X    for (view_ref = nhead;; view_ref = view_ref->next) {
  721. X        view_ref->z *= camera.focal_ratio;
  722. X        view_ref->x  = view_ref->x * minsize / view_ref->z + xsiz;
  723. X        view_ref->y  = view_ref->y * minsize / view_ref->z + ysiz;
  724. X        view_ref->u /= view_ref->z;
  725. X        view_ref->v /= view_ref->z;
  726. X        view_ref->w /= view_ref->z;
  727. X
  728. X        if (render_mode == GOURAUD) {
  729. X            (*surface->shader)
  730. X                (view_ref->nx, view_ref->ny, view_ref->nz, 
  731. X                 view_ref->u, view_ref->v, view_ref->w,
  732. X                 camera.vec, lightsrc_stack, 
  733. X                 surface->surface, &color);
  734. X        } 
  735. X
  736. X        if (render_mode == GOURAUD || render_mode == FLAT) {
  737. X            view_ref->nx = color.red;
  738. X            view_ref->ny = color.grn;
  739. X            view_ref->nz = color.blu;
  740. X        } 
  741. X
  742. X        if (view_ref->next == NULL) {
  743. X            view_ref->next = nhead;
  744. X            break;
  745. X        }
  746. X    }
  747. X
  748. X    create_edges(nhead, polygon++, surface, render_mode);
  749. X
  750. X    /*
  751. X     * Free the memory used by the transformed polygon.
  752. X     */
  753. X    mark = nhead;
  754. X    do {
  755. X        view_ref = nhead;
  756. X        nhead = nhead->next;
  757. X        free(view_ref);
  758. X    } while (nhead != mark);
  759. }
  760. X
  761. X
  762. X
  763. /*
  764. X * Initialize the scanline z-buffer and the actual picture
  765. X * scanline buffer.
  766. X */
  767. static void
  768. init_buffers(res, z_buffer, scanline)
  769. X    int            res;
  770. X    double        *z_buffer;
  771. X    unsigned char *scanline;
  772. {
  773. X    int i;
  774. X    
  775. #ifdef NOMEMCPY
  776. X    bzero(scanline, res * 3);
  777. #else
  778. X    memset(scanline, 0, res * 3);
  779. #endif
  780. X    for (i = 0; i < res; i++)
  781. X        z_buffer[i] = 1.0e100;
  782. }
  783. X    
  784. X
  785. /*
  786. X * Read edge pairs from the edge list EDGE_LIST. Walk along the scanline
  787. X * and interpolate z value, texture coordinates and normal vector as 
  788. X * we go. Call the shader and write into scanline buffer according to 
  789. X * result on z-buffer test.
  790. X */
  791. static void
  792. render_line(res, z_buffer, scanline, edge_list, render_mode)
  793. X    int            res;
  794. X    double        *z_buffer;
  795. X    unsigned char *scanline;
  796. X    Edge          *edge_list;
  797. X    int            render_mode;
  798. {
  799. X    double z, zstep;
  800. X    double nx, nxstep;
  801. X    double ny, nystep;
  802. X    double nz, nzstep;
  803. X    double u, ustep;
  804. X    double v, vstep;
  805. X    double w, wstep;
  806. X    double ur, vr, wr;
  807. X    double ratio;
  808. X    Color  color;
  809. X    int    i, j, x, xstop;
  810. X    Edge  *startedge, *stopedge;
  811. X    
  812. X    startedge = edge_list;
  813. X    stopedge = NULL;
  814. X    while (startedge != NULL) {
  815. X        stopedge = startedge->next;
  816. X        x = (int)(startedge->x + 0.5);
  817. X        xstop = (int)(stopedge->x + 0.5);
  818. X        z = startedge->z;
  819. X        nx = startedge->nx;
  820. X        ny = startedge->ny;
  821. X        nz = startedge->nz;
  822. X        u = startedge->u;
  823. X        v = startedge->v;
  824. X        w = startedge->w;
  825. X        if (x < xstop) {
  826. X            ratio = (double)(xstop - x);
  827. X            zstep = (stopedge->z - z) / ratio;
  828. X            if (render_mode != FLAT) {
  829. X                nxstep = (stopedge->nx - nx) / ratio;
  830. X                nystep = (stopedge->ny - ny) / ratio;
  831. X                nzstep = (stopedge->nz - nz) / ratio;
  832. X                if (render_mode == PHONG) {
  833. X                    ustep = (stopedge->u - u) / ratio;
  834. X                    vstep = (stopedge->v - v) / ratio;
  835. X                    wstep = (stopedge->w - w) / ratio;
  836. X                }
  837. X            }
  838. X        } else {
  839. X            zstep = 0.0;
  840. X            nxstep = nystep = nzstep = 0.0;
  841. X            ustep = vstep = wstep = 0.0;
  842. X        }
  843. X
  844. X        for (i = x, j = i * 3; i <= xstop; i++) {
  845. X
  846. X            if (z < z_buffer[i]) {
  847. X
  848. X                if (render_mode == PHONG) {
  849. X                    ur = u * z;  /* Transform texture coordinates back */
  850. X                    vr = v * z;  /* from their homogenouos form */
  851. X                    wr = w * z;
  852. X                    (*startedge->surface->shader)
  853. X                        (nx, ny, nz, ur, vr, wr,
  854. X                         camera.vec, lightsrc_stack, 
  855. X                         startedge->surface->surface, &color);
  856. X                    scanline[j++] = (unsigned char)(color.red * 255.0 + 0.5);
  857. X                    scanline[j++] = (unsigned char)(color.grn * 255.0 + 0.5);
  858. X                    scanline[j++] = (unsigned char)(color.blu * 255.0 + 0.5);
  859. X                    
  860. X                } else if (render_mode == FLAT || render_mode == GOURAUD) {
  861. X                    scanline[j++] = (unsigned char)(nx * 255.0 + 0.5);
  862. X                    scanline[j++] = (unsigned char)(ny * 255.0 + 0.5);
  863. X                    scanline[j++] = (unsigned char)(nz * 255.0 + 0.5);
  864. X                }
  865. X                
  866. X                z_buffer[i] = z;
  867. X                
  868. X            } else if (i >= res) {
  869. X                break;
  870. X                
  871. X            } else {
  872. X                j += 3;
  873. X            }
  874. X            
  875. X            z += zstep;
  876. X            if (render_mode != FLAT) {
  877. X                nx += nxstep;
  878. X                ny += nystep;
  879. X                nz += nzstep;
  880. X                if (render_mode == PHONG) {
  881. X                    u += ustep;
  882. X                    v += vstep;
  883. X                    w += wstep;
  884. X                }
  885. X            }
  886. X        }
  887. X        startedge = stopedge->next;
  888. X    }
  889. }
  890. X
  891. X
  892. X
  893. X
  894. /*
  895. X * Insert an edge into an edge list. Edges belonging to the same
  896. X * polygon must be inserted sorted in x, so that edge pairs are
  897. X * created.
  898. X */
  899. static Edge *
  900. insert_edge(edge_list, edge, poly_found)
  901. X    Edge *edge_list, *edge;
  902. X    bool  poly_found;
  903. {
  904. X    if (edge_list == NULL) {
  905. X        edge_list = edge;
  906. X    edge->next = NULL;
  907. X    } else if (edge_list->polygon == edge->polygon) {
  908. X        if (edge_list->x > edge->x) {
  909. X        edge->next = edge_list;
  910. X        edge_list = edge;
  911. X    } else if ((((int)(edge_list->x + 0.5)) == ((int)(edge->x + 0.5)))
  912. X                   && (edge_list->xstep > edge->xstep)) {
  913. X        edge->next = edge_list;
  914. X        edge_list = edge;
  915. X        } else {
  916. X        edge_list->next = insert_edge(edge_list->next, edge, TRUE);
  917. X        }
  918. X    } else if (poly_found) {
  919. X        edge->next = edge_list;
  920. X        edge_list = edge;
  921. X    } else {
  922. X        edge_list->next = insert_edge(edge_list->next, edge, FALSE);
  923. X    }
  924. X
  925. X    return edge_list;
  926. }
  927. X        
  928. X
  929. X
  930. /*
  931. X * Merge two edge lists.
  932. X */
  933. static Edge *
  934. merge_edge_lists(list1, list2)
  935. X    Edge *list1, *list2;
  936. {
  937. X    Edge *eref1, *eref2, *next;
  938. X    
  939. X    if (list2 == NULL)
  940. X        return list1;
  941. X
  942. X    eref1 = list1;
  943. X    eref2 = list2;
  944. X    do {
  945. X        next = eref2->next;
  946. X        eref1 = insert_edge(eref1, eref2, FALSE);
  947. X    eref2 = next;
  948. X    } while (eref2 != NULL);
  949. X
  950. X    return eref1;
  951. }
  952. X
  953. X
  954. X
  955. /*
  956. X * Store a rendered line on the place indicated by STORAGE_MODE.
  957. X */
  958. static void
  959. store_line(buf, npixels, line, storage_mode)
  960. X    unsigned char *buf;
  961. X    int            npixels;
  962. X    int            line;
  963. X    int            storage_mode;
  964. {
  965. X    int i, j;
  966. X
  967. X    switch (storage_mode) {
  968. X      case PBM_FILE:
  969. X        fwrite(buf, sizeof(unsigned char), npixels, image_file);
  970. X        fflush(image_file);
  971. X        break;
  972. X        
  973. X      case PPM_FILE:
  974. X        fwrite(buf, sizeof(unsigned char), npixels * 3, image_file);
  975. X        fflush(image_file);
  976. X        break;
  977. X
  978. X      case PIXMAP:
  979. X        for (i = 0, j = 0; j < npixels; j++, i += 3) {
  980. X            (*pixmap_set)(image_pm, j, line, buf[i], buf[i + 1], buf[i + 2]);
  981. X        }
  982. X        break;
  983. X
  984. X      default:
  985. X        break;
  986. X    }
  987. }
  988. X
  989. X
  990. /*
  991. X * Allocate the needed buffers. Create a list of active edges and
  992. X * move down the y-bucket, inserting and deleting edges from this
  993. X * active list as we go. Call render_line for each scanline and
  994. X * do an average filtering before storing the scanline.
  995. X */
  996. static void
  997. scan_and_render(xres, yres, storage_mode, render_mode, oversampl)
  998. X    int   xres, yres;
  999. X    int   storage_mode;
  1000. X    int   render_mode;
  1001. X    int   oversampl;
  1002. {
  1003. X    Edge           *active_list, *edgep, *edgep2;
  1004. X    double         *z_buffer;
  1005. X    unsigned char **linebuf;
  1006. X    int             curr_line;
  1007. X    int             y, next_edge;
  1008. X    int             sum;
  1009. X    int             i, j, k, l;
  1010. X    
  1011. X    z_buffer = (double *)scalloc(xres, sizeof(double));
  1012. X    linebuf  = (unsigned char **)alloca(oversampl * sizeof(unsigned char *));
  1013. X    for (i = 0; i < oversampl; i++) {
  1014. X        linebuf[i] = (unsigned char *)scalloc(xres * 3, sizeof(unsigned char));
  1015. X    }
  1016. X
  1017. X    if (storage_mode == PPM_FILE) {
  1018. X        fprintf(image_file, "P6\n");
  1019. X        fprintf(image_file, "#Image rendered with SIPP %s%s\n", 
  1020. X                SIPP_VERSION, PATCHLEVEL);
  1021. X        fprintf(image_file, "%d\n%d\n255\n", xres / oversampl, 
  1022. X                                             yres / oversampl);
  1023. X    }
  1024. X
  1025. X    y = yres - 1;
  1026. X    active_list = NULL;
  1027. X    curr_line = 0;
  1028. X    while (y >= 0) {
  1029. X
  1030. X        active_list = merge_edge_lists(active_list, y_bucket[y]);
  1031. X        next_edge = y - 1;
  1032. X
  1033. X        while (next_edge >=0 && y_bucket[next_edge] == NULL)
  1034. X            next_edge--;
  1035. X
  1036. X        while (y > next_edge) {
  1037. X
  1038. X            init_buffers(xres, z_buffer, linebuf[curr_line]);
  1039. X            render_line(xres, z_buffer, linebuf[curr_line], active_list,
  1040. X                        render_mode); 
  1041. X
  1042. X            if (++curr_line == oversampl) {
  1043. X
  1044. X                /*
  1045. X                 * Average the pixel.
  1046. X                 */
  1047. X                for (i = 0; i < ((xres / oversampl)); i++) {
  1048. X                    for (l = 0; l < 3; l++) {
  1049. X                        sum = 0;
  1050. X                        for (j = i * 3 * oversampl + l; 
  1051. X                             j < (i * 3 * oversampl + l + 3 * oversampl); 
  1052. X                             j += 3) {
  1053. X                            for (k = 0; k < oversampl; k++) {
  1054. X                                sum += *(linebuf[k] + j);
  1055. X                            }
  1056. X                        }
  1057. X                        *(linebuf[0] + i * 3 + l)
  1058. X                            = sum / (oversampl * oversampl);
  1059. X                    }
  1060. X                }
  1061. X                store_line(linebuf[0], xres / oversampl, 
  1062. X                           (yres - y - 1) / oversampl, storage_mode);
  1063. X                curr_line = 0;
  1064. X            }
  1065. X
  1066. X        if (active_list != NULL) {
  1067. X
  1068. X            edgep2 = active_list;
  1069. X            edgep = active_list->next;
  1070. X            while (edgep != NULL) {
  1071. X                if (edgep->y <= (edgep->y_stop + 1)) {
  1072. X                        edgep2->next = edgep->next;
  1073. X                free(edgep);
  1074. X                    edgep = edgep2->next;
  1075. X            } else {
  1076. X                edgep2 = edgep;
  1077. X                edgep = edgep->next;
  1078. X            }
  1079. X                }
  1080. X
  1081. X              if (active_list->y <= (active_list->y_stop + 1)) {
  1082. X                edgep = active_list;
  1083. X            active_list = active_list->next;
  1084. X                free(edgep);
  1085. X            }
  1086. X
  1087. X            edgep = active_list;
  1088. X            while (edgep != NULL) {
  1089. X                edgep->y--;
  1090. X            edgep->x += edgep->xstep;
  1091. X            edgep->z += edgep->zstep;
  1092. X                    if (render_mode != FLAT) {
  1093. X                        edgep->nx += edgep->nxstep;
  1094. X                        edgep->ny += edgep->nystep;
  1095. X                        edgep->nz += edgep->nzstep;
  1096. X                        if (render_mode == PHONG) {
  1097. X                            edgep->u += edgep->ustep;
  1098. X                            edgep->v += edgep->vstep;
  1099. X                            edgep->w += edgep->wstep;
  1100. X                        }
  1101. X                    }
  1102. X            edgep = edgep->next;
  1103. X            }
  1104. X        }
  1105. X        y--;
  1106. X    }
  1107. X    }
  1108. X    free(z_buffer);
  1109. X    for (i = 0; i < oversampl; i++) {
  1110. X        free(linebuf[i]);
  1111. X    }
  1112. }
  1113. X
  1114. X
  1115. X
  1116. /*
  1117. X * Reset the averaged normals in the vertex tree P.
  1118. X */
  1119. static void
  1120. reset_normals(vref)
  1121. X    Vertex *vref;
  1122. {
  1123. X    if (vref != NULL) {
  1124. X        vref->a = 0;
  1125. X        vref->b = 0;
  1126. X        vref->c = 0;
  1127. X        reset_normals(vref->big);
  1128. X        reset_normals(vref->sml);
  1129. X    }
  1130. }
  1131. X
  1132. X
  1133. X
  1134. /*
  1135. X * Push the current transformation matrix on the matrix stack.
  1136. X */
  1137. static void
  1138. matrix_push()
  1139. {
  1140. X    struct tm_stack_t *new_tm;
  1141. X
  1142. X    new_tm = (struct tm_stack_t *)smalloc(sizeof(struct tm_stack_t));
  1143. X    MatCopy(&new_tm->mat, &curr_mat);
  1144. X    new_tm->next = tm_stack;
  1145. X    tm_stack     = new_tm;
  1146. }
  1147. X
  1148. X
  1149. /*
  1150. X * Pop the top of the matrix stack and make
  1151. X * it the new current transformation matrix.
  1152. X */
  1153. static void
  1154. matrix_pop()
  1155. {
  1156. X    struct tm_stack_t *tmp;
  1157. X
  1158. X    MatCopy(&curr_mat, &tm_stack->mat);
  1159. X    tmp = tm_stack;
  1160. X    tm_stack = tm_stack->next;
  1161. X    free(tmp);
  1162. }
  1163. X
  1164. X
  1165. X
  1166. /*
  1167. X * Traverse an object hierarchy, transform each object
  1168. X * according to its transformation matrix.
  1169. X * Transform all polygons in the object to view coordinates.
  1170. X * Build the edge lists in y_bucket.
  1171. X */
  1172. static void
  1173. traverse_object_tree(object, view_mat, xres, yres, render_mode)
  1174. X    Object      *object;
  1175. X    Transf_mat  *view_mat;
  1176. X    int          xres, yres;
  1177. X    int          render_mode;
  1178. {
  1179. X    Object      *objref;
  1180. X    Surface     *surfref;
  1181. X    Polygon     *polyref;
  1182. X    Vector       eyepoint, tmp;
  1183. X    Transf_mat   loc_view_mat;
  1184. X    double       m[3][4], dtmp;
  1185. X    int          i, j;
  1186. X
  1187. X
  1188. X    if (object == NULL) {
  1189. X        return;
  1190. X    }
  1191. X
  1192. X    for (objref = object; objref != NULL; objref = objref->next) {
  1193. X
  1194. X        matrix_push();
  1195. X        mat_mul(&curr_mat, &objref->transf, &curr_mat);
  1196. X        mat_mul(&loc_view_mat, &curr_mat, view_mat);
  1197. X
  1198. X        tmp.x = camera.x0;
  1199. X        tmp.y = camera.y0;
  1200. X        tmp.z = camera.z0;
  1201. X
  1202. X        /*
  1203. X         * Do an inverse transformation of the viewpoint to use
  1204. X         * when doing backface culling (in calc_normals()).
  1205. X         */
  1206. X        tmp.x -= curr_mat.mat[3][0];
  1207. X        tmp.y -= curr_mat.mat[3][1];
  1208. X        tmp.z -= curr_mat.mat[3][2];
  1209. X        m[0][0] = curr_mat.mat[0][0] ; m[0][1] = curr_mat.mat[1][0];
  1210. X        m[0][2] = curr_mat.mat[2][0] ; m[0][3] = tmp.x;
  1211. X        m[1][0] = curr_mat.mat[0][1] ; m[1][1] = curr_mat.mat[1][1];
  1212. X        m[1][2] = curr_mat.mat[2][1] ; m[1][3] = tmp.y;
  1213. X        m[2][0] = curr_mat.mat[0][2] ; m[2][1] = curr_mat.mat[1][2];
  1214. X        m[2][2] = curr_mat.mat[2][2] ; m[2][3] = tmp.z;
  1215. X
  1216. X        if (m[0][0] == 0.0) {
  1217. X            if (m[1][0] != 0.0)
  1218. X                j = 1;
  1219. X            else
  1220. X                j = 2;
  1221. X            for (i = 0; i < 4; i++) {
  1222. X                dtmp     = m[0][i];
  1223. X                m[0][i] = m[j][i];
  1224. X                m[j][i] = dtmp;
  1225. X            }
  1226. X        }
  1227. X        
  1228. X        for (j = 1; j < 3; j++) {
  1229. X            m[j][0] /= (-m[0][0]);
  1230. X            for (i = 1; i < 4; i++)
  1231. X                m[j][i] += m[0][i] * m[j][0];
  1232. X        }
  1233. X        
  1234. X        if (m[1][1] == 0.0)
  1235. X            for (i = 1; i < 4; i++) {
  1236. X                dtmp     = m[1][i];
  1237. X                m[1][i] = m[2][i];
  1238. X                m[2][i] = dtmp;
  1239. X            }
  1240. X        
  1241. X        if (m[1][1] != 0.0) {
  1242. X            m[2][1] /= (-m[1][1]);
  1243. X            m[2][2] += m[1][2] * m[2][1];
  1244. X            m[2][3] += m[1][3] * m[2][1];
  1245. X        }
  1246. X        
  1247. X        eyepoint.z = m[2][3] / m[2][2];
  1248. X        eyepoint.y = (m[1][3] - eyepoint.z * m[1][2]) / m[1][1];
  1249. X        eyepoint.x = (m[0][3] - eyepoint.z * m[0][2] 
  1250. X                      - eyepoint.y * m[0][1]) / m[0][0];
  1251. X
  1252. X        for (surfref = objref->surfaces; surfref != NULL; 
  1253. X             surfref = surfref->next) {
  1254. X
  1255. X            calc_normals(surfref->polygons, eyepoint);
  1256. X
  1257. X            for (polyref = surfref->polygons; polyref != NULL; 
  1258. X                 polyref = polyref->next) {
  1259. X
  1260. X                if (!polyref->backface) {
  1261. X                    transf_vertices(polyref->vertices, surfref, 
  1262. X                                    &loc_view_mat, 
  1263. X                                    &curr_mat, (double)xres / 2.0,
  1264. X                                    (double)yres / 2.0, render_mode);
  1265. X                }
  1266. X
  1267. X            }
  1268. X            reset_normals(surfref->vertices);
  1269. X
  1270. X        }
  1271. X        traverse_object_tree(objref->sub_obj, view_mat, xres, yres,
  1272. X                             render_mode); 
  1273. X        matrix_pop();
  1274. X    }
  1275. }
  1276. X
  1277. X
  1278. X
  1279. /*
  1280. X * Recursively traverse the rendering database (preorder).
  1281. X * Call traverse_object_tree for each object.
  1282. X */
  1283. static void
  1284. traverse_object_db(obj_root, view_mat, xres, yres, render_mode)
  1285. X    Inst_object  *obj_root;
  1286. X    Transf_mat   *view_mat;
  1287. X    int           xres, yres;
  1288. X    int           render_mode;
  1289. {
  1290. X    if (obj_root != NULL) {
  1291. X        traverse_object_tree(obj_root->object, view_mat,
  1292. X                             xres, yres, render_mode); 
  1293. X        traverse_object_db(obj_root->sml, view_mat,
  1294. X                           xres, yres, render_mode);
  1295. X        traverse_object_db(obj_root->big, view_mat,
  1296. X                           xres, yres, render_mode);
  1297. X    }
  1298. }
  1299. X
  1300. X
  1301. X
  1302. X
  1303. /*
  1304. X * "Main" functions in rendering. Allocate y-bucket, transform vertices
  1305. X * into viewing coordinates, make edges and sort them into the y-bucket.
  1306. X * Call scan_and_render to do the real work.
  1307. X */
  1308. static void
  1309. render_main(xres, yres, storage_mode, render_mode, oversampling)
  1310. X    int   xres, yres;
  1311. X    int   storage_mode;
  1312. X    int   render_mode;
  1313. X    int   oversampling;
  1314. {
  1315. X    Transf_mat      view_mat;
  1316. X
  1317. X    if (render_mode != LINE) {
  1318. X        xres *= oversampling;
  1319. X        yres *= oversampling;
  1320. X        y_bucket = (Edge **)scalloc(yres, sizeof(Edge *));
  1321. X
  1322. X    } else if (storage_mode == PBM_FILE) {
  1323. X        image_pm = sipp_bitmap_create(xres, yres);
  1324. X        pixmap_set = sipp_bitmap_line;
  1325. X    }
  1326. X
  1327. X    get_view_transf(&view_mat);
  1328. X    MatCopy(&curr_mat, &ident_matrix);
  1329. X    
  1330. X    vecnorm(&camera.vec);
  1331. X
  1332. X    traverse_object_db(object_db, &view_mat,
  1333. X                       xres - 1, yres - 1, render_mode);
  1334. X
  1335. X    if (render_mode != LINE) {
  1336. X        scan_and_render(xres, yres, storage_mode, render_mode, oversampling);
  1337. X        free(y_bucket);
  1338. X
  1339. X    } else if (storage_mode == PBM_FILE) {
  1340. X        sipp_bitmap_write(image_file, image_pm);
  1341. X        sipp_bitmap_destruct(image_pm);
  1342. X    }
  1343. X
  1344. X    view_vec_eval();
  1345. X
  1346. }
  1347. X    
  1348. X
  1349. void
  1350. render_image_file(xres, yres, im_file, render_mode, oversampling)
  1351. X    int   xres, yres;
  1352. X    FILE *im_file;
  1353. X    int   render_mode;
  1354. X    int   oversampling;
  1355. {
  1356. X    image_file = im_file;
  1357. X
  1358. X    if (render_mode == LINE) {
  1359. X        render_main(xres, yres, PBM_FILE, render_mode, oversampling);
  1360. X    } else {
  1361. X        render_main(xres, yres, PPM_FILE, render_mode, oversampling);
  1362. X    }
  1363. }
  1364. X
  1365. X
  1366. void
  1367. render_image_pixmap(xres, yres, pixmap, pixmap_func, render_mode, oversampling)
  1368. X    int     xres, yres;
  1369. X    void   *pixmap;
  1370. X    void  (*pixmap_func)();
  1371. X    int     render_mode;
  1372. X    int     oversampling;
  1373. {
  1374. X    image_pm = pixmap;
  1375. X    pixmap_set = pixmap_func;
  1376. X    render_main(xres, yres, PIXMAP, render_mode, oversampling);
  1377. }
  1378. X
  1379. X
  1380. X
  1381. /*============= Functions that handles global initializations==============*/
  1382. X
  1383. /*
  1384. X * If called with TRUE as argument,  no backface culling will 
  1385. X * be performed. If a polygon is backfacing it will be rendered
  1386. X * as facing in the opposit direction.
  1387. X */
  1388. void
  1389. sipp_show_backfaces(flag)
  1390. X    bool flag;
  1391. {
  1392. X    show_backfaces = flag;
  1393. }
  1394. X
  1395. X
  1396. X
  1397. /*
  1398. X * Necessary initializations.
  1399. X */
  1400. void
  1401. sipp_init()
  1402. {
  1403. X    objects_init();
  1404. X    lightsource_init();
  1405. X    sipp_show_backfaces(FALSE);
  1406. X    viewpoint(0.0, 0.0, 10.0,  0.0, 0.0, 0.0,  0.0, 1.0, 0.0,  0.25);
  1407. }
  1408. SHAR_EOF
  1409. chmod 0644 libsipp/rendering.c ||
  1410. echo 'restore of libsipp/rendering.c failed'
  1411. Wc_c="`wc -c < 'libsipp/rendering.c'`"
  1412. test 39990 -eq "$Wc_c" ||
  1413.     echo 'libsipp/rendering.c: original size 39990, current size' "$Wc_c"
  1414. fi
  1415. # ============= libsipp/rendering.h ==============
  1416. if test -f 'libsipp/rendering.h' -a X"$1" != X"-c"; then
  1417.     echo 'x - skipping libsipp/rendering.h (File already exists)'
  1418. else
  1419. echo 'x - extracting libsipp/rendering.h (Text)'
  1420. sed 's/^X//' << 'SHAR_EOF' > 'libsipp/rendering.h' &&
  1421. /**
  1422. X ** sipp - SImple Polygon Processor
  1423. X **
  1424. X **  A general 3d graphic package
  1425. X **
  1426. X **  Copyright Jonas Yngvesson  (jonas-y@isy.liu.se) 1988/89/90/91
  1427. X **            Inge Wallin      (ingwa@isy.liu.se)         1990/91
  1428. X **
  1429. X ** This program is free software; you can redistribute it and/or modify
  1430. X ** it under the terms of the GNU General Public License as published by
  1431. X ** the Free Software Foundation; either version 1, or any later version.
  1432. X ** This program is distributed in the hope that it will be useful,
  1433. X ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  1434. X ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1435. X ** GNU General Public License for more details.
  1436. X ** You can receive a copy of the GNU General Public License from the
  1437. X ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1438. X **/
  1439. X
  1440. /**
  1441. X ** rendering.h - Types and interface to the rendering.c
  1442. X **/
  1443. X
  1444. #ifndef RENDERING_H
  1445. #define RENDERING_H
  1446. X
  1447. #include <sipp.h>
  1448. X
  1449. X
  1450. /*
  1451. X * Modes for storing the image.
  1452. X */
  1453. #define PBM_FILE   0
  1454. #define PPM_FILE   1
  1455. #define PIXMAP     2
  1456. X
  1457. X
  1458. /*
  1459. X * Temporary storage of transformed vertices.
  1460. X */
  1461. typedef struct view_coord_3d {
  1462. X    double                x, y, z;     /* Transformed vertex coordinates */
  1463. X    double                nx, ny, nz;  /* average normal */
  1464. X    double                u, v, w;     /* texture parameters */
  1465. X    struct view_coord_3d *next;        /* next vertex in the list */
  1466. } View_coord;
  1467. X
  1468. X
  1469. /*
  1470. X * Entry in the edge list used in rendering.
  1471. X */
  1472. typedef struct edges_3d {
  1473. X    int              y, y_stop;   /* Current point and interpolation steps */
  1474. X    double           x, xstep;            
  1475. X    double           z, zstep;
  1476. X    double           nx, nxstep;  /* Current normal and interp. steps */
  1477. X    double           ny, nystep;
  1478. X    double           nz, nzstep;
  1479. X    double           u, ustep;    /* Current texture coordinates and */
  1480. X    double           v, vstep;    /* interp. steps                   */
  1481. X    double           w, wstep;
  1482. X    int              polygon;     /* Uniqe polygon id of the polygon to */
  1483. X                                  /* which the edge belongs */
  1484. X    Surface         *surface;     /* Surface that the edge belongs to */
  1485. X    struct edges_3d *next;        /* Next edge on this scanline */
  1486. } Edge;
  1487. X
  1488. X
  1489. #endif /* RENDERING_H */
  1490. SHAR_EOF
  1491. chmod 0644 libsipp/rendering.h ||
  1492. echo 'restore of libsipp/rendering.h failed'
  1493. Wc_c="`wc -c < 'libsipp/rendering.h'`"
  1494. test 2300 -eq "$Wc_c" ||
  1495.     echo 'libsipp/rendering.h: original size 2300, current size' "$Wc_c"
  1496. fi
  1497. # ============= libsipp/shaders.h ==============
  1498. if test -f 'libsipp/shaders.h' -a X"$1" != X"-c"; then
  1499.     echo 'x - skipping libsipp/shaders.h (File already exists)'
  1500. else
  1501. echo 'x - extracting libsipp/shaders.h (Text)'
  1502. sed 's/^X//' << 'SHAR_EOF' > 'libsipp/shaders.h' &&
  1503. /**
  1504. X ** sipp - SImple Polygon Processor
  1505. X **
  1506. X **  A general 3d graphic package
  1507. X **
  1508. X **  Copyright Jonas Yngvesson  (jonas-y@isy.liu.se) 1988/89/90/91
  1509. X **            Inge Wallin      (ingwa@isy.liu.se)         1990/91
  1510. X **
  1511. X ** This program is free software; you can redistribute it and/or modify
  1512. X ** it under the terms of the GNU General Public License as published by
  1513. X ** the Free Software Foundation; either version 1, or any later version.
  1514. X ** This program is distributed in the hope that it will be useful,
  1515. X ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  1516. X ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  1517. X ** GNU General Public License for more details.
  1518. X ** You can receive a copy of the GNU General Public License from the
  1519. X ** Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  1520. X **/
  1521. X
  1522. /**
  1523. X ** shaders.h - This include file defines the different shaders availiable
  1524. X **             in sipp. Each shader is defined by a structure containing 
  1525. X **             the necessary parameters to describe how a surface should 
  1526. X **             be shaded with that particular shader, and the extern 
  1527. X **             declaration of the shader function itself.
  1528. X **/
  1529. X
  1530. X
  1531. #ifndef _SHADERS_H
  1532. #define _SHADERS_H
  1533. X
  1534. X
  1535. #include <sipp.h>
  1536. X
  1537. X
  1538. X
  1539. /*
  1540. X * Surface description used in strauss_shader().
  1541. X */
  1542. typedef struct {
  1543. X    double ambient;       /* Fraction of color visible in ambient light */
  1544. X    double smoothness;    /* Smoothness of the surface [0, 1] */
  1545. X    double metalness;     /* Metalness of the surface [0, 1] */
  1546. X    Color  color;         /* Base color of the surface */
  1547. } Strauss_desc;
  1548. X
  1549. X
  1550. X
  1551. /* 
  1552. X * Surface description for the bozo shader.
  1553. X */
  1554. typedef struct {
  1555. X    Color   *colors;
  1556. X    int      no_of_cols;
  1557. X    double   ambient;
  1558. X    double   specular;
  1559. X    double   c3;
  1560. X    double   scale;        /* Scale the texture by this value */
  1561. } Bozo_desc;
  1562. X    
  1563. X
  1564. X
  1565. /*
  1566. X * Surface description used by the wood shader. This shader
  1567. X * creates a solid texture (using noise & turbulence) that
  1568. X * simulates wood.
  1569. X */
  1570. typedef struct {
  1571. X    double   ambient;
  1572. X    double   specular;
  1573. X    double   c3;
  1574. X    double   scale;        /* Scale the wood texture by this value */
  1575. X    Color    base;         /* "Base" color of the surface */
  1576. X    Color    ring;         /* Color of the darker rings */
  1577. } Wood_desc;
  1578. X
  1579. X
  1580. X
  1581. /*
  1582. X * Surface description used by the marble shader. marble_shader
  1583. X * creates a solid texture (using noise & turbulence) that
  1584. X * simulates marble.
  1585. X */
  1586. typedef struct {
  1587. X    double   ambient;
  1588. X    double   specular;
  1589. X    double   c3;
  1590. X    double   scale;        /* Scale the marble texture by this value */
  1591. X    Color    base;         /* "Base" color of the surface */
  1592. X    Color    strip;        /* Color of the "stripes" in the marble */
  1593. } Marble_desc;
  1594. X
  1595. X
  1596. X
  1597. /*
  1598. X * Surface description used by the granite shader. granite_shader
  1599. X * creates a solid texture (using noise) that mixes two colors
  1600. X * to simulate granite.
  1601. X */
  1602. typedef struct {
  1603. X    double   ambient;
  1604. X    double   specular;
  1605. X    double   c3;
  1606. X    double   scale;        /* Scale the texture by this value */
  1607. X    Color    col1;         /* The two color components */
  1608. X    Color    col2;         /*                          */
  1609. } Granite_desc;
  1610. X
  1611. X
  1612. X
  1613. /*
  1614. X * Mask shader. It uses mask image (ususally a bitmap) to
  1615. X * choose between two other shaders. It projects the mask
  1616. X * image on the u-v plane (in texture coordinates). When a
  1617. X * surface is shaded it calls pixel_test() to check the
  1618. X * u, v coordinate in the mask and calls one of two other 
  1619. X * shaders depending of the outcome of that test.
  1620. X */
  1621. typedef struct {
  1622. X    Shader *fg_shader;          /* Shader to call if mask(x, y) != 0 */
  1623. X    void   *fg_surface;         /* Surface description for fg_shader */
  1624. X    Shader *bg_shader;          /* Shader to call if mask(x, y) == 0 */
  1625. X    void   *bg_surface;         /* Surface description for bg_shader */
  1626. X    void   *mask;               /* Pointer to mask image */
  1627. X    bool  (*pixel_test)();      /* Function that tests a pixel value */
  1628. X    int     x0, y0;             /* Where to put origo in the mask image */
  1629. X    int     xsize, ysize;       /* Size of the mask image */
  1630. X    double  xscale, yscale;     /* Scale the mask image with these values */
  1631. } Mask_desc;
  1632. X
  1633. X
  1634. /*
  1635. X * Surface description for the bumpy_shader(). This shader 
  1636. X * fiddles with the surface normals of a surface so the surface 
  1637. X * looks bumpy.
  1638. X */
  1639. X
  1640. typedef struct {
  1641. X    Shader *shader;
  1642. X    void   *surface;
  1643. X    double scale;
  1644. X    bool   bumpflag;
  1645. X    bool   holeflag;
  1646. } Bumpy_desc;
  1647. X
  1648. X
  1649. /*
  1650. X * Declarations of the actual shading functions.
  1651. X */
  1652. extern void strauss_shader();
  1653. extern void wood_shader();
  1654. extern void marble_shader();
  1655. extern void granite_shader();
  1656. extern void bozo_shader();
  1657. extern void mask_shader();
  1658. extern void bumpy_shader();
  1659. extern void planet_shader();
  1660. X
  1661. #endif /* _SHADERS_H */
  1662. SHAR_EOF
  1663. chmod 0664 libsipp/shaders.h ||
  1664. echo 'restore of libsipp/shaders.h failed'
  1665. Wc_c="`wc -c < 'libsipp/shaders.h'`"
  1666. test 4808 -eq "$Wc_c" ||
  1667.     echo 'libsipp/shaders.h: original size 4808, current size' "$Wc_c"
  1668. fi
  1669. true || echo 'restore of libsipp/sipp.h failed'
  1670. echo End of part 4, continue with part 5
  1671. exit 0
  1672.  
  1673. -- 
  1674. ------------------------------------------------------------------------------
  1675.  J o n a s   Y n g v e s s o n
  1676. Dept. of Electrical Engineering                             jonas-y@isy.liu.se
  1677. University of Linkoping, Sweden                   ...!uunet!isy.liu.se!jonas-y
  1678.  
  1679. exit 0 # Just in case...
  1680.