home *** CD-ROM | disk | FTP | other *** search
/ Stars of Shareware: Raytrace & Morphing / SOS-RAYTRACE.ISO / programm / utility / dos / plant0 / plant040.cpp < prev   
Encoding:
C/C++ Source or Header  |  1993-09-29  |  22.3 KB  |  541 lines

  1. /*         
  2.  Program : PLANT v0.40a
  3.  Purpose : Create plant-like objects for PoV Ray v1.0 and Polyray v1.6 
  4.            raytracers and also export to CTDS format.   
  5.  Created : 9/28/93
  6.  By      : Rob Bryerton CIS [73747,433]           
  7.  File    : PLANT040.CPP
  8.  Compiler: Microsoft C++ v8.00  
  9.  Model   : Small
  10.  Comments: Creates 'organic' plant-like objects using spheres...
  11.  NOTE    : this code is VERY MS specific and kinda shaky at this time
  12. */                           
  13.  
  14. #include <graph.h>              //  for graphics functions
  15. #include <stdlib.h>             //  for srand(), rand()
  16. #include <time.h>               //  for randomize()
  17. #include <math.h>               //  for sin(), cos()
  18. #include <conio.h>              //  for getch()
  19. #include <fstream.h>            //  for disk access, cin, cout, etc
  20. #include <string.h>             //  for strcpy()
  21. #include <float.h>              //  for FLT_MIN, FLT_MAX, etc 
  22.  
  23. #define VERSION  "0.40a"
  24. #define GREEN 2                 //  color indices
  25. #define RED 4
  26. #define LIGHTGREEN 10
  27. #define YELLOW 14
  28.  
  29. enum bool {FALSE, TRUE};
  30. enum Format {POV,POLY,CTDS};
  31.  
  32. struct Vector{ double x,y,z;};
  33.  
  34. void bound_piece(void);
  35. void calc_bounds(void);
  36. void calc_branch(int size, double theta, double x, double y);
  37. void calc_cluster(int size, double x, double y);
  38. void close_display(void);
  39. void end_run(void);
  40. void get_inputs(void);
  41. void init_display(int v_mode); 
  42. void new_union(void);
  43. void process_args (int argc, char* argv[]);
  44. void process_option (char* s);
  45. void reset_bounds(void);
  46. void set_precision(char* prec);
  47. void show_title(void);
  48. void usage(void);
  49. void write_header(void);
  50. void write_piece(void);   
  51. void write_end(void);
  52.  
  53. Format    format = POV;       // default output
  54. bool      nest_bounds = TRUE; 
  55. bool      bound_sum = FALSE;    // include bound stats w/ each bound written
  56. bool      display = FALSE;     // ****** change to FALSE for release version
  57. bool      extended = FALSE;    // ****** change to FALSE for release version
  58. int       v_mode=0;           // ****** change to 0 for release version 0-none 1-640x480 2-800x600 3-1024x768
  59. long      bound_val=30,bound_count=0;// bnd every ...and count # bounds written for next nested
  60. long      total_bounds = 1;  // start w/1 for default global bounding box
  61. long      counter=0;         // total # of objects written
  62. char      com[3] = "//";     // default comment char
  63. char      filename[80];      // outfile name
  64. char      union_name[80];    // for output file union name
  65. char      buff[257];         // general use buffer
  66. char      texture[80];
  67. clock_t   start, finish;  // ******** 2 lines for timer
  68. double    duration;   
  69. double    basic_rad = 1.0,sphere_rad=1.0;  // basic radius and current sphere radius
  70. double    bound_radi = 0.0;     // current max sph. radius for bound info
  71. double    prev_sphere_rad,first_sphere_rad; // radii
  72. double    ht_scale = 1.0; // flat or tall plant
  73. double    internal_scale, user_scale, overall_scale;  // fixes numbers so object is 2 units 
  74. Vector    ray  = {0.0, 0.0, 0.0};  // outfile vector
  75. Vector    min  = {FLT_MAX, FLT_MAX, FLT_MAX};     // for nested bounding info
  76. Vector    max  = {FLT_MIN, FLT_MIN, FLT_MIN};     
  77. Vector    gmin = {FLT_MAX, FLT_MAX, FLT_MAX};  // for scene extent and 
  78. Vector    gmax = {FLT_MIN, FLT_MIN, FLT_MIN};  // global bounding info
  79.  
  80. ofstream  outfile;    //  these vars are used for basic shape calculations
  81. double    pi=3.1415926535897932384626; //  pi ...lower #'s change 'radius' of plant
  82. int       nume=30;            //  numerator of probability ...left or rite ?
  83. int       denom=100;          //  denominator of prob.
  84. int       number=4;           //  number of branches per cluster
  85. double    rad=4.5;            //  length of straight line segments
  86. double    deltheta=0.1;       //  change in THETA (radians)    
  87. int       segs=60;            //  max objects & line segments per branch
  88. int       size=60;
  89. double    redux=3.0;          //  how much to divide # of segments...lower # means finer 'res.' (more objects)
  90. int       min_len=1;          //  min # of line segments (spheres per branch)
  91. int       x,y;                //  display vector...object vector is derived from this also
  92.  
  93.  
  94.  
  95. //main
  96. int main(int argc, char* argv[])             
  97. {   
  98.     if(argc>1)process_args (argc, argv);    
  99.     
  100.     show_title(); 
  101.     get_inputs();               //  get user input and check for 'validity' 
  102.             
  103.     outfile.open(filename,ios::out);      // try to open disk file
  104.     if(! outfile)   exit(1);   // if disk access error,exit       
  105.     
  106.     if(display) init_display(v_mode);     // try to set graphics display 
  107.     
  108.     write_header();    
  109.     outfile.setf(ios::showpoint | ios::fixed);//outfile.precision(6);            
  110.     srand( (unsigned)time(NULL) );         //   seed random number    
  111.     
  112.     x=512,y=384;   //  set origin of cluster    
  113.     internal_scale = 0.1111;                     // default object size is 
  114.     overall_scale  = internal_scale*user_scale;  // approx.10x10x10
  115.     size = segs;  
  116.     bound_val = segs*0.5; // seems to be the best figure as far as rendering
  117.                           //    speed and bound accuracy are concerned
  118.     if(display)  cerr << "TOP VIEW (XZ)\n"; 
  119.     cerr << "\nCalculating object... Press any key to abort\n\n";
  120.      start = clock(); // ****************** start timer
  121.  
  122.     calc_cluster(size, x, y);          // calculate plant and show progress 
  123.    
  124.     if(format != CTDS) bound_piece(); // write final nested bound if nec.     
  125.     write_end(); 
  126.     outfile.close;          //  close disk file  
  127.     finish = clock();    // *********************  stop timer
  128.     duration = (double)(finish - start) / CLOCKS_PER_SEC;  // *** calc. time
  129.     
  130.     if(display) {
  131.      cerr << "Press any key to continue...";
  132.      getch();                        //  wait for keypress
  133.      close_display();    //  restore video to previous state
  134.     }       
  135.     cout << endl << counter << " spheres used to create " << filename;
  136.     cout << "\nCalculation time : "<<duration<< " seconds\n"; // show time
  137.     return(0);
  138. }
  139.  
  140. /******************************                    **************************
  141. ****************************** FUNCTION DEFINITIONS *************************
  142.  ******************************                    *************************/
  143.         
  144. void bound_piece()
  145. {    
  146.     Vector cbmin,cbmax; // current bound min and max vectors         
  147.     
  148.     cbmax.x = max.x + bound_radi;
  149.     cbmin.x = min.x - bound_radi;
  150.     cbmax.y = max.y + bound_radi;
  151.     cbmin.y = min.y - bound_radi;
  152.     cbmax.z = max.z + bound_radi;  
  153.     cbmin.z = min.z - bound_radi;  
  154.             
  155.  switch(format){
  156.    case POLY :          
  157.     if(nest_bounds){ outfile << "  bounding_box < " <<cbmin.x<<", "<<cbmin.y<<", "<<cbmin.z<<" >,<"
  158.                                                     <<cbmax.x<<", "<<cbmax.y<<", "<<cbmax.z<<" >\n"
  159.                                                     << " }"; // close the UNION                
  160.     }
  161.     else {           outfile << "  }";       
  162.     }               
  163.      break;                             
  164.    case POV  :
  165.     if(nest_bounds){ outfile << "  }\n" 
  166.                              << " bounded_by{ \n"
  167.                              << "  box{ < " << cbmin.x<<" "<<cbmin.y<<" "<<cbmin.z << "> < "
  168.                                             << cbmax.x<<" "<<cbmax.y<<" "<<cbmax.z << "> }\n  }\n"            
  169.                              << " }  ";                                                    
  170.     }
  171.     else { outfile << "  }\n }";        
  172.     }                 
  173.   }  
  174.   if(bound_sum){        
  175.     outfile <<com<<"          Current bounding box info...\n"        
  176.             <<com<<"                 Min. x : " << cbmin.x << endl
  177.             <<com<<"                      y : " << cbmin.y << endl
  178.             <<com<<"                      z : " << cbmin.z << endl
  179.             <<com<<"                 Max. x : " << cbmax.x << endl        
  180.             <<com<<"                      y : " << cbmax.y << endl         
  181.             <<com<<"                      z : " << cbmax.z; 
  182.   }               
  183.   outfile << endl;
  184. }   
  185.  
  186.  
  187. void calc_bounds()
  188. {
  189.     // compute min and max object vectors for current bounding box if needed
  190.  if(format != CTDS && nest_bounds){  
  191.    min.x = __min(min.x,ray.x);
  192.    max.x = __max(max.x,ray.x);
  193.    min.y = __min(min.y,ray.y);
  194.    max.y = __max(max.y,ray.y);
  195.    min.z = __min(min.z,ray.z);
  196.    max.z = __max(max.z,ray.z);      
  197.  }                        
  198.            
  199.    gmin.x = __min(gmin.x,ray.x);    // now globally
  200.    gmax.x = __max(gmax.x,ray.x);
  201.    gmin.y = __min(gmin.y,ray.y);
  202.    gmax.y = __max(gmax.y,ray.y);
  203.    gmin.z = __min(gmin.z,ray.z);
  204.    gmax.z = __max(gmax.z,ray.z);
  205. }        
  206.        
  207. void calc_branch(int size, double theta, double x, double y)
  208. {
  209.     for(int j=0; j<size; j++)
  210.     {                                   //  get rand. #, range 0 to denom
  211.         int randy = rand() % denom;
  212.         int chng = (randy<nume) ? -1 : 1;   //  left or right ??
  213.         theta = theta + chng * deltheta;    //  new angle
  214.         x = x + rad*sin(theta);             //  x and y  
  215.         y = y + rad*cos(theta);             //   of next point  
  216.                         
  217.         if(size<(segs*0.0667)){ ray.y =j+(segs-3)+(segs/redux)+((segs/redux)/redux);  
  218.               if(display) _setcolor(RED); 
  219.               if(j==0) strcpy(texture,"flower_tex"); 
  220.               sphere_rad = basic_rad*1.2;                     
  221.          } 
  222.         else if(size<(segs*0.22)){ ray.y =j+(segs-2)+(segs/redux);         
  223.               if(display) _setcolor(YELLOW); 
  224.               if(j==0) strcpy(texture,"sub_branch_tex"); 
  225.               sphere_rad = basic_rad*1.45;                    
  226.          } 
  227.         else if(size<(segs*0.675)){ ray.y =j+(segs-1);             
  228.               if(display) _setcolor(LIGHTGREEN); 
  229.               if(j==0) strcpy(texture,"branch_tex");
  230.               sphere_rad = basic_rad*1.85;               
  231.          }
  232.         else{ ray.y =j;
  233.               if(display) _setcolor(GREEN);  //dk green
  234.               if(j==0) strcpy(texture,"stem_tex");
  235.               sphere_rad = basic_rad*2.25;                       
  236.          }       
  237.         if(display){
  238.           if     (v_mode==1) _lineto(int(x*0.625),int(y*0.625)); 
  239.           else if(v_mode==2) _lineto(int (x*0.78125),int(y*0.78125)); 
  240.           else               _lineto(int(x),int(y));  // draw line                        
  241.         } 
  242.                 
  243.         ray.x = ((double)(x-512)*0.3)*overall_scale;  // translate sizes to
  244.         ray.z = ((double)(y-384)*0.3)*overall_scale;  // file sizes based on      
  245.         ray.y = ray.y*overall_scale*ht_scale;         // scaling info...
  246.         sphere_rad *= overall_scale; 
  247.                 
  248.         if(counter==0){            //first time around only        
  249.           prev_sphere_rad = sphere_rad;  
  250.           first_sphere_rad = sphere_rad;
  251.         }             
  252.         bound_radi = prev_sphere_rad; //current bound, radius to add to bound
  253.                         
  254.         if((format != CTDS) &&                       // if it's POV or Polyray  AND  we're
  255.         (bound_count==bound_val && nest_bounds || //ready for a bound (nested only) OR....
  256.          prev_sphere_rad != sphere_rad && nest_bounds)// the sphere radius changed... time for a new bound
  257.         ){                                           //    (nested only)   GOT IT ??? (pretty twisted)
  258.          bound_piece();          
  259.          new_union();
  260.          total_bounds++;
  261.          reset_bounds(/*min,max*/);             
  262.          bound_count=1; 
  263.          write_piece();
  264.         }
  265.         else { 
  266.          bound_count++; 
  267.          write_piece();
  268.         }                
  269.         
  270.         prev_sphere_rad = sphere_rad; 
  271.         calc_bounds();     
  272.         counter++;                             // increment sphere count
  273.     }
  274.     if(size>min_len)
  275.     {                                   //  if branch long enough       
  276.         int newsize = size / redux;     //  but smaller than before
  277.         calc_cluster(newsize,x,y);         //  and display it
  278.     }
  279. }
  280.  
  281. void calc_cluster(int size, double x, double y)
  282. {
  283.     if( kbhit()) end_run();
  284.     
  285.     for(int i=0; i<number; i++)         //  for each branch
  286.     {
  287.         double theta = i * 2 * pi / number;    
  288.         
  289.         if(display){        
  290.           if     (v_mode==1) _moveto(int(x*0.625),int(y*0.625));
  291.           else if(v_mode==2) _moveto(int(x*0.78125),int(y*0.78125)); 
  292.           else               _moveto(int(x),int(y));  // get set to draw next line          
  293.         }     
  294.         
  295.                               //  make a branch
  296.         calc_branch(size, theta, x, y);        
  297.     }
  298. }
  299.  
  300.  
  301. void close_display()    
  302. {
  303.    _setvideomode(_DEFAULTMODE);    //  restore video to 'normal'
  304. }       
  305.  
  306. void end_run()
  307.    if(format != CTDS) bound_piece();
  308.    write_end();    
  309.    if(display)   close_display();    //  restore video to previous state   
  310.    cerr << "\n--RUN ABORTED--\n";
  311.    cout << counter << " spheres used to create " << filename << endl;
  312.    
  313.    exit(1);
  314. }   
  315.    
  316.  
  317. void get_inputs() 
  318. {   
  319.  int choice; double noise=1.0,pi_distort=1.0,sphere_mult=1.0,denom_mult=1.0;
  320.     
  321.     cout<< "\n1\tPOV\n2\tPolyray\n3\tCTDS\n" << "Number for format? [1]: ";
  322.         cin.getline(buff,256);           choice = atoi(buff);         
  323.     switch(choice){ case 2 : format = POLY;  break;  // output format
  324.                     case 3 : format = CTDS;  break;                   
  325.                     default: format = POV;        
  326.     }                 
  327.     cout << "Ouput filename? [plant.inc]: ";
  328.         cin.getline(buff,256);           strcpy(filename,buff);
  329. if(format != CTDS){
  330.     cout << "Union name? [plant]: ";
  331.         cin.getline(buff,256);           strcpy(union_name,buff);   }        
  332.     cout << "Number of branches (recursive) ? [4]:";
  333.         cin.getline(buff,256);           number = atoi(buff);    
  334.     cout << "Maximum # of spheres per branch ? [60]:";
  335.         cin.getline(buff,256);           segs = atoi(buff);
  336.     cout << "Minimum # of spheres per branch ? [1]:";
  337.         cin.getline(buff,256);           min_len = atoi(buff); 
  338. if(extended) {   
  339.     cout << "Divide branches by ? [3.0]:";
  340.         cin.getline(buff,256);           redux = atof(buff);  
  341.     cout << "Radial distortion (PI * x)  ? [1.0]:";
  342.         cin.getline(buff,256);           pi_distort = atof(buff);     
  343.     cout << "Branch rotation factor ? [1.0]:";
  344.         cin.getline(buff,256);           denom_mult = atof(buff);    
  345.     cout << "Overall noise factor ? [1.0]:";
  346.         cin.getline(buff,256);           noise = atof(buff);    
  347.     cout << "Height scaling  ? [1.0]:";
  348.         cin.getline(buff,256);           ht_scale = atof(buff); 
  349.     cout << "Sphere scaling  ? [1.0]:";
  350.         cin.getline(buff,256);           sphere_mult = atof(buff);   }                                                
  351.     cout << "Global scaling  ? [1.0]: ";
  352.         cin.getline(buff,256);           user_scale = atof(buff);
  353.     
  354.         // Set up default values if applicable
  355.     if(filename[0]=='\0') strcpy(filename,"plant.inc");
  356.     if(union_name[0]=='\0') strcpy(union_name,"plant");    
  357.     if(min_len==0) min_len = 1;         
  358.     if(denom_mult==0.0) denom_mult = 1.0; denom *= denom_mult;   
  359.     if(number==0) number = 4;       if(user_scale==0.0) user_scale = 1.0;
  360.     if(pi_distort==0.0) pi_distort = 1.0;  pi *= pi_distort;
  361.     if(noise==0.0) noise = 1.0;  deltheta *= noise;
  362.     if(segs==0) segs = 60;          if(redux==0.0) redux = 3.0;
  363.     if(ht_scale==0.0) ht_scale = 1.0;  
  364.     if(sphere_mult==0.0) sphere_mult = 1.0; basic_rad *= sphere_mult;
  365. }
  366.  
  367.  
  368. void init_display(int v_mode) 
  369. {     
  370.     switch(v_mode){
  371.         case 3  : if(!_setvideomode(_XRES16COLOR)) {cerr << "\nCouldn't set 1024x768 graphics mode... trying 800x600\n"; v_mode = 2;}
  372.                    else break;       /* 1024x768x16 */
  373.         case 2  : if(!_setvideomode(_SRES16COLOR)) {cerr << "\nCouldn't set 800x600 graphics mode... trying 640x480\n";  v_mode = 1;}
  374.                    else break;       /*  800x600x16 */ 
  375.         case 1  : if(!_setvideomode(_VRES16COLOR)) {cerr << "\nCouldn't set 640x480 graphics mode... continuing without display\n"; v_mode = 0;}
  376.                    else break;       /*  640x480x16 */
  377.         default : display = FALSE;   /*  no display */                
  378.      }              
  379. }
  380.  
  381.     
  382. void new_union()
  383. {  
  384.  
  385.   switch(format){
  386.    case POV  :          
  387.        outfile << " object{\n  union{\n"; break;
  388.    case POLY :                      
  389.        outfile << "+object{ \n";           break;
  390.   }
  391.        
  392.  
  393.  
  394. void process_args (int argc, char* argv[])
  395. {
  396.     for (int i = 1; i < argc; i++)
  397.     {
  398.         if (argv[i][0] == '-' || argv[i][0] == '/')
  399.             process_option (&argv[i][1]);
  400.         else
  401.         {usage();   exit(1);}
  402.     }
  403. }     
  404.  
  405.  
  406. void process_option (char* s)
  407. {
  408.     switch (toupper(s[0]))
  409.     {    
  410.     case 'E': extended = TRUE;       break;
  411.     case 'P': set_precision(&s[1]);  break;
  412.     case 'D': display = TRUE; v_mode = atoi(&s[1]);  break;
  413.     case 'N': nest_bounds = FALSE;   break;
  414.     case 'S': bound_sum = TRUE;      break;
  415.     case '?': usage(); exit(0);
  416.     case 'H': usage(); exit(0);
  417.     default : usage(); exit(1);     
  418.     }
  419. }
  420.  
  421. void reset_bounds()
  422. {
  423.     min.x=FLT_MAX, min.y=FLT_MAX, min.z=FLT_MAX;  // 
  424.     max.x=FLT_MIN, max.y=FLT_MIN, max.z=FLT_MIN;  // reset for new bounding box
  425. }    
  426.  
  427. void set_precision(char* prec)
  428. {  
  429.     outfile.precision((atoi(prec) > 2 ? atoi(prec) : 6 ));  
  430. }
  431.  
  432. void show_title()
  433. {
  434.     cout << "\nPlant v"<< VERSION << ", Copyright (c) 1993 Rob Bryerton\n"    
  435.          << "Creates a data file of a plant-like object for the PoV-Ray v1.0" << endl
  436.          << "and Polyray v1.6 raytracers, and the Connect The Dots Smoother (CTDS).\n";             
  437. }         
  438.     
  439. void write_header()
  440. {
  441.  if(format==CTDS){ strcpy(com,";"); strcpy(union_name,"-----");}
  442.    
  443.    outfile 
  444.     <<com<<" File: "<<filename<<"  Union Name: "<<union_name<< endl
  445.     <<com<<" This data file created by PLANT.EXE v"<<VERSION<<" for the PoV Ray v1.0 and\n"
  446.     <<com<<" Polyray v1.6 raytracers, and the Connect The Dots Smoother (CTDS).\n"  
  447.     <<com<<" ----------------SEE END OF LISTING FOR OBJECT EXTENTS----------------------\n\n";   
  448.  switch(format) {    
  449.   case POLY :
  450.    outfile 
  451.     << "include \"..\\colors.inc\"\n"
  452.     //<< "include \"..\\texture.inc\"\n\n"
  453.     << "define stem_tex       texture{ matte { color <0.0, 0.65, 0.0> } }\n" 
  454.     << "define branch_tex     texture{ matte { color <0.0, 0.8, 0.0> } }\n"
  455.     << "define sub_branch_tex texture{ matte { color yellow } }\n"
  456.     << "define flower_tex     texture{ matte { color red } }\n\n"
  457.     << "define " << union_name << endl
  458.     << "object{ \n object{\n";         break;
  459.    case POV  :
  460.     outfile 
  461.     << "#declare stem_tex=       texture{ diffuse 0.7 color green 0.65  } \n" 
  462.     << "#declare branch_tex=     texture{ diffuse 0.7 color green 0.8  } \n"
  463.     << "#declare sub_branch_tex= texture{ diffuse 0.7 color Yellow } \n"
  464.     << "#declare flower_tex=     texture{ diffuse 0.7 color Red } \n\n"            
  465.     << "declare "<<union_name<<" = composite{ \nobject{\n union{\n";       
  466.  }
  467. }   
  468.  
  469. void write_piece()
  470. {       
  471.       switch(format){
  472.        case POLY :
  473.         if(counter !=0 && bound_count!=1) outfile << "   +"; //  for Polyray union 
  474.         else                              outfile << "    ";
  475.         outfile << "object{ sphere < " <<ray.x<< ", " << ray.y << ", " <<ray.z<< " >, " << sphere_rad << "  " << texture <<" }\n";
  476.            break;
  477.        case CTDS :         
  478.         if(sphere_rad != prev_sphere_rad) outfile << endl; //insert blank line for CTDS for each new sphere size for /m option
  479.         outfile << ray.x<< " " << ray.y << " " <<ray.z<< " " << sphere_rad << endl;
  480.            break;
  481.        default :    // (POV 1.0)
  482.         outfile << "   sphere{ < "<<ray.x<<" "<<ray.y<<" "<<ray.z<<" > "<<sphere_rad<<" texture{ " <<texture<< "} }\n";
  483.       }
  484. }
  485.  
  486.  
  487.     
  488. void write_end()
  489. {           
  490.     gmax.x += first_sphere_rad;   
  491.     gmin.x -= first_sphere_rad; 
  492.     gmax.y += first_sphere_rad;   
  493.     gmin.y -= first_sphere_rad; 
  494.     gmax.z += first_sphere_rad;
  495.     gmin.z -= first_sphere_rad;   
  496.         
  497.  switch(format){
  498.    case POLY :          
  499.     outfile << "  bounding_box < " <<gmin.x<<", "<<gmin.y<<", "<<gmin.z<<" >,<"
  500.                                    <<gmax.x<<", "<<gmax.y<<", "<<gmax.z<<" >\n"
  501.             << "}\n\n";  break;   // close the UNION
  502.           
  503.    case POV  :
  504.     outfile << " bounded_by{\n"
  505.             << "  box{ < " << gmin.x<<" "<<gmin.y<<" "<<gmin.z << "> < "
  506.                            << gmax.x<<" "<<gmax.y<<" "<<gmax.z << "> }\n  }\n"            
  507.             << "}\n\n"; // close composite                                               
  508.   } // this next block is output for ALL formats w/the appropriate comment char's       
  509.  if(format != CTDS){
  510.  outfile <<com<<" Bounds written...."<< total_bounds << endl; }
  511.  outfile <<com<<" Spheres written..."<< counter << endl << endl       
  512.          <<com<<"   Object extents are as follows...\n"        
  513.          <<com<<"     Min. x : " << gmin.x << endl
  514.          <<com<<"          y : " << gmin.y << endl
  515.          <<com<<"          z : " << gmin.z << endl
  516.          <<com<<"     Max. x : " << gmax.x << endl        
  517.          <<com<<"          y : " << gmax.y << endl         
  518.          <<com<<"          z : " << gmax.z << endl;
  519. }                
  520.     
  521.  
  522.  
  523. void usage()
  524. {
  525.     cerr << "\n                               Plant v" << VERSION << endl          
  526.         << "Usage: plant [options]\n"
  527.         << "Options:  -d#   enables 2D (xz) display of plant... # is the graphics mode.\n"        
  528.         << "                0=no display  1=640x480  2=800x600  3=1024x768  \n"
  529.         << "                Default value is 0.\n"
  530.         << "          -e    Gives you a menu with an extended choice of options.\n"        
  531.         << "          -n    No nested bounds in POV or Polyray output.\n" 
  532.         << "          -p#   where # is the precision of the output file numbers.\n"
  533.         << "                Range is 3 - 9 with a default precision of 6 decimal places.\n" 
  534.         << "          -s    Include all bounding stats in output file. (POV and Polyray)\n"
  535.         << "\nType PLANT with no parameters for the default menus and options.\n";        
  536. }
  537.  
  538.  
  539.