home *** CD-ROM | disk | FTP | other *** search
/ Current Shareware 1994 January / SHAR194.ISO / graphuti / frgen14.zip / SOURCE.ZIP / FRGEN.CPP < prev    next >
C/C++ Source or Header  |  1993-09-30  |  20KB  |  795 lines

  1. /*-------------------------------------------------------------------------
  2.  
  3.             Fractal Landscape Generator v1.4
  4.              Copyright (c) 1993 Steve Anger
  5.           This program is freely distributable
  6.  
  7.      FRGEN is a utility to generate fractal landscapes and shapes using
  8.    successive triangle sub-division. The fractal data can be output as
  9.    POV-Ray 1.0/2.0 or Vivid scene description files or as raw triangle
  10.    data.
  11.  
  12.    Notes for compiling: This program has been successfully compiled with
  13.    Borland C++ 3.1 and DJGCC C/C++ 2.4.1. Under Turbo/Borland C++ compile
  14.    with COMPACT or LARGE memory model with "Copy propagation" optimization
  15.    disabled.
  16.  
  17.                       CompuServe: 70714,3113
  18.                        YCCMR BBS: (708)358-5611
  19.  
  20.    Modified for Mac MPW C++ support 4/16/93 - Eduard [esp] Schwan
  21.  
  22. -------------------------------------------------------------------------*/
  23.  
  24. #include <fstream.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27. #include <string.h>
  28. #include <ctype.h>
  29. #include <math.h>
  30. #include <values.h>
  31. #include <time.h>
  32. #include "vect.h"
  33.  
  34. #ifdef __TURBOC__
  35. #include <graphics.h>
  36. #include <conio.h>
  37. #include <dos.h>
  38. extern unsigned _stklen = 16000;  // Larger stack size for recursion
  39. #endif
  40.  
  41. #ifdef applec
  42. #include <CursorCtl.h> // for multitasking
  43. #endif
  44.  
  45. typedef enum bool {false = 0, true = 1};
  46. typedef enum Format {POV10, POV20, VIVID, RAW, NONE};
  47.  
  48. const char ver[] = "v1.4";
  49.  
  50. // Function prototypes
  51. void usage (void);
  52. void abortmsg (char *msg, int exit_code);
  53. void add_ext (char *fname, char *ext, bool force);
  54. void swap (float &a, float &b);
  55. void process_args (int argc, char *argv[]);
  56. void file_args (void);
  57. void process_option (char *s);
  58. void write_options (void);
  59. bool read_triangle (Vector&a, Vector&b, Vector&c, int &fix_ab, int &fix_bc, int
  60.      &fix_ca);
  61. Vector noise_vector (Vector&v, int level);
  62. void tri_fractal (Vector&a, Vector&b, Vector&c, int fix_ab, int fix_bc, int
  63.      fix_ca, int level, Vector&vmin, Vector&vmax);
  64. void write_light (fstream &f, Vector pos);
  65. void write_camera (fstream &f, Vector pos, Vector target);
  66. void set_view (void);
  67. char upcase (char c);
  68. void plot_tri (const Vector&a, const Vector&b, const Vector&c);
  69. int init_display (void);
  70. void close_display (void);
  71. void check_abort (void);
  72.  
  73.  
  74. // Global variables
  75. fstream in, out, data;
  76. Vector  viewpoint;      // Where you're looking from
  77. Vector  lookat;         // Where you're looking at
  78. Vector  nx, ny, nz;     // Basis vectors for viewpoint
  79. Vector  nscale;         // Noise scaling factors
  80. Vector  nbias;          // Noise biasing factors
  81. Vector  nfalloff;       // Noise falloff factor
  82. int     depth;          // Depth of recursion
  83. int     seed;           // Seed for random number generator
  84. bool    display;        // Set to true if display preview enabled
  85. bool    swap_yz;        // Swap y and z coords on output
  86. Format  format;         // Output file format
  87. char    infile[64];     // Input file name
  88. char    mainfile[64];   // Output file name
  89. char    datafile[64];   // Include file name
  90. long    tri_count;      // Count of triangles generated
  91. int     input_line;     // Current input line being parsed
  92. Vector  gmin, gmax;
  93.  
  94.  
  95. int main (int argc, char* argv[])
  96. {
  97.     cerr << "\nFractal Landscape Generator " << ver << " ";
  98.     cerr << "Copyright (c) 1993 Steve Anger\n";
  99.     cerr << "This program is freely distributable\n\n";
  100.  
  101.     srand ((unsigned)time(NULL));
  102.     seed = (int)(10000.0 * rand() / (float)RAND_MAX);
  103.     infile[0] = '\0';
  104.     mainfile[0] = '\0';
  105.     viewpoint = Vector (10.0, 10.0, -10.0);
  106.     lookat = Vector (0.0, 0.0, 0.0);
  107.     nscale = Vector (0.10, 0.10, 0.10);
  108.     nbias = Vector (0.0, 0.0, 0.0);
  109.     nfalloff = Vector (1.0, 1.0, 1.0);
  110.     depth = 3;
  111.     display = false;
  112.     swap_yz = false;
  113.     format = POV20;
  114.     tri_count = 0;
  115.     input_line = 0;
  116.  
  117.     for (int i = 1; i < argc; i++) {
  118.     if (argv[i][0] != '-' && argv[i][0] != '/') {
  119.         if (strlen(infile) == 0) {
  120.         strcpy (infile, argv[i]);
  121.         add_ext (infile, "fr", false);
  122.         }
  123.         else if (strlen(mainfile) == 0)
  124.         strcpy (mainfile, argv[i]);
  125.             else
  126.                 abortmsg ("Too many file names specified.", 1);
  127.         }
  128.     }
  129.  
  130.     if (strlen (infile) == 0) {
  131.     usage();
  132.     exit (1);
  133.     }
  134.  
  135.     in.open (infile, ios::in);
  136.     if (!in) abortmsg ("Error opening input file.", 1);
  137.  
  138.     file_args();  // Get options from input file
  139.  
  140.     process_args (argc, argv);  // Get the command line options
  141.  
  142.     if (strlen (mainfile) == 0) {
  143.     strcpy (mainfile, infile);
  144.     strcpy (datafile, infile);
  145.  
  146.     switch (format) {
  147.         case POV10:
  148.         case POV20: add_ext (mainfile, "pov", true);
  149.             add_ext (datafile, "inc", true); break;
  150.         case VIVID: add_ext (mainfile, "v",   true);
  151.             add_ext (datafile, "vo",  true); break;
  152.         case RAW:   add_ext (datafile, "raw", true); break;
  153.     }
  154.     }
  155.  
  156.     switch (format) {
  157.     case POV10:
  158.     case POV20: add_ext (mainfile, "pov", false);
  159.             add_ext (datafile, "inc", false); break;
  160.     case VIVID: add_ext (mainfile, "v",   false);
  161.             add_ext (datafile, "vo",  false); break;
  162.     case RAW:   add_ext (datafile, "raw", false); break;
  163.     }
  164.  
  165.     if (format != NONE) {
  166.     if (format != RAW) {
  167.         out.open (mainfile, ios::out);
  168.         if (!out) abortmsg ("Error opening output file.", 1);
  169.     }
  170.  
  171.     data.open (datafile, ios::out);
  172.     if (!data) abortmsg ("Error opening output file.", 1);
  173.     }
  174.  
  175.     if (depth < 1)
  176.     abortmsg ("Recurse depth (-r) must be >= 1", 1);
  177.  
  178.     cout << "Generating fractal\n";
  179.  
  180.     if (display) {
  181.     set_view();
  182.  
  183.     if (init_display() < 0)
  184.         abortmsg ("Unable to initialize graphics display.", 1);
  185.     }
  186.  
  187.     write_options();
  188.  
  189.     switch (format) {
  190.     case POV10: out << "#declare FracTexture = texture {\n";
  191.             out << "    ambient 0.1 diffuse 0.8\n";
  192.             out << "    color red 1.0 green 1.0 blue 1.0\n";
  193.             out << "}\n\n";
  194.             out << "#include \"" << datafile << "\"\n\n";
  195.             data << "composite {\n";
  196.             break;
  197.  
  198.     case POV20: out << "#declare FracTexture = texture {\n";
  199.             out << "    finish { ambient 0.1 diffuse 0.8 }\n";
  200.             out << "    pigment { color red 1.0 green 1.0 blue 1.0 }\n";
  201.             out << "}\n\n";
  202.             out << "#include \"" << datafile << "\"\n\n";
  203.             data << "union {\n";
  204.             break;
  205.  
  206.     case VIVID: out << "surface {\n";
  207.             out << "    ambient 0.1 0.1 0.1\n";
  208.             out << "    diffuse 0.8 0.8 0.8\n";
  209.             out << "    shine 70, 1.0 1.0 1.0\n";
  210.             out << "}\n\n";
  211.             out << "#include " << datafile << "\n\n";
  212.             break;
  213.     }
  214.  
  215.     if (format == POV20)
  216.     Vector::set_delim (',');
  217.  
  218.     Vector a, b, c, vmin, vmax;
  219.     int fix_ab, fix_bc, fix_ca, tri_read = 0;
  220.  
  221.     Vector gmin = Vector (+MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
  222.     Vector gmax = Vector (-MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
  223.  
  224.     while (read_triangle (a, b, c, fix_ab, fix_bc, fix_ca)) {
  225.     tri_fractal (a, b, c, fix_ab, fix_bc, fix_ca, depth, vmin, vmax);
  226.  
  227.     gmin = min (gmin, vmin);
  228.     gmax = max (gmax, vmax);
  229.     tri_read++;
  230.     }
  231.  
  232.     switch (format) {
  233.     case POV10:
  234.         data << "\tbounded_by { box { <" << gmin << "> <" << gmax << "> } }\n";
  235.         data << "}\n\n";
  236.         break;
  237.  
  238.     case POV20:
  239.         data << "\n\ttexture { FracTexture }\n";
  240.         data << "}\n\n";
  241.         break;
  242.     }
  243.  
  244.     if (format != RAW && format != NONE) {
  245.     write_camera (out, viewpoint, lookat);
  246.     write_light (out, viewpoint);
  247.     }
  248.  
  249.     in.close();
  250.  
  251.     if (format != NONE) {
  252.     data.close();
  253.  
  254.     if (format != RAW)
  255.         out.close();
  256.     }
  257.  
  258.     cerr << "\n" << tri_count << " triangles generated.\n";
  259.  
  260.     if (display) {
  261.     cerr << "Press return.\n";
  262.     getchar();
  263.     close_display();
  264.     }
  265.  
  266.     return 0;
  267. }
  268.  
  269.  
  270. void usage()
  271. {
  272.     cerr << "Usage: frgen infile[.fr] [outfile] [options]\n";
  273.     cerr << "Options: -sx, -sy, -sz  Scale noise\n";
  274.     cerr << "         -bx, -by, -bz  Bias noise\n";
  275.     cerr << "         -fx, -fy, -fz  Set noise falloff\n";
  276.     cerr << "         -vx, -vy, -vz  Set viewpoint position\n";
  277.     cerr << "         -lx, -ly, -lz  Set lookat position\n";
  278.     cerr << "         -ennn          Use nnn as seed for random number generator\n";
  279.     cerr << "         -rnnn          Maximum recursion depth of nnn\n";
  280.     cerr << "         -d             Display generated fractal on screen\n";
  281.     cerr << "         -op            Output to POV-Ray 2.0 format (default)\n";
  282.     cerr << "         -op1           Output to POV-Ray 1.0 format\n";
  283.     cerr << "         -ov            Output to Vivid 2.0 format\n";
  284.     cerr << "         -or            Output to RAW triangle format\n";
  285.     cerr << "         -on            Null output (for quick preview).\n";
  286.     cerr << "         -x             Exchange Y and Z coords on output.\n";
  287. }
  288.  
  289.  
  290. void abortmsg (char *msg, int exit_code)
  291. {
  292.     if (display)
  293.         close_display();
  294.  
  295.     cerr << msg << "\n";
  296.     exit (exit_code);
  297. }
  298.  
  299.  
  300. void add_ext (char *fname, char *ext, bool force)
  301. {
  302.     int i;
  303.  
  304.     for (i = 0; i < strlen(fname); i++)
  305.         if (fname[i] == '.') break;
  306.  
  307.     if (fname[i] == '\0' || force) {
  308.         fname[i] = '.';
  309.     strcpy (&fname[i+1], ext);
  310.     }
  311. }
  312.  
  313.  
  314. void swap (float &a, float &b)
  315. {
  316.     float temp = a;
  317.     a = b;
  318.     b = temp;
  319. }
  320.  
  321.  
  322. void process_args (int argc, char* argv[])
  323. {
  324.     for (int i = 1; i < argc; i++) {
  325.         if (argv[i][0] == '-' || argv[i][0] == '/')
  326.         process_option (&argv[i][1]);
  327.     }
  328. }
  329.  
  330.  
  331. void file_args()
  332. {
  333.     char line[100] = "";
  334.     char last_ch = ' ';
  335.  
  336.     do {
  337.     in.getline (line, 100);
  338.     input_line++;
  339.     } while (!in.eof() && line[0] == ';');
  340.  
  341.     if (in.eof())
  342.     return;
  343.  
  344.     for (int i = 0; i < strlen (line); i++) {
  345.     if ((line[i] == '-' || line[i] == '/') && isspace(last_ch))
  346.         process_option (&line[i+1]);
  347.  
  348.     last_ch = line[i];
  349.     }
  350. }
  351.  
  352.  
  353. void process_option (char *s)
  354. {
  355.     switch (upcase(s[0])) {
  356.     case 'V':
  357.         switch (upcase(s[1])) {
  358.         case 'X': viewpoint.x = atof(&s[2]); break;
  359.         case 'Y': viewpoint.y = atof(&s[2]); break;
  360.         case 'Z': viewpoint.z = atof(&s[2]); break;
  361.         default : cerr << "Invalid option -v" << s[1] << "\n";
  362.         }
  363.         break;
  364.  
  365.     case 'L':
  366.         switch (upcase(s[1])) {
  367.         case 'X': lookat.x = atof(&s[2]); break;
  368.         case 'Y': lookat.y = atof(&s[2]); break;
  369.         case 'Z': lookat.z = atof(&s[2]); break;
  370.         default : cerr << "Invalid option -l" << s[1] << "\n";
  371.         }
  372.         break;
  373.  
  374.     case 'S':
  375.         switch (upcase(s[1])) {
  376.         case 'X': nscale.x = atof(&s[2]); break;
  377.         case 'Y': nscale.y = atof(&s[2]); break;
  378.         case 'Z': nscale.z = atof(&s[2]); break;
  379.         default : float value = atof(&s[1]);
  380.               nscale = Vector (value, value, value);
  381.         }
  382.         break;
  383.  
  384.     case 'B':
  385.         switch (upcase(s[1])) {
  386.         case 'X': nbias.x = atof(&s[2]); break;
  387.         case 'Y': nbias.y = atof(&s[2]); break;
  388.         case 'Z': nbias.z = atof(&s[2]); break;
  389.         default : float value = atof(&s[1]);
  390.               nbias = Vector (value, value, value);
  391.         }
  392.         break;
  393.  
  394.     case 'F':
  395.         switch (upcase(s[1])) {
  396.         case 'X': nfalloff.x = atof(&s[2]); break;
  397.         case 'Y': nfalloff.y = atof(&s[2]); break;
  398.         case 'Z': nfalloff.z = atof(&s[2]); break;
  399.         default : float value = atof(&s[1]);
  400.               nfalloff = Vector (value, value, value);
  401.         }
  402.         break;
  403.  
  404.     case 'E': seed = atoi(&s[1]);
  405.           break;
  406.  
  407.     case 'R': depth = atoi(&s[1]);
  408.           break;
  409.  
  410.     case 'D': display = true;
  411.           break;
  412.  
  413.     case 'X': swap_yz = true;
  414.           break;
  415.  
  416.     case 'O' :
  417.         switch (upcase(s[1])) {
  418.         case 'P': format = (s[2] == '2') ? POV20 : POV10; break;
  419.         case 'V': format = VIVID;  break;
  420.         case 'R': format = RAW;    break;
  421.         case 'N': format = NONE;   break;
  422.         default : cerr <<"Invalid option -o" << s[1] << ", ignored\n";
  423.         }
  424.         break;
  425.  
  426.  
  427.     default : cerr << "Invalid option -" << s[1] << ", ignored\n";
  428.     }
  429. }
  430.  
  431.  
  432. void write_options()
  433. {
  434.     if (format == POV10 || format == POV20 || format == VIVID) {
  435.     data << "/*\n";
  436.     data << "     Generated with FRGEN " << ver << " from file " << infile << "\n";
  437.     data << "     Options in effect:";
  438.     data << " -sx" <<  nscale.x << " -sy" << nscale.y << " -sz" << nscale.z;
  439.     data << " -bx" << nbias.x << " -by" << nbias.y << " -bz" << nbias.z << "\n";
  440.     data << "                        -fx" << nfalloff.x << " -fy" << nfalloff.y << " -fz" << nfalloff.z;
  441.     data << " -r" << depth << " -e" << seed << "\n";
  442.     data << "*/\n\n";
  443.     }
  444.     else if (format == NONE)
  445.     cout << "Seed: -e" << seed << "\n";
  446. }
  447.  
  448.  
  449. bool read_triangle (Vector &a, Vector &b, Vector &c,
  450.             int &fix_ab, int &fix_bc, int &fix_ca)
  451. {
  452.     char line[256] = "";
  453.     char msg[40];
  454.     int n;
  455.  
  456.     do {
  457.     in.getline (line, 256);
  458.     input_line++;
  459.     } while (!in.eof() && line[0] == ';');
  460.  
  461.     if (in.eof())
  462.     return false;
  463.  
  464.     a = Vector (0.0, 0.0, 0.0);
  465.     b = Vector (0.0, 0.0, 0.0);
  466.     c = Vector (0.0, 0.0, 0.0);
  467.  
  468.     fix_ab = 0;
  469.     fix_bc = 0;
  470.     fix_ca = 0;
  471.  
  472.     n = sscanf (line, "%f %f %f %f %f %f %f %f %f %d %d %d",
  473.         &a.x, &a.y, &a.z, &b.x, &b.y, &b.z, &c.x, &c.y, &c.z,
  474.         &fix_ab, &fix_bc, &fix_ca);
  475.  
  476.     if (n == EOF)
  477.     return false;
  478.  
  479.     if (!(n == 9 || n == 12)) {
  480.     sprintf (msg, "Error in input file, line %d", input_line);
  481.     abortmsg (msg, 1);
  482.     }
  483.  
  484.     return true;
  485. }
  486.  
  487.  
  488. Vector noise_vector (Vector &v, int level)
  489. {
  490.     // Generate a random vector that is a function of the
  491.     // vector v's position
  492.     Vector noise, scale;
  493.  
  494.     scale.x = nscale.x * exp (level * log (nfalloff.x));
  495.     scale.y = nscale.y * exp (level * log (nfalloff.y));
  496.     scale.z = nscale.z * exp (level * log (nfalloff.z));
  497.  
  498.     // seed the rand # generator with a mish-mash of the x, y, and z coords
  499.     srand (seed ^ (long)(-23465*v.x) ^ (long)(17365*v.y) ^ (long)(5364*v.z));
  500.  
  501.     noise.x = scale.x * (2.0*rand()/RAND_MAX - 1.0 + nbias.x);
  502.     noise.y = scale.y * (2.0*rand()/RAND_MAX - 1.0 + nbias.y);
  503.     noise.z = scale.z * (2.0*rand()/RAND_MAX - 1.0 + nbias.z);
  504.  
  505.     return noise;
  506. }
  507.  
  508.  
  509. void tri_fractal (Vector &a, Vector &b, Vector &c,
  510.           int fix_ab, int fix_bc, int fix_ca, int level,
  511.           Vector &vmin, Vector &vmax)
  512. {
  513.     Vector ab, bc, ca;
  514.     float  ab_len, bc_len, ca_len;
  515.  
  516.     vmin = Vector (+MAXFLOAT, +MAXFLOAT, +MAXFLOAT);
  517.     vmax = Vector (-MAXFLOAT, -MAXFLOAT, -MAXFLOAT);
  518.  
  519.     if (level == 0) {
  520.     check_abort();
  521.  
  522.     if (swap_yz) {
  523.         swap (a.y, a.z);
  524.         swap (b.y, b.z);
  525.         swap (c.y, c.z);
  526.     }
  527.  
  528.     switch (format) {
  529.         case POV10:
  530.         data << "\t\ttriangle { <" << a << "> <" << b << "> <" << c << "> }\n";
  531.         break;
  532.  
  533.         case POV20:
  534.         data << "\ttriangle { <" << a << ">, <" << b << ">, <" << c << "> }\n";
  535.         break;
  536.  
  537.         case VIVID:
  538.         data << "polygon {\n";
  539.         data << "\tpoints 3\n";
  540.         data << "\tvertex " << a << "\n";
  541.         data << "\tvertex " << b << "\n";
  542.         data << "\tvertex " << c << "\n";
  543.         data << "}\n\n";
  544.         break;
  545.  
  546.         case RAW:
  547.         data << a << " " << b << " " << c << "\n";
  548.         break;
  549.     }
  550.  
  551.     if (swap_yz) {
  552.         swap (a.y, a.z);
  553.         swap (b.y, b.z);
  554.         swap (c.y, c.z);
  555.     }
  556.  
  557.     tri_count++;
  558.  
  559.     if (display)
  560.         plot_tri (a, b, c);
  561.  
  562.     vmin = min (vmin, a);
  563.     vmin = min (vmin, b);
  564.     vmin = min (vmin, c);
  565.  
  566.     vmax = max (vmax, a);
  567.     vmax = max (vmax, b);
  568.     vmax = max (vmax, c);
  569.     }
  570.     else {
  571.     if (format == POV10) {
  572.         if (level == 1) {
  573.         data << "\tobject {\n";
  574.         data << "\t\tunion {\n";
  575.         }
  576.         else if (level > 1)
  577.         data << "composite {\n";
  578.     }
  579.  
  580.     // Find the midpoints of the three line segments
  581.     ab = (a + b)/2.0;
  582.     bc = (b + c)/2.0;
  583.     ca = (c + a)/2.0;
  584.  
  585.     ab_len = mag(a - b);
  586.     bc_len = mag(b - c);
  587.     ca_len = mag(c - a);
  588.  
  589.     // Compute the normal to the triangle
  590.     Vector norm = (b - a) * (c - a);
  591.     norm = norm/mag(norm);
  592.  
  593.     // Create some noise proportional to the edge lengths
  594.     Vector noise_ab = ab_len * noise_vector (ab, depth - level);
  595.     Vector noise_bc = bc_len * noise_vector (bc, depth - level);
  596.     Vector noise_ca = ca_len * noise_vector (ca, depth - level);
  597.  
  598.     // Don't let any 'fixed' points move out of the plane
  599.     // of the triangle (remove the noise's normal component)
  600.     if (fix_ab) noise_ab = noise_ab * norm;
  601.     if (fix_bc) noise_bc = noise_bc * norm;
  602.     if (fix_ca) noise_ca = noise_ca * norm;
  603.  
  604.     // Perturb the three vectors
  605.     ab = ab + noise_ab;
  606.     bc = bc + noise_bc;
  607.     ca = ca + noise_ca;
  608.  
  609.     Vector new_min[4], new_max[4];
  610.  
  611.     tri_fractal (a,  ab, ca, fix_ab, 0, fix_ca, level-1, new_min[0], new_max[0]);
  612.     tri_fractal (b,  bc, ab, fix_bc, 0, fix_ab, level-1, new_min[1], new_max[1]);
  613.     tri_fractal (c,  ca, bc, fix_ca, 0, fix_bc, level-1, new_min[2], new_max[2]);
  614.     tri_fractal (ab, bc, ca,      0, 0,      0, level-1, new_min[3], new_max[3]);
  615.  
  616.     for (int i = 0; i < 4; i++) {
  617.         vmin = min (vmin, new_min[i]);
  618.         vmax = max (vmax, new_max[i]);
  619.     }
  620.  
  621.     if (format == POV10) {
  622.         if (level == 1) {
  623.         data << "\t\t}\n\n";
  624.  
  625.         data << "\t\ttexture { FracTexture }\n\n";
  626.         data << "\t\tbounded_by { box { <" << vmin << "> <" << vmax << "> } }\n";
  627.         data << "\t}\n\n";
  628.         }
  629.         else if (level > 1) {
  630.         data << "\tbounded_by { box { <" << vmin << "> <" << vmax << "> } }\n";
  631.         data << "}\n";
  632.         }
  633.     }
  634.     }
  635. }
  636.  
  637.  
  638. void write_light (fstream &f, Vector pos)
  639. {
  640.     switch (format) {
  641.     case POV10:
  642.         f << "object {\n";
  643.         f << "    light_source { <" << pos << "> color red 1 green 1 blue 1 }\n";
  644.         f << "}\n\n";
  645.         break;
  646.  
  647.     case POV20:
  648.         f << "light_source { <" << pos << "> color rgb <1,1,1> }\n\n";
  649.         break;
  650.  
  651.     case VIVID:
  652.         f << "light {\n";
  653.         f << "    type point\n";
  654.         f << "    position " << pos << "\n";
  655.         f << "    color 1.0 1.0 1.0\n";
  656.         f << "}\n\n";
  657.         break;
  658.     }
  659. }
  660.  
  661.  
  662. void write_camera (fstream &f, Vector pos, Vector target)
  663. {
  664.     switch (format) {
  665.     case POV10:
  666.         f << "camera {\n";
  667.         f << "   location <" << pos << ">\n";
  668.         f << "   look_at <" << target << ">\n";
  669.         f << "}\n\n";
  670.         break;
  671.  
  672.     case POV20:
  673.         f << "camera {\n";
  674.         f << "   location <" << pos << ">\n";
  675.         f << "   look_at <" << target << ">\n";
  676.         f << "}\n\n";
  677.         break;
  678.  
  679.     case VIVID:
  680.         f << "studio {\n";
  681.         f << "    from " << pos << "\n";
  682.         f << "    at " << target << "\n";
  683.         f << "    up 0 0 1\n";
  684.         f << "    angle 60.0\n";
  685.         f << "    aspect 4/3\n";
  686.         f << "    resolution 320 200\n";
  687.         f << "    antialias none\n";
  688.         f << "}\n\n";
  689.         break;
  690.     }
  691. }
  692.  
  693.  
  694. void set_view()
  695. {
  696.     Vector sky;
  697.  
  698.     sky = Vector (0.0, 1.0, 0.0);
  699.  
  700.     // Calculate a set of base vectors for the new viewpoint
  701.     nz = lookat - viewpoint;
  702.     nz = nz/mag(nz);
  703.  
  704.     ny = sky - nz*(nz.y/(nz % nz));
  705.     ny = ny/mag(ny);
  706.  
  707.     nx = 1.333 * nz * ny;
  708. }
  709.  
  710.  
  711. /* Convert character 'c' top upper case */
  712. char upcase (char c)
  713. {
  714.     if (c >= 'a' && c <= 'z')
  715.     c = c - 'a' + 'A';
  716.  
  717.     return c;
  718. }
  719.  
  720.  
  721. void plot_tri (const Vector &a, const Vector &b, const Vector &c)
  722. {
  723. #ifdef __TURBOC__
  724.     Vector pa, pb, pc, ta, tb, tc;
  725.     int ax, ay, bx, by, cx, cy;
  726.  
  727.     ta = a - viewpoint;
  728.     tb = b - viewpoint;
  729.     tc = c - viewpoint;
  730.  
  731.     pa = Vector (ta % nx, ta % ny, ta % nz);
  732.     pb = Vector (tb % nx, tb % ny, tb % nz);
  733.     pc = Vector (tc % nx, tc % ny, tc % nz);
  734.  
  735.     ax = int((0.5*pa.x/pa.z + 0.5)*getmaxx());
  736.     bx = int((0.5*pb.x/pb.z + 0.5)*getmaxx());
  737.     cx = int((0.5*pc.x/pc.z + 0.5)*getmaxx());
  738.     ay = int((0.5 - pa.y/pa.z)*getmaxy());
  739.     by = int((0.5 - pb.y/pb.z)*getmaxy());
  740.     cy = int((0.5 - pc.y/pc.z)*getmaxy());
  741.  
  742.     setcolor (LIGHTBLUE);
  743.     moveto (ax, ay);
  744.     lineto (bx, by);
  745.     lineto (cx, cy);
  746.     lineto (ax, ay);
  747. #endif
  748. }
  749.  
  750.  
  751. int init_display()
  752. {
  753. #ifdef __TURBOC__
  754.     int gdriver = VGA, gmode = VGAHI, errorcode;
  755.  
  756.     registerbgidriver (EGAVGA_driver);
  757.  
  758.     initgraph (&gdriver, &gmode, "");
  759.     errorcode = graphresult();
  760.     if (errorcode != grOk) {
  761.         cerr << "ERROR:" << grapherrormsg (errorcode) << "\n\n";
  762.         return -1;
  763.     }
  764. #endif
  765.  
  766.     return 0;
  767. }
  768.  
  769.  
  770. void close_display()
  771. {
  772. #ifdef __TURBOC__
  773.     restorecrtmode();
  774. #endif
  775. }
  776.  
  777.  
  778. void check_abort()
  779. {
  780. #ifdef __TURBOC__
  781.     static int cnt = 0;
  782.  
  783.     ++cnt;
  784.  
  785.     if (cnt >= 10) {
  786.         cnt = 0;
  787.  
  788.         if (kbhit())
  789.             abortmsg ("Aborted!", 1);
  790.     }
  791. #endif
  792. }
  793.  
  794.  
  795.