home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HomeWare 14
/
HOMEWARE14.bin
/
graphics
/
dna095.arj
/
DNA_V095.CPP
next >
Wrap
C/C++ Source or Header
|
1994-01-11
|
19KB
|
439 lines
/*****************************************************************************
Program : DNA.EXE v0.95
Purpose : Creates twisted ladder-shaped objects ( like DNA strands ) for the
POV-Ray v2.x raytracer.
Created : 12/30/93
By : Rob Bryerton CIS [73747,433]
File : DNA_v095.CPP
Compiler: Microsoft C++ v8.00 (MSVC v1.0)
Model : Medium
Comments: To do... add graphic preview...
*****************************************************************************/
#include <fstream.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
const char cVERSION[6] = "v0.95";
const int MAXDOSPREFIX = 8;
enum BOOL {FALSE, TRUE};
enum Format {POV, POLY, CTDS};
struct Flags {BOOL WriteStrand_1, WriteStrand_2, WriteConnectors;
Format format;
};
char *AddFileExtension(char *FileName, char *FileExtension);
void ErrExit(char *cMessage);
void GetAndValidateUserInput(char *cSceneFileName, char *cIncludeFileName,
char *cUnionName, double *dHeight,
double *dRadius, double *dPartRadius,
long *lStepsPerRevolution, long *lTotalSteps,
long *lConnectXsteps, Flags &flags);
void ProcessArgs(int argc, char *argv[], Flags *flags);
void ShowTitle();
void Usage();
void WriteCone(double dLastX, double dLastY, double dLastZ,
double dX, double dY, double dZ,
double dRad, ofstream& outfile, long *lGlobalCounter,
Flags& flags);
void WriteFileEnd(ofstream& outfile, long lGlobalCounter);
void WriteFileHeader(char *cSceneFileName, char *cIncludeFileName,
char *cUnionName, ofstream& outfile, Flags& flags);
void WriteSceneFile(char *cSceneFileName, char *cIncludeFileName, char *cUnionName,
double dHeight, double dRadius, Flags& flags);
void WriteSphere(double dX, double dY, double dZ, double dRad,
ofstream& outfile, long *lGlobalCounter, Flags& flags);
void Usage();
int main(int argc, char *argv[])
{
char cSceneFileName[80] = "DNA.POV";
char cIncludeFileName[80] = "DNA.INC";
char cUnionName[80] = "DNA";
double dRadius; // the radius of the twister (DNA strand)
double dHeight; // the overall Y-length ('height) of the object
double dPartRadius;// the radius of the spheres (and cones) written at each coordinate
double dLastXpos1, dLastZpos1, dLastYpos; // stores the previous values... used
double dLastXpos2, dLastZpos2; // to connect the cones together
long lTotalSteps;// the TOTAL number of coords calc'd
long lStepsPerRevolution;
long lGlobalCounter = 0; // the overall # of objects written to file
long lConnectorCounter = 0; // ready for another connector??
long lConnectXsteps; // connect strands every X steps
// initialize a structure that controls object properties
// default format... write complete DNA strand
Flags flags = {TRUE, TRUE, TRUE, POV};
ShowTitle(); // show the title screen and process comd. line args, if any
if(argc > 1) ProcessArgs(argc, argv, &flags);
/* get some user input and check for validity */
GetAndValidateUserInput(cSceneFileName, cIncludeFileName,
cUnionName, &dHeight,
&dRadius, &dPartRadius,
&lStepsPerRevolution, &lTotalSteps,
&lConnectXsteps, flags);
/* Open file for output */
// try to open a disk file
ofstream outfile(cIncludeFileName, ios::out | ios::showpoint | ios::fixed);
if(! outfile) ErrExit("opening file."); // can't open disk file,exit
WriteFileHeader(cSceneFileName, cIncludeFileName, cUnionName, outfile, flags);
/* caculate each vector and write to file */
for(long lCurrentStep = 0; lCurrentStep < lTotalSteps; ++lCurrentStep)
{
const double dPI = 3.1415926535897932384626;// PI, to calc polar co-ords
double dAngle = dPI * 2 * ( (double)lCurrentStep / (double)lStepsPerRevolution );
double dYpos = dHeight * ( (double)lCurrentStep / (double)lTotalSteps );
double dXpos1 = dRadius * cos(dAngle); // translate polar co-ords to
double dZpos1 = dRadius * sin(dAngle); // rectangular co-ords
double dXpos2 = fabs(dRadius) * cos(dAngle);
double dZpos2 = fabs(dRadius) * sin(dAngle);
if(flags.WriteStrand_1)
WriteSphere(dXpos1, dYpos, dZpos1, dPartRadius,
outfile, &lGlobalCounter, flags);
if(flags.WriteStrand_2)
WriteSphere(dXpos2, dYpos, dZpos2, dPartRadius,
outfile, &lGlobalCounter, flags);
if(lCurrentStep > 0) // ignore this clause the first time around
{
if(flags.WriteStrand_1)
WriteCone(dLastXpos1, dLastYpos, dLastZpos1,
dXpos1, dYpos, dZpos1,
dPartRadius, outfile, &lGlobalCounter,
flags);
if(flags.WriteStrand_2)
WriteCone(dLastXpos2, dLastYpos, dLastZpos2,
dXpos2, dYpos, dZpos2,
dPartRadius, outfile, &lGlobalCounter,
flags);
}
if(flags.WriteConnectors)
{
lConnectorCounter++;
if(lConnectorCounter == lConnectXsteps) /* write a connector? */
{
WriteCone(dXpos1, dYpos, dZpos1,
dXpos2, dYpos, dZpos2,
dPartRadius, outfile, &lGlobalCounter,
flags);
lConnectorCounter = 0; // reset counter to calc the next connector
}
}
dLastXpos1 = dXpos1; // now store x, y etc in Lastx, LastY etc
dLastZpos1 = dZpos1; // so we can use them on the next loop to
dLastXpos2 = dXpos2; // connect the cones and spheres together
dLastZpos2 = dZpos2;
dLastYpos = dYpos;
}
WriteFileEnd(outfile, lGlobalCounter);
cout << lGlobalCounter << " objects written to " << cIncludeFileName << endl;
outfile.close(); // close the output file
// now write a scene file to show the new object
WriteSceneFile(cSceneFileName, cIncludeFileName, cUnionName,
dHeight, dRadius, flags);
// we're outa' here !
return(0);
}
/************************** FUNCTION DEFINITIONS *****************************/
char *AddFileExtension(char *FileName, char *FileExtension)
{
for(int i = 0; i < (int)strlen(FileName); i++)
if(FileName[i] == '.') break;
if( i > MAXDOSPREFIX ) i = MAXDOSPREFIX;
strcpy(&FileName[i], ".");
strcpy(&FileName[i+1], FileExtension);
return FileName;
}
void ErrExit(char *cMessage)
{
cerr << "\a\n\nERROR " << cMessage << "- Exiting \n";
exit(1);
}
void GetAndValidateUserInput(char *cSceneFileName, char *cIncludeFileName,
char *cUnionName, double *dHeight,
double *dRadius, double *dPartRadius,
long *lStepsPerRevolution, long *lTotalSteps,
long *lConnectXsteps, Flags& flags)
{
char cBuffer[256]; // general use (user input) buffer
const int iBUFFSIZE = 255;// constant size for cin.getline()
cout << "\nOutput file name [DNA.INC]:";
cin.getline(cBuffer,iBUFFSIZE);
if(cBuffer[0] == NULL) strcpy(cBuffer, "DNA.INC");
strcpy(cSceneFileName, strcpy(cIncludeFileName, AddFileExtension(_strupr(cBuffer), "INC")));
if(flags.format == POV) AddFileExtension(cSceneFileName, "POV");
else AddFileExtension(cSceneFileName, "PI");
cout << "Union name [DNA]:";
cin.getline(cBuffer,iBUFFSIZE);
if(cBuffer[0] == NULL) strcpy(cBuffer, "DNA");
strcpy(cUnionName, cBuffer);
cout << "Height (Y units) of object [50.0]:";
cin.getline(cBuffer,iBUFFSIZE);
*dHeight = atof(cBuffer);
if( *dHeight <= 0.0 ) *dHeight = 50.0;
cout << "Radius (X-Z) of object [10.0]:";
cin.getline(cBuffer,iBUFFSIZE);
*dRadius = atof(cBuffer);
if( *dRadius <= 0.0 ) *dRadius = 10.0;
*dRadius -= (*dRadius * 2); // to make the result a negative
cout << "Radius of individual objects [0.5]:";
cin.getline(cBuffer,iBUFFSIZE);
*dPartRadius = atof(cBuffer);
if(*dPartRadius <= 0.0 ) *dPartRadius = 0.5;
cout << "Steps per revolution [30]:";
cin.getline(cBuffer,iBUFFSIZE);
*lStepsPerRevolution = atoi(cBuffer);
if(*lStepsPerRevolution <= 0 ) *lStepsPerRevolution = 30;
cout << "Connect strands every X steps [3]:";
cin.getline(cBuffer,iBUFFSIZE);
*lConnectXsteps = atoi(cBuffer);
if(*lConnectXsteps <= 0 ) *lConnectXsteps = 3;
cout << "Number of revolutions [1]:";
cin.getline(cBuffer,iBUFFSIZE);
*lTotalSteps = atoi(cBuffer);
if(*lTotalSteps <=0) *lTotalSteps = 1;
*lTotalSteps = (*lTotalSteps * *lStepsPerRevolution);
// That * operator sure gets around!
}
void ProcessArgs(int argc, char *argv[], Flags *flags)
{
for(int i = 1; i < argc; i++)
{
if(argv[i][0] == '-' || argv[i][0] == '/')
switch(toupper(argv[i][1]))
{
//case 'E': extended = TRUE; break;
case 'O': switch(toupper(argv[i][2]))
{
case 'P' : flags->format = POV; break; // default
case 'L' : flags->format = POLY; break;
default : Usage(); exit(1);
}
break;
//case 'D': display = TRUE;
//v_mode = atoi(&s[1]); break; //def=no display
//case 'T': write_texture = FALSE; break; //def=TRUE, write textures
case 'F': switch(argv[i][2])
{
case '0' : break; // default; does not modify flags structure
case '1' : flags->WriteConnectors = FALSE; break;
case '2' : flags->WriteStrand_1 = FALSE;
flags->WriteStrand_2 = FALSE; break;
case '3' : flags->WriteStrand_2 = FALSE; break;
case '4' : flags->WriteConnectors = FALSE;
flags->WriteStrand_2 = FALSE; break;
default : Usage(); exit(1);
}
break;
case '?': Usage(); exit(0);
case 'H': Usage(); exit(0);
default : Usage(); exit(1);
}
else
{
Usage();
exit(1);
}
}
}
void ShowTitle()
{
cout << "\nDNA "<< cVERSION << ", Copyright (c) 1994 Rob Bryerton\n"
<< "Creates a data file of a twisted ladder-shaped object (like a DNA strand)\n"
<< "for the POV-Ray v2.x and PolyRay v1.6 raytracers.\n";
}
void Usage()
{
cerr << endl
<< "Usage: DNA [options]\n"
// << "Options: -d# enables 2D (xz) display of object... # is the graphics mode.\n"
// << " 0=no display (default) \n"
// << " 1=640x480 \n"
// << " 2=800x600 \n"
// << " 3=1024x768 \n"
<< "Options: -f# Where # is the option to set the following flags:\n"
<< " 0= Write complete object. (default) \n"
<< " 1= Do NOT write connectors.\n"
<< " 2= Write horizontal connectors ONLY.\n"
<< " 3= Write only one spiral.\n"
<< " 4= Write only one spiral but do NOT write connectors.\n"
<< " -o Output format. Choices are:\n"
<< " P=POV-Ray v2.x... (default) -oP\n"
<< " L=PolyRay v1.6... -oL\n"
<< "\nType DNA with no parameters to accept the default options.\n";
}
void WriteCone(double dLastX, double dLastY, double dLastZ,
double dX, double dY, double dZ,
double dRad, ofstream& outfile, long *lGlobalCounter,
Flags& flags)
{
switch(flags.format)
{
case POV : outfile << "\n cone{ < " <<dLastX<< ", " << dLastY << ", " <<dLastZ<< " >, " << dRad
<< ", < " <<dX<< ", " << dY << ", " <<dZ<< " >, " << dRad << " }";
break;
case POLY : char cToken[2] = " ";
if(*lGlobalCounter > 0) strcpy(cToken, "+");
outfile << "\n " << cToken << "object { cone < " <<dLastX<< ", " << dLastY << ", " <<dLastZ<< " >, " << dRad
<< ", < " <<dX<< ", " << dY << ", " <<dZ<< " >, " << dRad << " }";
}
++*lGlobalCounter; //increment counter (why won't postfix notation work ????)
}
void WriteFileEnd(ofstream& outfile, long lGlobalCounter)
{
outfile << "\n}\n"
<< "\n// " << lGlobalCounter << " objects written to this file.\n";
}
void WriteFileHeader(char *cSceneFileName, char *cIncludeFileName, char *cUnionName, ofstream& outfile, Flags& flags)
{
cout<< "\nCreating data file " << cIncludeFileName << endl;
outfile << "// This data file created by DNA.EXE " << cVERSION << " for the POV-Ray v2.x and \n"
<< "// PolyRay v1.6 raytracers.\n"
<< "// Scene File: " << cSceneFileName << " Include File: " << cIncludeFileName << " Union Name: " << cUnionName << endl;
switch(flags.format)
{
case POV : outfile << "\n#declare " << cUnionName << " =\n"
<< "union {";
break;
case POLY : outfile << "\ndefine " << cUnionName << endl
<< "object {";
break;
}
}
void WriteSceneFile(char *cSceneFileName, char *cIncludeFileName, char *cUnionName,
double dHeight, double dRadius, Flags& flags)
{
struct Vector{ double x,y,z;};
Vector CamLocation, CamLookAt, LightLocation;
/* Open file for output */
ofstream outfile(cSceneFileName, ios::out | ios::showpoint | ios::fixed);
if(! outfile) ErrExit("opening file."); // if we can't open a disk file, exit
cout<< "Creating scene file " << cSceneFileName << endl;
// calculate camera and light vectors based on object size
CamLocation.x = 0;
CamLocation.y = dHeight * 0.5;
CamLocation.z = dHeight - (dHeight * 2.2);
CamLookAt.x = 0;
CamLookAt.y = dHeight * 0.5;
CamLookAt.z = 0;
LightLocation.x = fabs(dRadius);
LightLocation.y = dHeight * 0.75;
LightLocation.z = dHeight - (dHeight * 2.0);
outfile << "// This data file created by DNA.EXE " << cVERSION << " for the POV-Ray v2.x and \n"
<< "// PolyRay v1.6 raytracers.\n"
<< "// Scene File: " << cSceneFileName << " Include File: " << cIncludeFileName << " Union Name: " << cUnionName << endl;
switch(flags.format)
{
case POV : outfile << "#include \"colors.inc\"\n"
<< "#include \"textures.inc\"\n\n";
outfile << "camera {\n"
<< " location < " << CamLocation.x << ", " << CamLocation.y << ", " << CamLocation.z << " >\n"
<< " look_at < " << CamLookAt.x << ", " << CamLookAt.y << ", " << CamLookAt.z << " >\n"
<< "}\n\n";
outfile << "light_source { < " << LightLocation.x << ", " << LightLocation.y << ", " << LightLocation.z << " > color White }\n"
<< "\n#declare " << cUnionName << "_Texture ="
<< "\ntexture { Y_Gradient finish { ambient 0.3 } scale<1," << dHeight << ",1> }\n\n";
outfile << "#include \"" << cIncludeFileName << "\"\n\n"
<< "object{"
<< "\n " << cUnionName
<< "\n texture{ " << cUnionName << "_Texture rotate < 0,0,25 > }"
<< "\n}\n";
break;
case POLY : outfile << "include \"..\\colors.inc\"\n"
<< "include \"..\\texture.inc\"\n\n";
outfile << "viewpoint {\n"
<< " from < " << CamLocation.x << ", " << CamLocation.y << ", " << CamLocation.z << " >\n"
<< " at < " << CamLookAt.x << ", " << CamLookAt.y << ", " << CamLookAt.z << " >\n"
<< " angle 53\n"
<< " aspect 4/3\n"
<< " resolution 320, 240\n"
<< "}\n\n";
outfile << "light < " << LightLocation.x << ", " << LightLocation.y << ", " << LightLocation.z << " >\n"
<< "\ndefine " << cUnionName << "_Texture"
<< "\n xz_wheel_texture { rotate < 0,0,15 > }\n\n";
outfile << "include \"" << cIncludeFileName << "\""
<< "\n" << cUnionName << " { " << cUnionName << "_Texture }";
}
}
void WriteSphere(double dX, double dY, double dZ, double dRad,
ofstream& outfile, long *lGlobalCounter, Flags& flags)
{
switch(flags.format)
{
case POV : outfile << "\n sphere{ < " << dX << ", " << dY << ", " << dZ << " > " << dRad << " }";
break;
case POLY : char cToken[2] = " ";
if(*lGlobalCounter > 0) strcpy(cToken, "+");
outfile << "\n " << cToken << "object { sphere < " << dX << ", " << dY << ", " << dZ << " >, " << dRad << " }";
}
++*lGlobalCounter;//increment counter (why won't postfix notation work ????)
}