home *** CD-ROM | disk | FTP | other *** search
/ HomeWare 14 / HOMEWARE14.bin / graphics / dna095.arj / DNA_V095.CPP next >
C/C++ Source or Header  |  1994-01-11  |  19KB  |  439 lines

  1. /*****************************************************************************         
  2.  Program : DNA.EXE v0.95
  3.  Purpose : Creates twisted ladder-shaped objects ( like DNA strands ) for the 
  4.            POV-Ray v2.x raytracer.   
  5.  Created : 12/30/93
  6.  By      : Rob Bryerton CIS [73747,433]           
  7.  File    : DNA_v095.CPP
  8.  Compiler: Microsoft C++ v8.00 (MSVC v1.0) 
  9.  Model   : Medium
  10.  Comments: To do... add graphic preview...
  11. *****************************************************************************/     
  12.  
  13. #include <fstream.h>
  14. #include <math.h>  
  15. #include <stdlib.h> 
  16. #include <string.h>
  17.  
  18. const char cVERSION[6] = "v0.95";
  19. const int MAXDOSPREFIX = 8;
  20.  
  21. enum   BOOL   {FALSE, TRUE};
  22. enum   Format {POV, POLY, CTDS}; 
  23. struct Flags  {BOOL WriteStrand_1, WriteStrand_2, WriteConnectors;
  24.                Format format;
  25.               };
  26.  
  27. char *AddFileExtension(char *FileName, char *FileExtension);
  28.  
  29. void ErrExit(char *cMessage);
  30.  
  31. void GetAndValidateUserInput(char *cSceneFileName, char *cIncludeFileName,
  32.                              char *cUnionName, double *dHeight, 
  33.                              double *dRadius, double *dPartRadius, 
  34.                              long *lStepsPerRevolution, long *lTotalSteps,
  35.                              long *lConnectXsteps, Flags &flags);
  36.  
  37. void ProcessArgs(int argc, char *argv[], Flags *flags);
  38.  
  39. void ShowTitle();
  40.  
  41. void Usage();
  42.  
  43. void WriteCone(double dLastX, double dLastY, double dLastZ, 
  44.                double dX, double dY, double dZ,
  45.                double dRad, ofstream& outfile, long *lGlobalCounter,
  46.                Flags& flags);  
  47.  
  48. void WriteFileEnd(ofstream& outfile, long lGlobalCounter); 
  49.  
  50. void WriteFileHeader(char *cSceneFileName, char *cIncludeFileName, 
  51.                      char *cUnionName, ofstream& outfile, Flags& flags);
  52.  
  53. void WriteSceneFile(char *cSceneFileName, char *cIncludeFileName, char *cUnionName,
  54.                      double dHeight, double dRadius, Flags& flags);                     
  55.  
  56. void WriteSphere(double dX, double dY, double dZ, double dRad, 
  57.                  ofstream& outfile, long *lGlobalCounter, Flags& flags);
  58.  
  59. void Usage();                 
  60.  
  61. int main(int argc, char *argv[])
  62. {          
  63.     char   cSceneFileName[80] = "DNA.POV";      
  64.     char   cIncludeFileName[80] = "DNA.INC";
  65.     char   cUnionName[80] = "DNA";    
  66.     double dRadius;    // the radius of the twister (DNA strand)
  67.     double dHeight;    // the overall Y-length ('height) of the object    
  68.     double dPartRadius;// the radius of the spheres (and cones) written at each coordinate
  69.     double dLastXpos1, dLastZpos1, dLastYpos; // stores the previous values... used
  70.     double dLastXpos2, dLastZpos2;            //    to connect the cones together    
  71.     long   lTotalSteps;// the TOTAL number of coords calc'd
  72.     long   lStepsPerRevolution;   
  73.     long   lGlobalCounter = 0;  // the overall # of objects written to file
  74.     long   lConnectorCounter = 0;  // ready for another connector??
  75.     long   lConnectXsteps;        // connect strands every X steps
  76.  
  77.     // initialize a structure that controls object properties
  78.     //   default format... write complete DNA strand
  79.     Flags flags = {TRUE, TRUE, TRUE, POV};    
  80.         
  81.     ShowTitle();     // show the title screen and process comd. line args, if any                             
  82.     if(argc > 1) ProcessArgs(argc, argv, &flags);   
  83.     
  84.                /* get some user input and check for validity */    
  85.     GetAndValidateUserInput(cSceneFileName, cIncludeFileName, 
  86.                             cUnionName, &dHeight,
  87.                             &dRadius, &dPartRadius, 
  88.                             &lStepsPerRevolution, &lTotalSteps, 
  89.                             &lConnectXsteps, flags);
  90.     
  91.                         /* Open file for output */    
  92.                 //    try to open a disk file  
  93.     ofstream outfile(cIncludeFileName, ios::out | ios::showpoint | ios::fixed);
  94.     if(! outfile)     ErrExit("opening file.");    //    can't open disk file,exit    
  95.         
  96.     WriteFileHeader(cSceneFileName, cIncludeFileName, cUnionName, outfile, flags);
  97.     
  98.                  /* caculate each vector and write to file */
  99.     for(long lCurrentStep = 0; lCurrentStep < lTotalSteps; ++lCurrentStep)
  100.     {   
  101.         const double dPI = 3.1415926535897932384626;// PI, to calc polar co-ords       
  102.         double dAngle = dPI * 2 * ( (double)lCurrentStep / (double)lStepsPerRevolution );
  103.         double dYpos  = dHeight * ( (double)lCurrentStep / (double)lTotalSteps );
  104.         double dXpos1 = dRadius * cos(dAngle);  // translate polar co-ords to
  105.         double dZpos1 = dRadius * sin(dAngle);  //    rectangular co-ords                
  106.         double dXpos2 = fabs(dRadius) * cos(dAngle);
  107.         double dZpos2 = fabs(dRadius) * sin(dAngle);                      
  108.         
  109.         if(flags.WriteStrand_1)
  110.             WriteSphere(dXpos1, dYpos, dZpos1, dPartRadius, 
  111.                         outfile, &lGlobalCounter, flags);
  112.         if(flags.WriteStrand_2)        
  113.             WriteSphere(dXpos2, dYpos, dZpos2, dPartRadius, 
  114.                         outfile, &lGlobalCounter, flags);         
  115.                 
  116.         if(lCurrentStep > 0) // ignore this clause the first time around
  117.         {   
  118.             if(flags.WriteStrand_1)
  119.                 WriteCone(dLastXpos1, dLastYpos, dLastZpos1, 
  120.                           dXpos1, dYpos, dZpos1,
  121.                           dPartRadius, outfile, &lGlobalCounter,
  122.                           flags);
  123.             if(flags.WriteStrand_2)
  124.                 WriteCone(dLastXpos2, dLastYpos, dLastZpos2, 
  125.                           dXpos2, dYpos, dZpos2,
  126.                           dPartRadius, outfile, &lGlobalCounter,
  127.                           flags);                    
  128.         }                   
  129.         
  130.         if(flags.WriteConnectors)
  131.         {    
  132.             lConnectorCounter++;
  133.             if(lConnectorCounter == lConnectXsteps) /* write a connector? */          
  134.             {
  135.                 WriteCone(dXpos1, dYpos, dZpos1, 
  136.                           dXpos2, dYpos, dZpos2,
  137.                           dPartRadius, outfile, &lGlobalCounter,
  138.                           flags);
  139.                 lConnectorCounter = 0;  // reset counter to calc the next connector
  140.             }
  141.         }    
  142.             
  143.         dLastXpos1 = dXpos1;      // now store x, y etc in Lastx, LastY etc
  144.         dLastZpos1 = dZpos1;      //  so we can use them on the next loop to
  145.         dLastXpos2 = dXpos2;      //  connect the cones and spheres together
  146.         dLastZpos2 = dZpos2;
  147.         dLastYpos  = dYpos;        
  148.     }        
  149.     
  150.     WriteFileEnd(outfile, lGlobalCounter);
  151.     cout << lGlobalCounter << " objects written to " << cIncludeFileName << endl;       
  152.     
  153.     outfile.close();   // close the output file
  154.                                   
  155.                    // now write a scene file to show the new object
  156.     WriteSceneFile(cSceneFileName, cIncludeFileName, cUnionName, 
  157.                    dHeight, dRadius, flags);
  158.     // we're outa' here !
  159.     return(0);
  160. }    
  161.     
  162.  
  163.  
  164. /************************** FUNCTION DEFINITIONS *****************************/
  165.  
  166.  
  167. char *AddFileExtension(char *FileName, char *FileExtension)
  168. {
  169.     for(int i = 0; i < (int)strlen(FileName); i++)
  170.         if(FileName[i] == '.')    break;         
  171.     if( i > MAXDOSPREFIX ) i = MAXDOSPREFIX;                    
  172.     strcpy(&FileName[i], ".");
  173.     strcpy(&FileName[i+1], FileExtension);
  174.     return FileName;
  175. }    
  176.  
  177.  
  178. void ErrExit(char *cMessage)
  179. {   
  180.     cerr << "\a\n\nERROR " << cMessage << "- Exiting \n";
  181.     exit(1);
  182. }    
  183.  
  184.  
  185. void GetAndValidateUserInput(char *cSceneFileName, char *cIncludeFileName, 
  186.                              char *cUnionName, double *dHeight, 
  187.                              double *dRadius, double *dPartRadius, 
  188.                              long *lStepsPerRevolution, long *lTotalSteps,
  189.                              long *lConnectXsteps, Flags& flags)
  190. {       
  191.     char cBuffer[256];            // general use (user input) buffer  
  192.     const int iBUFFSIZE = 255;// constant size for cin.getline()    
  193.     
  194.     cout << "\nOutput file name [DNA.INC]:";
  195.     cin.getline(cBuffer,iBUFFSIZE);
  196.     if(cBuffer[0] == NULL) strcpy(cBuffer, "DNA.INC");
  197.     strcpy(cSceneFileName, strcpy(cIncludeFileName, AddFileExtension(_strupr(cBuffer), "INC")));    
  198.     if(flags.format == POV) AddFileExtension(cSceneFileName, "POV");
  199.     else                    AddFileExtension(cSceneFileName, "PI");
  200.  
  201.     cout << "Union name [DNA]:";
  202.     cin.getline(cBuffer,iBUFFSIZE);
  203.     if(cBuffer[0] == NULL) strcpy(cBuffer, "DNA");
  204.     strcpy(cUnionName, cBuffer);
  205.         
  206.     cout << "Height (Y units) of object [50.0]:";
  207.     cin.getline(cBuffer,iBUFFSIZE);    
  208.     *dHeight = atof(cBuffer); 
  209.     if( *dHeight <= 0.0 ) *dHeight = 50.0;
  210.     
  211.     cout << "Radius (X-Z) of object [10.0]:";
  212.     cin.getline(cBuffer,iBUFFSIZE);    
  213.     *dRadius = atof(cBuffer);
  214.     if( *dRadius <= 0.0 ) *dRadius = 10.0;
  215.     *dRadius -= (*dRadius * 2);   // to make the result a negative
  216.         
  217.     cout << "Radius of individual objects [0.5]:";
  218.     cin.getline(cBuffer,iBUFFSIZE);    
  219.     *dPartRadius = atof(cBuffer);
  220.     if(*dPartRadius <= 0.0 ) *dPartRadius = 0.5;
  221.     
  222.     cout << "Steps per revolution [30]:";
  223.     cin.getline(cBuffer,iBUFFSIZE);    
  224.     *lStepsPerRevolution = atoi(cBuffer);
  225.     if(*lStepsPerRevolution <= 0 ) *lStepsPerRevolution = 30;
  226.     
  227.     cout << "Connect strands every X steps [3]:";
  228.     cin.getline(cBuffer,iBUFFSIZE);    
  229.     *lConnectXsteps = atoi(cBuffer);
  230.     if(*lConnectXsteps <= 0 ) *lConnectXsteps = 3;
  231.                                          
  232.     cout << "Number of revolutions [1]:";
  233.     cin.getline(cBuffer,iBUFFSIZE);    
  234.     *lTotalSteps = atoi(cBuffer);
  235.     if(*lTotalSteps <=0) *lTotalSteps = 1;
  236.     *lTotalSteps = (*lTotalSteps * *lStepsPerRevolution);  
  237.     // That * operator sure gets around!
  238. }                                                                                
  239.  
  240.  
  241. void ProcessArgs(int argc, char *argv[], Flags *flags)
  242. {
  243.     for(int i = 1; i < argc; i++)
  244.     {
  245.         if(argv[i][0] == '-' || argv[i][0] == '/')                
  246.             switch(toupper(argv[i][1]))
  247.             {                   
  248.                 //case 'E': extended = TRUE;       break;
  249.                 case 'O': switch(toupper(argv[i][2]))
  250.                           {
  251.                               case 'P' : flags->format = POV;  break; // default
  252.                               case 'L' : flags->format = POLY; break;
  253.                               default  : Usage(); exit(1);
  254.                           }                          
  255.                           break;
  256.                 //case 'D': display = TRUE; 
  257.                           //v_mode = atoi(&s[1]);  break;  //def=no display                    
  258.                 //case 'T': write_texture = FALSE; break; //def=TRUE, write textures
  259.                 case 'F': switch(argv[i][2])
  260.                           {
  261.                               case '0'  : break; // default; does not modify flags structure
  262.                               case '1'  : flags->WriteConnectors = FALSE; break;
  263.                               case '2'  : flags->WriteStrand_1   = FALSE; 
  264.                                           flags->WriteStrand_2   = FALSE; break;
  265.                               case '3'  : flags->WriteStrand_2   = FALSE; break;
  266.                               case '4'  : flags->WriteConnectors = FALSE;
  267.                                           flags->WriteStrand_2   = FALSE; break;
  268.                               default   : Usage(); exit(1);
  269.                           }   
  270.                           break;   
  271.                 case '?': Usage(); exit(0);
  272.                 case 'H': Usage(); exit(0);
  273.                 default : Usage(); exit(1);     
  274.             }
  275.         else
  276.         {
  277.            Usage();
  278.            exit(1);
  279.         }
  280.     }
  281. }     
  282.  
  283.  
  284. void ShowTitle()
  285. {
  286.     cout << "\nDNA "<< cVERSION << ", Copyright (c) 1994 Rob Bryerton\n"    
  287.          << "Creates a data file of a twisted ladder-shaped object (like a DNA strand)\n"
  288.          << "for the POV-Ray v2.x and PolyRay v1.6 raytracers.\n";
  289. }         
  290.  
  291. void Usage()
  292. {
  293.    cerr << endl          
  294.         << "Usage: DNA [options]\n"        
  295.    //     << "Options: -d#   enables 2D (xz) display of object... # is the graphics mode.\n"        
  296.    //     << "                 0=no display (default) \n"  
  297.    //     << "                 1=640x480    \n"  
  298.    //     << "                 2=800x600    \n"  
  299.    //     << "                 3=1024x768   \n"        
  300.         << "Options: -f#   Where # is the option to set the following flags:\n"
  301.         << "                 0= Write complete object. (default) \n"
  302.         << "                 1= Do NOT write connectors.\n"
  303.         << "                 2= Write horizontal connectors ONLY.\n"
  304.         << "                 3= Write only one spiral.\n"
  305.         << "                 4= Write only one spiral but do NOT write connectors.\n"
  306.         << "         -o    Output format. Choices are:\n"
  307.         << "                 P=POV-Ray v2.x... (default) -oP\n"
  308.         << "                 L=PolyRay v1.6...           -oL\n"
  309.         << "\nType DNA with no parameters to accept the default options.\n";        
  310. }
  311.  
  312. void WriteCone(double dLastX, double dLastY,     double dLastZ, 
  313.                       double dX,     double dY,         double dZ,    
  314.                       double dRad,   ofstream& outfile, long *lGlobalCounter,
  315.                       Flags& flags)
  316. {   
  317.     switch(flags.format)
  318.     {
  319.         case POV  : outfile << "\n  cone{ < " <<dLastX<< ", " << dLastY << ", " <<dLastZ<< " >, " << dRad 
  320.                                          << ", < " <<dX<< ", " << dY << ", " <<dZ<< " >, " << dRad << " }";
  321.                     break;
  322.         
  323.         case POLY : char cToken[2] = " ";
  324.                     if(*lGlobalCounter > 0) strcpy(cToken, "+");        
  325.                     outfile << "\n " << cToken << "object { cone < " <<dLastX<< ", " << dLastY << ", " <<dLastZ<< " >, " << dRad 
  326.                                                                << ", < " <<dX<< ", " << dY << ", " <<dZ<< " >, " << dRad << " }";
  327.     }                                    
  328.     ++*lGlobalCounter; //increment counter (why won't postfix notation work ????)
  329. }    
  330.  
  331. void WriteFileEnd(ofstream& outfile, long lGlobalCounter)
  332. {
  333.     outfile << "\n}\n"
  334.             << "\n// " << lGlobalCounter << " objects written to this file.\n"; 
  335. }
  336.  
  337. void WriteFileHeader(char *cSceneFileName, char *cIncludeFileName, char *cUnionName, ofstream& outfile, Flags& flags)
  338. {   
  339.     cout<< "\nCreating data file " << cIncludeFileName << endl;
  340.     
  341.     outfile << "//  This data file created by DNA.EXE " << cVERSION << " for the POV-Ray v2.x and \n"
  342.             << "//  PolyRay v1.6 raytracers.\n"
  343.             << "//  Scene File: " << cSceneFileName << "   Include File: " << cIncludeFileName << "   Union Name: " << cUnionName << endl;
  344.             
  345.     switch(flags.format)
  346.     {
  347.         case POV  : outfile << "\n#declare " << cUnionName << " =\n"
  348.                             << "union {";  
  349.                     break; 
  350.         case POLY : outfile << "\ndefine " << cUnionName << endl
  351.                             << "object {";  
  352.                     break; 
  353.     }                   
  354.             
  355. }
  356.  
  357. void WriteSceneFile(char *cSceneFileName, char *cIncludeFileName, char *cUnionName,
  358.                      double dHeight, double dRadius, Flags& flags)
  359. {
  360.     struct Vector{ double x,y,z;};        
  361.     Vector CamLocation, CamLookAt, LightLocation;      
  362.                             /* Open file for output */                
  363.     ofstream outfile(cSceneFileName, ios::out | ios::showpoint | ios::fixed);
  364.     if(! outfile)     ErrExit("opening file.");    //    if we can't open a disk file, exit    
  365.         
  366.     cout<< "Creating scene file " << cSceneFileName << endl; 
  367.         
  368.     //  calculate camera and light vectors based on object size     
  369.     CamLocation.x = 0;
  370.     CamLocation.y = dHeight * 0.5;
  371.     CamLocation.z = dHeight - (dHeight * 2.2);
  372.     
  373.     CamLookAt.x = 0;
  374.     CamLookAt.y = dHeight * 0.5;
  375.     CamLookAt.z = 0;
  376.     
  377.     LightLocation.x = fabs(dRadius);
  378.     LightLocation.y = dHeight * 0.75;
  379.     LightLocation.z = dHeight - (dHeight * 2.0);         
  380.     
  381.     outfile << "//  This data file created by DNA.EXE " << cVERSION << " for the POV-Ray v2.x and \n"
  382.             << "//  PolyRay v1.6 raytracers.\n"
  383.             << "//  Scene File: " << cSceneFileName << "   Include File: " << cIncludeFileName << "   Union Name: " << cUnionName << endl;
  384.     switch(flags.format)
  385.     {
  386.         case POV  : outfile  << "#include \"colors.inc\"\n"
  387.                              << "#include \"textures.inc\"\n\n";
  388.                  
  389.                     outfile << "camera {\n"
  390.                             << "    location < " << CamLocation.x << ", " << CamLocation.y << ", " << CamLocation.z << " >\n"
  391.                             << "    look_at  < " << CamLookAt.x   << ", " << CamLookAt.y   << ", " << CamLookAt.z   << " >\n"
  392.                             << "}\n\n";
  393.                  
  394.                     outfile << "light_source { < " << LightLocation.x << ", " << LightLocation.y << ", " << LightLocation.z << " > color White }\n"
  395.                  
  396.                             << "\n#declare " << cUnionName << "_Texture ="
  397.                             << "\ntexture { Y_Gradient finish { ambient 0.3 } scale<1," << dHeight << ",1> }\n\n";
  398.                
  399.                    outfile << "#include \"" << cIncludeFileName << "\"\n\n"
  400.                            << "object{" 
  401.                            << "\n  " << cUnionName 
  402.                            << "\n  texture{ " << cUnionName << "_Texture rotate < 0,0,25 > }"
  403.                            << "\n}\n"; 
  404.                    break;              
  405.       case POLY :  outfile << "include \"..\\colors.inc\"\n"
  406.                            << "include \"..\\texture.inc\"\n\n";
  407.                  
  408.                    outfile << "viewpoint {\n"
  409.                            << "    from < " << CamLocation.x << ", " << CamLocation.y << ", " << CamLocation.z << " >\n"
  410.                            << "    at   < " << CamLookAt.x   << ", " << CamLookAt.y   << ", " << CamLookAt.z   << " >\n"
  411.                            << "    angle 53\n"
  412.                            << "    aspect 4/3\n"
  413.                            << "    resolution 320, 240\n"
  414.                            << "}\n\n";
  415.                  
  416.                    outfile << "light < " << LightLocation.x << ", " << LightLocation.y << ", " << LightLocation.z << " >\n"
  417.                  
  418.                            << "\ndefine " << cUnionName << "_Texture"
  419.                            << "\n  xz_wheel_texture { rotate < 0,0,15 > }\n\n";
  420.                
  421.                    outfile << "include \"" << cIncludeFileName << "\""
  422.                            << "\n" << cUnionName << " { " << cUnionName << "_Texture }";
  423.                            
  424.     }                 
  425. }                     
  426.  
  427. void WriteSphere(double dX, double dY, double dZ, double dRad, 
  428.                         ofstream& outfile, long *lGlobalCounter, Flags& flags)
  429. {    
  430.     switch(flags.format)
  431.     {
  432.         case POV  :    outfile << "\n  sphere{ < " << dX << ", " << dY << ", " << dZ << " > " << dRad << " }";
  433.                     break;
  434.         case POLY : char cToken[2] = " ";
  435.                     if(*lGlobalCounter > 0) strcpy(cToken, "+");
  436.                     outfile << "\n " << cToken << "object { sphere < " << dX << ", " << dY << ", " << dZ << " >, " << dRad << " }";            
  437.     }    
  438.     ++*lGlobalCounter;//increment counter (why won't postfix notation work ????)
  439. }