home *** CD-ROM | disk | FTP | other *** search
/ Current Shareware 1994 January / SHAR194.ISO / graphuti / rayl210.zip / RAYLATHE.C < prev    next >
Text File  |  1993-09-18  |  20KB  |  653 lines

  1. /*   RayLathe (c) Koehler
  2.    - Thick <0 = draw solid, =0 = move, >0 = draw hollow
  3.    Revision History:
  4.    03-24-93 1.00 KJK  New. Inspired by uLathe.
  5.    03-28-93 1.01 KJK  Attempting Vivid output for Doug Downs.
  6.    04-11-93 1.10 KJK  Releasable Vivid output version.
  7.          Noticed THICK in Vivid no supported! Must fix if possible.
  8.    04-11-93 1.11 KJK  Cured black speckles in POVRAY output.
  9.    04-14-93 1.12 KJK  Allow 0 length cones (rings) for Vivid.
  10.    04-15-93 1.13 KJK  Enable THICK for Vivid. Print line # of .DAT file.
  11.    04-24-93 1.20 KJK  Since they are necessary when thickness is used,
  12.          simulate cone/rings for POVRAY.
  13.    06-28-93 1.?? esp  Add POV-Ray 2.0 syntax, clean up cmdline parsing,
  14.              add Macintosh (MPW) support, change FP compares like (x==y)
  15.              to (fabs(x-y) < EPSILON) to better conform to
  16.              the way fp numbers (mis)behave, add tabwidth parm, clean up
  17.              indenting.
  18.    06-05-93 1.21 KJK  First attempt at POVRAY triangles.
  19.    06-25-93 1.22 KJK  Steve Anger replied to my message on YCCMR about
  20.               what vertex order is required!
  21.    07-10-93 1.23 KJK  Steve Anger replied again. Problem was that data has
  22.               to be one whole object, not multiple objects.
  23.    07-11-93 1.24 KJK  Combined Eduard Schwan's (esp) changes to 1.20 with
  24.               my 1.23.    Removed double slash comments in code to
  25.               keep compatible with regular C. Its my understanding
  26.               the double slash is new for C++.
  27.    07-20-93 1.25 KJK  Doug Downs said Vivid is OK, so lets do final cleanup.
  28.               Also, I will be looking into accepting color data
  29.               to pass along to the RAW converters.
  30.               Watch for seam in RAW output. I'm reluctant to fix what
  31.               I can't prove.
  32.    07-20-93 2.00 KJK  Final release. You know, the one just before the bug fix
  33.               release.    The verbose comments for all of the unreleased
  34.               versions are just an informational story. "It doesn't
  35.               matter, and so-what if it did!"
  36.    09-18-93 2.10 KJK  Fix bug: Commas introduced by esp tabbing where they
  37.               didn't belong.
  38. */
  39.  
  40.  
  41. /* ========================================================= */
  42. /* INCLUDES */
  43.  
  44. #include <math.h>
  45. #include <stdio.h>   /* printf() */
  46. #include <stdlib.h>  /* exit() */
  47. #include <string.h>  /* strcmp() */
  48. #include <ctype.h>   /* tolower() */
  49.  
  50.  
  51. /* ========================================================= */
  52. /* DEFINES */
  53.  
  54. #define VERSION        2.10
  55.  
  56. #ifndef min
  57.     #define min(a,b) ((a)<(b) ? (a) : (b))
  58.     #define max(a,b) ((a)>(b) ? (a) : (b))
  59. #endif
  60. #define EPSILON        1.0e-10   /* miniscule fp number, essentially zero */
  61. const double PI = 3.141592653589;
  62.  
  63. /* Raytracer output styles supported */
  64. #define TRACER_VIVID   1
  65. #define TRACER_POV10   2
  66. #define TRACER_POV20   3
  67. #define TRACER_RAW     4
  68.  
  69. #define DATA_OLD       0
  70. #define DATA_SLICED   -1
  71. #define DATA_COLOR    -2
  72.  
  73. #define TAB_WIDTH       4 /* default width */
  74.  
  75.  
  76. /* ========================================================= */
  77. /* PROTOTYPES */
  78.  
  79. static void  show_usage(char *);
  80. static void  lathe_cut_viv(double, double, double, double, double);
  81. static void  lathe_cut_pov10(double, double, double, double, double);
  82. static void  lathe_cut_pov20(double, double, double, double, double);
  83. static void  lathe_tri_raw(double, double, double, double, double, unsigned char, double, double, double);
  84. static void  tab_printf(void);
  85. static void  tab_inc();
  86. static void  tab_dec();
  87. static double intercept(double, double, double, double);
  88.  
  89.  
  90. /* ========================================================= */
  91. /* GLOBAL VARIABLES */
  92. static int     tab_width = TAB_WIDTH;
  93. static int     tab_level = 0;
  94.  
  95.  
  96. /* ========================================================= */
  97. int main(argc,argv)
  98. int argc;
  99. char *argv[];
  100. {
  101.    int tracer = TRACER_POV10;
  102.    int line=0;
  103.    int k;
  104.    double oldx = 0.01, oldy = 0.01;
  105.    double x, y, thick;
  106.    double boundminx=1.0e8, boundmaxx=-1.0e8, boundmaxy=0.0;
  107.    double length, center, eye_distance;
  108.    double colorR = -1.0, colorG = -1.0, colorB = -1.0;
  109.    unsigned char slices = 8;
  110.    int datatype = DATA_OLD;
  111.  
  112.    fprintf(stderr,"RayLathe v%2.2f (c) 1993 Koehler\n",VERSION);
  113.  
  114.  
  115.    /* Check the command line options ("/" for MSDOS, "-" for Unix & Mac) */
  116.  
  117.    for (k=1; k<argc; k++)
  118.    {
  119.        /* this setup makes it easier to add new switches later */
  120.        switch (argv[k][0])
  121.        {
  122.        case '/':
  123.        case '-':
  124.        switch (tolower(argv[k][1]))
  125.        {
  126.        case '?':
  127.            show_usage(NULL);
  128.            break;
  129.        case 't':
  130.            tab_width = atoi(&argv[k][2]);
  131.            if ((tab_width < 1) || (tab_width > 16))
  132.            show_usage(argv[k]);
  133.            break;
  134.        case 'v':
  135.            tracer = TRACER_VIVID;
  136.            fprintf(stderr,"   Generating Vivid 2.0 object\n");
  137.            break;
  138.        case 'r':
  139.            tracer = TRACER_RAW;
  140.            fprintf(stderr,"   Generating Export (RAW) object\n");
  141.            break;
  142.        case 'p':
  143.            switch (argv[k][2])
  144.            {
  145.            case '1':
  146.            tracer = TRACER_POV10;
  147.            fprintf(stderr,"   Generating POV-Ray 1.0 object\n");
  148.            break;
  149.            case '2':
  150.            tracer = TRACER_POV20;
  151.            fprintf(stderr,"   Generating POV-Ray 2.0 object\n");
  152.            break;
  153.            default:
  154.            show_usage(argv[k]);
  155.            break;
  156.            }
  157.            break;
  158.        default:
  159.            show_usage(argv[k]);
  160.            break;
  161.        } /* switch */
  162.        break;
  163.  
  164.        default:
  165.        show_usage(argv[k]);
  166.        break;
  167.        } /* switch */
  168.    } /* for */
  169.  
  170.  
  171.  
  172.    /* write header */
  173.  
  174.    switch (tracer)
  175.    {
  176.        case TRACER_VIVID:
  177.        printf("// Vivid 2.0 object created by RayLathe v%2.2f (c) 1993 Koehler\n",VERSION);
  178.        printf("// See overall dimensions of object at end of this file\n");
  179.        /* printf("// See suggested camera vectors at end of this file\n"); */
  180.        printf("\n");
  181.        break;
  182.        case TRACER_POV10:
  183.        printf("// POVRAY 1.0 object created by RayLathe v%2.2f (c) 1993 Koehler\n",VERSION);
  184.        printf("// See suggested camera vectors at end of this file\n\n");
  185.        printf("//#declare LatheWork =\n");
  186.        tab_inc();
  187.        tab_printf();printf("composite\n");
  188.        tab_printf();printf("{\n");
  189.        tab_inc();
  190.        break;
  191.        case TRACER_POV20:
  192.        printf("// POVRAY 2.0 object created by RayLathe v%2.2f (c) 1993 Koehler\n",VERSION);
  193.        printf("// See suggested camera vectors at end of this file\n\n");
  194.        printf("//#declare LatheWork =\n");
  195.        tab_inc();
  196.        tab_printf();printf("merge\n");
  197.        tab_printf();printf("{\n");
  198.        tab_inc();
  199.        break;
  200.    } /* switch */
  201.  
  202.  
  203.    /* Read first line from file */
  204.  
  205.    scanf("%lf %lf %lf", &x, &y, &thick);
  206.    if (x < DATA_OLD)       /* LAT2RAYL v1.00 didn't give slices, v1.10 does */
  207.        {
  208.        datatype = x;
  209.        slices = thick;
  210.        scanf("%lf %lf %lf", &x, &y, &thick);
  211.        }
  212.    if (datatype == DATA_COLOR)
  213.        scanf("%lf %lf %lf", &colorR, &colorG, &colorB);
  214.    line++;
  215.  
  216.  
  217.    /* loop through file */
  218.  
  219.    do
  220.    {
  221.        if (tracer != TRACER_RAW)
  222.        {
  223.        tab_printf();printf("// ###\n");
  224.        tab_printf();printf("// ### Line %-4d (%lg, %lg, %lg)\n", line, x, y, thick);
  225.        }
  226.        if (thick)
  227.        {
  228.        switch (tracer)
  229.        {
  230.            case TRACER_VIVID:
  231.            lathe_cut_viv(oldx, oldy, x, y, thick);
  232.            break;
  233.            case TRACER_POV10:
  234.            lathe_cut_pov10(oldx, oldy, x, y, thick);
  235.            break;
  236.            case TRACER_POV20:
  237.            lathe_cut_pov20(oldx, oldy, x, y, thick);
  238.            break;
  239.            case TRACER_RAW:
  240.            lathe_tri_raw(oldx, oldy, x, y, thick, slices, colorR, colorG, colorB);
  241.            break;
  242.        } /* switch */
  243.        }
  244.  
  245.        boundmaxx = max(boundmaxx, x);
  246.        boundminx = min(boundminx, x);
  247.        boundmaxy = max(boundmaxy, y);
  248.        oldx = x;
  249.        oldy = y;
  250.  
  251.  
  252.        /* read next line of file */
  253.  
  254.        scanf("%lf %lf %lf", &x, &y, &thick);
  255.        if (datatype == DATA_COLOR)
  256.        scanf("%lf %lf %lf", &colorR, &colorG, &colorB);
  257.        line++;
  258.    } while ((x >= 0.0) || (y >= 0.0));
  259.  
  260.  
  261.    /* write trailer */
  262.  
  263.    boundminx *= 1.001;
  264.    boundmaxx *= 1.001;
  265.    boundmaxy *= 1.001;
  266.    switch (tracer)
  267.    {
  268.        case TRACER_VIVID:
  269.        break;
  270.        case TRACER_POV10:
  271.        tab_printf();printf("bounded_by\n");
  272.        tab_printf();printf("{\n");
  273.        tab_inc();
  274.        tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",boundminx,-boundmaxy,-boundmaxy, boundmaxx, boundmaxy, boundmaxy);
  275.        tab_dec();
  276.        tab_printf();printf("}\n");
  277.        tab_dec();
  278.        tab_printf();printf("} // composite\n");
  279.        tab_dec();
  280.        length = boundmaxx - boundminx;
  281.        center = length / 2.0 + boundminx;
  282.        printf("\n#declare Look_At = <%g 0 0>  // Center of object\n", center);
  283.        eye_distance = -max(fabs(length), boundmaxy*2.4);
  284.        printf("#declare Location = <%g 0 %g>  // Good camera position\n", center, eye_distance);
  285.        break;
  286.        case TRACER_POV20:
  287.        tab_printf();printf("bounded_by\n");
  288.        tab_printf();printf("{\n");
  289.        tab_inc();
  290.        tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",boundminx,-boundmaxy,-boundmaxy, boundmaxx, boundmaxy, boundmaxy);
  291.        tab_dec();
  292.        tab_printf();printf("}\n");
  293.        tab_dec();
  294.        tab_printf();printf("} // union\n");
  295.        tab_dec();
  296.        length = boundmaxx - boundminx;
  297.        center = length / 2.0 + boundminx;
  298.        printf("\n#declare Look_At = <%g 0 0>  // Center of object\n", center);
  299.        eye_distance = -max(fabs(length), boundmaxy*2.4);
  300.        printf("#declare Location = <%g 0 %g>  // Good camera position\n", center, eye_distance);
  301.        break;
  302.    } /* switch */
  303.  
  304.    if (tracer != TRACER_RAW)
  305.        printf("\n// Min X Y Z = %f %f %f    Max X Y Z = %f %f %f\n",boundminx,-boundmaxy,-boundmaxy, boundmaxx, boundmaxy, boundmaxy);
  306.  
  307.    return (0); /* Happy ANSI */
  308.  
  309. } /* main */
  310.  
  311.  
  312. /* ========================================================= */
  313. static void  show_usage(char * opt)
  314. {
  315.    if (opt != NULL)
  316.        fprintf(stderr,"### ERROR!  Bad option '%s'\n", opt);
  317.    fprintf(stderr,"### Usage: raylathe [-v | -p1 | -p2 | -r] [-tN] <infile.dat >outfile.inc\n");
  318.    fprintf(stderr,"### where -v=Vivid, -p1=POV1.0, -p2=POV2.0, -r=RAW, -tN=tabwidth\n");
  319.    exit(1);
  320. } /* show_usage */
  321.  
  322.  
  323. /* ========================================================= */
  324. static void lathe_cut_viv(x1, y1, x2, y2, thick)
  325. double x1, y1, x2, y2, thick;
  326. {
  327.    /* cone { base 1 1 1 base_radius 4  apex 0 0 5 apex_radius 1 } */
  328.    tab_printf();printf("cone { base %g 0.0 0.0  base_radius %g   ", x1, y1);
  329.    tab_inc();
  330.    tab_printf();printf("apex %g 0.0 0.0  apex_radius %g }\n", x2, y2);
  331.    tab_dec();
  332.    if (thick > 0)
  333.    {
  334.        tab_printf();printf("cone { base %g 0.0 0.0  base_radius %g  ", x1, max(y1-thick, 0.0));
  335.        tab_inc();
  336.        tab_printf();printf("apex %g 0.0 0.0  apex_radius %g }\n", x2, max(y2-thick, 0.0));
  337.        tab_dec();
  338.        tab_printf();printf("cone { base %g 0.0 0.0  base_radius %g  ", x1, max(y1, 0.0));
  339.        tab_inc();
  340.        tab_printf();printf("apex %g 0.0 0.0  apex_radius %g }\n", x1, max(y1-thick, 0.0));
  341.        tab_dec();
  342.        tab_printf();printf("cone { base %g 0.0 0.0  base_radius %g  ", x2, max(y2, 0.0));
  343.        tab_inc();
  344.        tab_printf();printf("apex %g 0.0 0.0  apex_radius %g }\n", x2, max(y2-thick, 0.0));
  345.        tab_dec();
  346.    }
  347. } /* lathe_cut_viv */
  348.  
  349.  
  350. /* ========================================================= */
  351. static void lathe_cut_pov10(x1, y1, x2, y2, thick)
  352. double x1, y1, x2, y2, thick;
  353. {
  354.    double minx, miny, minz, maxx, maxy, maxz, origin;
  355.  
  356.    if (fabs(x1-x2) < EPSILON)
  357.        if (fabs(thick) > EPSILON)
  358.        x1 = x1 * 1.001;    /* Fudge a flat cone (ring) */
  359.        else
  360.        return;
  361.  
  362.    minx = min(x1,x2);
  363.    maxx = max(x1,x2);
  364.    maxy = max(y1,y2);
  365.    miny = -maxy;
  366.    maxz = maxy;
  367.    minz = miny;
  368.  
  369.    tab_printf();printf("object\n");
  370.    tab_printf();printf("{\n");
  371.    tab_inc();
  372.    tab_printf();printf("intersection\n");
  373.    tab_printf();printf("{\n");
  374.    tab_inc();
  375.    if (fabs(y1-y2) < EPSILON)
  376.    {
  377.        if (fabs(y1) > EPSILON)
  378.        {
  379.        tab_printf();printf("quadric { Cylinder_X  scale <1 %g %g> }\n", y1, y1);
  380.        }
  381.    }
  382.    else
  383.    {
  384.        if ((fabs(x1) < EPSILON) || (fabs(x2) < EPSILON))
  385.        origin = 0;
  386.        else
  387.        origin=intercept(x1, y1, x2, y2);
  388.        tab_printf();printf("quadric { QCone_X  ");
  389.  
  390.        if (fabs(x1) < EPSILON)
  391.        {printf("scale <%g %g %g>", fabs(origin-x2), y2, y2);}
  392.        else
  393.        {printf("scale <%g %g %g>", fabs(origin-x1), y1, y1);}
  394.        printf("  translate <%g 0 0> }\n", origin);
  395.    }
  396.  
  397.    if ((thick > 0.0) && (((y1-thick) > 0.0) || ((y2-thick) > 0.0)))
  398.    {
  399.        if (fabs(y1-y2) < EPSILON)
  400.        {
  401.        if ((y1-thick) > 0.0)
  402.        {
  403.            tab_printf();printf("quadric { Cylinder_X  scale <1 %g %g> inverse }\n", y1-thick, y1-thick);
  404.        }
  405.        }
  406.        else
  407.        {
  408.        if ((fabs(x1) < EPSILON) || (fabs(x2) < EPSILON))
  409.            origin = 0;
  410.        else
  411.            origin = (((y1-thick)/y1)*(origin-x1))+x1;
  412.        tab_printf();printf("quadric { QCone_X  ");
  413.  
  414.        if (fabs(origin-x1) < EPSILON)
  415.            {printf("scale <%g %g %g>", fabs(origin-x2), y2-thick, y2-thick);}
  416.        else
  417.            {printf("scale <%g %g %g>", fabs(origin-x1), y1-thick, y1-thick);}
  418.        printf("  translate <%g 0 0> inverse }\n", origin);
  419.        }
  420.    }
  421.  
  422.    tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",minx,miny,minz,maxx,maxy,maxz);
  423.    tab_dec();
  424.    tab_printf();printf("} // intersection\n");
  425.  
  426.    minx = minx*1.001;  /* Adjust for bounding */
  427.    maxx = maxx*1.001;
  428.    maxy = maxy*1.001;
  429.    miny = -maxy;
  430.    maxz = maxy;
  431.    minz = miny;
  432.  
  433.    tab_printf();printf("bounded_by\n");
  434.    tab_printf();printf("{\n");
  435.    tab_inc();
  436.    tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",minx,miny,minz,maxx,maxy,maxz);
  437.    tab_dec();
  438.    tab_printf();printf("}\n");
  439.  
  440.    tab_printf();printf("texture\n");
  441.    tab_printf();printf("{\n");
  442.    tab_inc();
  443.    tab_printf();printf("LatheWorkTex\n");
  444.    tab_dec();
  445.    tab_printf();printf("}\n");
  446.  
  447.    tab_dec();
  448.    tab_printf();printf("} // object\n");
  449.  
  450. } /* lathe_cut_pov10 */
  451.  
  452.  
  453. /* ========================================================= */
  454. static void lathe_cut_pov20(x1, y1, x2, y2, thick)
  455. double x1, y1, x2, y2, thick;
  456. {
  457.    double minx, miny, minz, maxx, maxy, maxz, origin;
  458.  
  459.    if (fabs(x1-x2) < EPSILON)
  460.        if (fabs(thick) > EPSILON)
  461.        x1 = x1 * 1.001;    /* Fudge a flat cone (ring) */
  462.        else
  463.        return;
  464.  
  465.    minx = min(x1,x2);
  466.    maxx = max(x1,x2);
  467.    maxy = max(y1,y2);
  468.    miny = -maxy;
  469.    maxz = maxy;
  470.    minz = miny;
  471.  
  472.    tab_printf();printf("intersection\n");
  473.    tab_printf();printf("{\n");
  474.    tab_inc();
  475.    if (fabs(y1-y2) < EPSILON)
  476.    {
  477.        if (fabs(y1) > EPSILON)
  478.        {
  479.        tab_printf();printf("quadric { Cylinder_X  scale <1 %g %g> }\n", y1, y1);
  480.        }
  481.    }
  482.    else
  483.    {
  484.        if ((fabs(x1) < EPSILON) || (fabs(x2) < EPSILON))
  485.        origin = 0;
  486.        else
  487.        origin=intercept(x1, y1, x2, y2);
  488.        tab_printf();printf("quadric { QCone_X  ");
  489.  
  490.        if (fabs(x1) < EPSILON)
  491.        {printf("scale <%g %g %g>", fabs(origin-x2), y2, y2);}
  492.        else
  493.        {printf("scale <%g %g %g>", fabs(origin-x1), y1, y1);}
  494.        printf("  translate %g*x }\n", origin);
  495.    }
  496.  
  497.    if ((thick > 0.0) && (((y1-thick) > 0.0) || ((y2-thick) > 0.0)))
  498.    {
  499.        if (fabs(y1-y2) < EPSILON)
  500.        {
  501.        if ((y1-thick) > 0.0)
  502.        {
  503.            tab_printf();printf("quadric { Cylinder_X  scale <1, %g %g> inverse }\n", y1-thick, y1-thick);
  504.        }
  505.        }
  506.        else
  507.        {
  508.        if ((fabs(x1) < EPSILON) || (fabs(x2) < EPSILON))
  509.            origin = 0;
  510.        else
  511.            origin = (((y1-thick)/y1)*(origin-x1))+x1;
  512.        tab_printf();printf("quadric { QCone_X  ");
  513.  
  514.        if (fabs(origin-x1) < EPSILON)
  515.            {printf("scale <%g %g %g>", fabs(origin-x2), y2-thick, y2-thick);}
  516.        else
  517.            {printf("scale <%g %g %g>", fabs(origin-x1), y1-thick, y1-thick);}
  518.        printf("  translate %g*x inverse }\n", origin);
  519.        }
  520.    }
  521.  
  522.    tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",minx,miny,minz,maxx,maxy,maxz);
  523.  
  524.    minx = minx*1.001;  /* Adjust for bounding */
  525.    maxx = maxx*1.001;
  526.    maxy = maxy*1.001;
  527.    miny = -maxy;
  528.    maxz = maxy;
  529.    minz = miny;
  530.  
  531.    tab_printf();printf("bounded_by\n");
  532.    tab_printf();printf("{\n");
  533.    tab_inc();
  534.    tab_printf();printf("box { <%g %g %g>  <%g %g %g> }\n",minx,miny,minz,maxx,maxy,maxz);
  535.    tab_dec();
  536.    tab_printf();printf("}\n");
  537.  
  538.    tab_printf();printf("texture\n");
  539.    tab_printf();printf("{\n");
  540.    tab_inc();
  541.    tab_printf();printf("LatheWorkTex\n");
  542.    tab_dec();
  543.    tab_printf();printf("}\n");
  544.  
  545.    tab_dec();
  546.    tab_printf();printf("} // intersection\n");
  547.  
  548. } /* lathe_cut_pov20 */
  549.  
  550.  
  551. /* ========================================================= */
  552. static void lathe_tri_raw(x1, y1, x2, y2, thick, slices, colorR, colorG, colorB)
  553.    double x1, y1, x2, y2, thick, colorR, colorG, colorB;
  554.    unsigned char slices;
  555.    {
  556.    double byo, bzo, cy1, cz1, byi, bzi, cy3, cz3;
  557.    double ark, angle;
  558.    double pointy, pointz;
  559.  
  560.    ark= (2 * PI / slices);
  561.    byo = 0;       /* set outside for first pass */
  562.    bzo = y2;
  563.    cy1 = 0;
  564.    cz1 = y1;
  565.    byi = 0;       /* same for inside */
  566.    bzi = y2-thick;
  567.    cy3 = 0;
  568.    cz3 = y1-thick;
  569.    for (angle=ark; angle<(2 * PI); angle+=ark)
  570.        {
  571.        pointy=sin(angle);
  572.        pointz=cos(angle);
  573.        if (y1 > 0)
  574.        {
  575.        if ( colorR >= 0)
  576.            printf("%g %g %g  ", colorR, colorG, colorB);
  577.     /*A*/  printf("%g %g %g  ", x1, (pointy*y1), (pointz*y1));
  578.     /*D*/  printf("%g %g %g  ", x2, byo, bzo );
  579.     /*C*/  printf("%g %g %g\n", x1, cy1, cz1);
  580.        }
  581.        if (y2 > 0)
  582.        {
  583.        if ( colorR >= 0)
  584.            printf("%g %g %g  ", colorR, colorG, colorB);
  585.     /*A*/  printf("%g %g %g  ", x1, (pointy*y1), (pointz*y1) );
  586.     /*B*/  printf("%g %g %g  ", x2, (pointy*y2), (pointz*y2));
  587.     /*D*/  printf("%g %g %g\n", x2, byo, bzo );
  588.        }
  589.        byo  = (pointy*y2); /* update for next pass */
  590.        bzo  = (pointz*y2);
  591.        cy1 = (pointy*y1);
  592.        cz1 = (pointz*y1);
  593.  
  594.        if ((thick >= 0) && (((y1-thick)>0) || ((y2-thick)>0)))
  595.        {
  596.        if ((y1-thick) > 0)
  597.            {
  598.            if ( colorR >= 0)
  599.            printf("%g %g %g  ", colorR, colorG, colorB);
  600.        /*A*/   printf("%g %g %g  ", x1, (pointy*(y1-thick)), (pointz*(y1-thick)) );
  601.        /*D*/   printf("%g %g %g  ", x2, byi, bzi );
  602.        /*C*/   printf("%g %g %g\n", x1, cy3, cz3);
  603.            }
  604.        if ((y2-thick) > 0)
  605.            {
  606.            if ( colorR >= 0)
  607.            printf("%g %g %g  ", colorR, colorG, colorB);
  608.     /*A*/  printf("%g %g %g  ", x1, (pointy*(y1-thick)), (pointz*(y1-thick)) );
  609.     /*B*/  printf("%g %g %g  ", x2, (pointy*(y2-thick)), (pointz*(y2-thick)));
  610.     /*D*/  printf("%g %g %g\n", x2, byi, bzi );
  611.            }
  612.        byi    = (pointy*(y2-thick)); /* update for next pass */
  613.        bzi    = (pointz*(y2-thick));
  614.        cy3 = (pointy*(y1-thick));
  615.        cz3 = (pointz*(y1-thick));
  616.        }
  617.        }
  618.    }
  619.  
  620.  
  621. /* ========================================================= */
  622. static double intercept(x1, y1, x2, y2)
  623. double x1, y1, x2, y2;
  624. {
  625.    return(x2 - ((x2-x1) / (y2-y1) * y2));
  626. } /* intercept */
  627.  
  628.  
  629. /* ========================================================= */
  630. static void  tab_printf(void)
  631. {
  632.    int       k;
  633.    /* Q&D way to do it... */
  634.    for (k=0; k<tab_width*tab_level; k++)
  635.        putchar(' ');
  636. } /* tab_printf */
  637.  
  638.  
  639. /* ========================================================= */
  640. static void  tab_inc()
  641. {
  642.    tab_level++;
  643. } /* tab_inc */
  644.  
  645.  
  646. /* ========================================================= */
  647. static void  tab_dec()
  648. {
  649.    tab_level--;
  650.    if (tab_level < 0)
  651.        tab_level = 0;
  652. } /* tab_dec */
  653.