home *** CD-ROM | disk | FTP | other *** search
Wrap
/* name: raylab.c Main program ------------ */ #include <stdio.h> #include <stdlib.h> #include <time.h> #include "defs.h" #include "getworld.h" #include "tga.h" /* Global variables (most mentioned in extern.h) */ long PicWidth, PicHeight, RecDepth, NumObjects, NumLights; CAMERA Camera; COLOR BackgroundColor; long AntiAliasingRec; double AntiAliasingThreshold, AntiAliasingJitter; long ReqDisplayType, GotDisplayType; OBJECT *ObjectArray[maxobjects]; LIGHT *LightArray[maxlights]; unsigned char pixlearray[parraysize]; long picturerendering; long PlaneIntersectionAttempts,PlaneIntersections; long SphereIntersectionAttempts,SphereIntersections; long EllipsoidIntersectionAttempts,EllipsoidIntersections; long TriangleIntersectionAttempts,TriangleIntersections; long BoxIntersectionAttempts,BoxIntersections; long DiscIntersectionAttempts,DiscIntersections; long CylinderIntersectionAttempts,CylinderIntersections; long ShadowAttempts,ShadowHits,ReflectedRays; FILE *inputfile,*outputfile; long outfileopen,objectalloc,aalinbufalloc,displayopen; /* Declaration of entries in the anti-aliasing table(s) */ typedef struct AAEntry_Struct AAENTRY; struct AAEntry_Struct { COLOR Color; unsigned char Done; }; AAENTRY aatable[aamaxlevel][aamaxlevel]; /* 9x9 matrix <=> max rec.-level: 4 */ AAENTRY *aalinebuffer; /* Line-buffer for major speedup during antialiasing */ /********************************************************************** * * main() * **********************************************************************/ void main(int argc, char *argv[]) { time_t starttrace, endtrace; int spenttime, spent_h, spent_m, spent_s; outfileopen=objectalloc=aalinbufalloc=displayopen=picturerendering=0; fprintf(stderr,"RayLab v1.0 (c)1995-1996 by Marcus Geelnard\n"); fprintf(stderr,"-------------------------------------------\n"); if(argc<3) { fprintf(stderr,"\n*** Not enough parameters!\n"); fprintf(stderr,"Usage: %s <input file> <output file>\n",argv[0]); exit(0); } if(CreateWorld(argv[1])!=0) { /* Do some world-declarations */ exit(1); } objectalloc=1; if((outputfile=fopen(argv[2],"wb"))==NULL) { fprintf(stderr,"\n*** Could not open output file!\n"); cleanup(); exit(1); } else outfileopen=1; if(AntiAliasingRec>=1L) { if((aalinebuffer=(AAENTRY *)calloc((size_t)(PicWidth*aamaxlevel),sizeof(AAENTRY)))==NULL) { fprintf(stderr,"\n*** Could not allocate memory for antialiasing line buffer!\n"); cleanup(); exit(1); } else { fprintf(stderr,"(Allocated %ld KB of memory for antialiasing line buffer)\n\n",(long)(PicWidth*aamaxlevel*(long)sizeof(AAENTRY))/(long)1024); aalinbufalloc=1; } } fprintf(stderr,"Image size: %ldx%ld\n",PicWidth,PicHeight); WriteTgaHeader(outputfile,PicWidth,PicHeight); fprintf(stderr,"\nLights: %ld\n",NumLights); fprintf(stderr,"Primitives: %ld\n\n",NumObjects); PlaneIntersectionAttempts = PlaneIntersections = 0; SphereIntersectionAttempts = SphereIntersections = 0; EllipsoidIntersectionAttempts = EllipsoidIntersections = 0; DiscIntersectionAttempts = DiscIntersections = 0; CylinderIntersectionAttempts = CylinderIntersections = 0; ShadowAttempts=ShadowHits = 0; ReflectedRays = 0; GotDisplayType = OpenDisplay(ReqDisplayType); /* Open potential display */ displayopen=1; time(&starttrace); picturerendering=1; ScanWorld(); /* Make the actual ray-tracing */ picturerendering=0; time(&endtrace); spenttime=(int)difftime(endtrace,starttrace); spent_h=spenttime/(60*60); spent_m=(spenttime%(60*60))/60; spent_s=spenttime%60; fprintf(stderr,"\nDone!\n\n"); fprintf(stderr,"Shape Tests Hits\n"); fprintf(stderr,"-----------------------------------------------\n"); if(PlaneIntersectionAttempts>0) fprintf(stderr,"Plane %10ld %10ld (%3.2lf%%)\n",PlaneIntersectionAttempts,PlaneIntersections,((double)PlaneIntersections/(double)PlaneIntersectionAttempts)*100.0); if(SphereIntersectionAttempts>0) fprintf(stderr,"Sphere %10ld %10ld (%3.2lf%%)\n",SphereIntersectionAttempts,SphereIntersections,((double)SphereIntersections/(double)SphereIntersectionAttempts)*100.0); if(EllipsoidIntersectionAttempts>0) fprintf(stderr,"Ellipsoid %10ld %10ld (%3.2lf%%)\n",EllipsoidIntersectionAttempts,EllipsoidIntersections,((double)EllipsoidIntersections/(double)EllipsoidIntersectionAttempts)*100.0); if(TriangleIntersectionAttempts>0) fprintf(stderr,"Triangle %10ld %10ld (%3.2lf%%)\n",TriangleIntersectionAttempts,TriangleIntersections,((double)TriangleIntersections/(double)TriangleIntersectionAttempts)*100.0); if(BoxIntersectionAttempts>0) fprintf(stderr,"Box %10ld %10ld (%3.2lf%%)\n",BoxIntersectionAttempts,BoxIntersections,((double)BoxIntersections/(double)BoxIntersectionAttempts)*100.0); if(DiscIntersectionAttempts>0) fprintf(stderr,"Disc %10ld %10ld (%3.2lf%%)\n",DiscIntersectionAttempts,DiscIntersections,((double)DiscIntersections/(double)DiscIntersectionAttempts)*100.0); if(CylinderIntersectionAttempts>0) fprintf(stderr,"Cylinder %10ld %10ld (%3.2lf%%)\n",CylinderIntersectionAttempts,CylinderIntersections,((double)CylinderIntersections/(double)CylinderIntersectionAttempts)*100.0); fprintf(stderr,"\nShadow rays: tested: %ld blocked: %ld (%2.2lf%%)\n",ShadowAttempts,ShadowHits,100.0*(double)ShadowHits/(double)ShadowAttempts); fprintf(stderr,"Reflected rays: %ld\n",ReflectedRays); fprintf(stderr,"\nTime: %dh %dmin %ds\n\n",spent_h,spent_m,spent_s); /* if(AntiAliasingRec>=1L) { free(aalinebuffer); } FreeAllObjectMemory(); fclose(outputfile); */ cleanup(); exit(0); } /********************************************************************** * * cleanup() cleans up the system, closes down things etc... * **********************************************************************/ void cleanup(void) { if(outfileopen==1) { fclose(outputfile); outfileopen=0; } if(aalinbufalloc==1) { free(aalinebuffer); aalinbufalloc=0; } if(displayopen==1) { CloseDisplay(); /* Close display (if any was opened) */ displayopen=0; } if(objectalloc==1) { FreeAllObjectMemory(); /* Free memory that was allocated for objects */ objectalloc=0; } } /********************************************************************** * * ScanWorld() is the main tracing routine * **********************************************************************/ void ScanWorld(void) { long column,line; COLOR ReturnColor; LINE ScanLine; POINT CameraLocation,ScreenLocation,OldScreenLocation; VECTOR vtemp,vxstep,vystep; int i,j; unsigned char RGBColor[3]; AAENTRY *currentlinebufentry,*currentlinebufentry_tmp; CreatePoint(&CameraLocation,Camera.Location.x,Camera.Location.y,Camera.Location.z); CopyPoint(&ScreenLocation,&CameraLocation); ScaleVector(&vtemp,Camera.Aspect.z,&(Camera.Direction)); ScreenLocation.x+=vtemp.x; ScreenLocation.y+=vtemp.y; ScreenLocation.z+=vtemp.z; ScaleVector(&vtemp,(Camera.Aspect.y)/(double)2,&(Camera.Up)); ScreenLocation.x+=vtemp.x; ScreenLocation.y+=vtemp.y; ScreenLocation.z+=vtemp.z; ScaleVector(&vtemp,(Camera.Aspect.x)/(double)2,&(Camera.Right)); ScreenLocation.x-=vtemp.x; ScreenLocation.y-=vtemp.y; ScreenLocation.z-=vtemp.z; ScaleVector(&vxstep,(Camera.Aspect.x)/(double)PicWidth,&(Camera.Right)); ScaleVector(&vystep,-(Camera.Aspect.y)/(double)PicHeight,&(Camera.Up)); if(AntiAliasingRec>=1L) { currentlinebufentry=aalinebuffer; for(column=0;column<PicWidth;column++) { /* Clear antialiasing line-buffer */ for(i=0;i<aamaxlevel;i++) { currentlinebufentry->Done=0; currentlinebufentry++; } } } for(line=1;line<=PicHeight;line++) { if(AntiAliasingRec>=1L) { for(i=0;i<aamaxlevel;i++) { for(j=0;j<aamaxlevel;j++) { aatable[i][j].Done=0; /* Clear whole aatable */ } } currentlinebufentry=aalinebuffer; } CopyPoint(&OldScreenLocation,&ScreenLocation); fprintf(stderr,"\rRendering line %ld of %ld (%3.1lf%%)",line,PicHeight,100.0*(double)line/(double)PicHeight); for(column=1;column<=PicWidth;column++) { if(AntiAliasingRec<1L) { MakeLine(&ScanLine,&CameraLocation,&ScreenLocation); (void) TraceRay(&ReturnColor,&ScanLine,RecDepth); } else { for(j=0;j<aamaxlevel;j++) { /* Copy right column of last scan to left column of new scan! */ if((aatable[0][j].Done=aatable[aamaxlevel-1][j].Done)!=0) CopyColor(&aatable[0][j].Color,&aatable[aamaxlevel-1][j].Color); } currentlinebufentry_tmp=currentlinebufentry; for(i=0;i<aamaxlevel;i++) { /* Copy top row from previous line */ if((aatable[i][0].Done=currentlinebufentry->Done)!=0) CopyColor(&aatable[i][0].Color,¤tlinebufentry->Color); currentlinebufentry++; } for(i=1;i<aamaxlevel;i++) { for(j=1;j<aamaxlevel;j++) { aatable[i][j].Done=0; /* Clear rest of aatable */ } } ScanOnePoint(&ReturnColor,&CameraLocation,&ScreenLocation,&vxstep,&vystep,0,aamaxlevel-1,0,aamaxlevel-1,AntiAliasingRec); currentlinebufentry=currentlinebufentry_tmp; for(i=0;i<aamaxlevel;i++) { /* Save bottom row for next line */ if((currentlinebufentry->Done=aatable[i][aamaxlevel-1].Done)!=0) CopyColor(¤tlinebufentry->Color,&aatable[i][aamaxlevel-1].Color); currentlinebufentry++; } } RGBColor[0] = (unsigned char)(255*ReturnColor.r); RGBColor[1] = (unsigned char)(255*ReturnColor.g); RGBColor[2] = (unsigned char)(255*ReturnColor.b); pixlearray[(column-1)*3+0] = RGBColor[0]; pixlearray[(column-1)*3+1] = RGBColor[1]; pixlearray[(column-1)*3+2] = RGBColor[2]; if(GotDisplayType!=0L) DisplayPlot((int)(column-1),(int)(line-1), RGBColor); ScreenLocation.x+=vxstep.x; ScreenLocation.y+=vxstep.y; ScreenLocation.z+=vxstep.z; } WriteTgaLine(outputfile,PicWidth); CopyPoint(&ScreenLocation,&OldScreenLocation); ScreenLocation.x+=vystep.x; ScreenLocation.y+=vystep.y; ScreenLocation.z+=vystep.z; } } void ScanOnePoint(COLOR *Color, POINT *CameraLocation, POINT *ScreenLocation, VECTOR *dx, VECTOR *dy, int ColumnFirst, int ColumnLast, int RowFirst, int RowLast, long AARec) { LINE ScanLine; POINT ScreenLocation2; VECTOR dx2,dy2; COLOR ReColor[4],MinColor,MaxColor; double ColorDiff; int i, DeltaColumn, DeltaRow; if(aatable[ColumnFirst][RowFirst].Done==0) { MakeLine(&ScanLine,CameraLocation,ScreenLocation); (void) TraceRay(&ReColor[0],&ScanLine,RecDepth); aatable[ColumnFirst][RowFirst].Done=1; CopyColor(&aatable[ColumnFirst][RowFirst].Color,&ReColor[0]); } else { CopyColor(&ReColor[0],&aatable[ColumnFirst][RowFirst].Color); } AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)ScreenLocation,dx); if(aatable[ColumnLast][RowFirst].Done==0) { MakeLine(&ScanLine,CameraLocation,&ScreenLocation2); (void) TraceRay(&ReColor[1],&ScanLine,RecDepth); aatable[ColumnLast][RowFirst].Done=1; CopyColor(&aatable[ColumnLast][RowFirst].Color,&ReColor[1]); } else { CopyColor(&ReColor[1],&aatable[ColumnLast][RowFirst].Color); } AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,dy); if(aatable[ColumnLast][RowLast].Done==0) { MakeLine(&ScanLine,CameraLocation,&ScreenLocation2); (void) TraceRay(&ReColor[2],&ScanLine,RecDepth); aatable[ColumnLast][RowLast].Done=1; CopyColor(&aatable[ColumnLast][RowLast].Color,&ReColor[2]); } else { CopyColor(&ReColor[2],&aatable[ColumnLast][RowLast].Color); } SubVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,dx); if(aatable[ColumnFirst][RowLast].Done==0) { MakeLine(&ScanLine,CameraLocation,&ScreenLocation2); (void) TraceRay(&ReColor[3],&ScanLine,RecDepth); aatable[ColumnFirst][RowLast].Done=1; CopyColor(&aatable[ColumnFirst][RowLast].Color,&ReColor[3]); } else { CopyColor(&ReColor[3],&aatable[ColumnFirst][RowLast].Color); } if(AARec>1L) { CopyColor(&MinColor,&ReColor[0]); /* Determine min/max values for r,g,b */ CopyColor(&MaxColor,&ReColor[0]); for(i=1;i<4;i++) { if(ReColor[i].r<MinColor.r) MinColor.r=ReColor[i].r; else if(ReColor[i].r>MaxColor.r) MaxColor.r=ReColor[i].r; if(ReColor[i].g<MinColor.g) MinColor.g=ReColor[i].g; else if(ReColor[i].g>MaxColor.g) MaxColor.g=ReColor[i].g; if(ReColor[i].b<MinColor.b) MinColor.b=ReColor[i].b; else if(ReColor[i].b>MaxColor.b) MaxColor.b=ReColor[i].b; } ColorDiff=MaxColor.r-MinColor.r+MaxColor.g-MinColor.g+MaxColor.b-MinColor.b; if(ColorDiff>AntiAliasingThreshold) { ScaleVector(&dx2,0.5,dx); ScaleVector(&dy2,0.5,dy); DeltaColumn=(ColumnLast-ColumnFirst)>>1; DeltaRow=(RowLast-RowFirst)>>1; ScanOnePoint(&ReColor[0],CameraLocation,ScreenLocation,&dx2,&dy2,ColumnFirst,ColumnFirst+DeltaColumn,RowFirst,RowFirst+DeltaRow,AARec-1); AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)ScreenLocation,&dx2); ScanOnePoint(&ReColor[1],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst+DeltaColumn,ColumnLast,RowFirst,RowFirst+DeltaRow,AARec-1); AddVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,&dy2); ScanOnePoint(&ReColor[2],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst+DeltaColumn,ColumnLast,RowFirst+DeltaRow,RowLast,AARec-1); SubVector((VECTOR *)&ScreenLocation2,(VECTOR *)&ScreenLocation2,&dx2); ScanOnePoint(&ReColor[3],CameraLocation,&ScreenLocation2,&dx2,&dy2,ColumnFirst,ColumnFirst+DeltaColumn,RowFirst+DeltaRow,RowLast,AARec-1); } } CopyColor(Color,&ReColor[0]); for(i=1;i<4;i++) { Color->r+=ReColor[i].r; Color->g+=ReColor[i].g; Color->b+=ReColor[i].b; } Color->r*=0.25; Color->g*=0.25; Color->b*=0.25; } /********************************************************************** * * TraceRay() will trace a given ray and return a resulting color * **********************************************************************/ long TraceRay(COLOR *Color, LINE *RayLine, long RecurseLevel) { double t,tnew,angle,dintense,pintense; LINE LightLine,ReflectLine; POINT IPoint; VECTOR surfnormal,reflectvect; COLOR surfcolor,ReflectedColor; long i,ObjNum=-1; /* Find closest hit */ if(RecurseLevel>0) { t=-1; for(i=0;i<NumObjects;i++) { tnew=Intersect_Object(RayLine, ObjectArray[i]); if((tnew>EPSILON)&&((tnew<t)||(t<=EPSILON))) { ObjNum=i; t=tnew; } } /* Calculate color in intersected point */ if(ObjNum>=0) { IPoint.x=RayLine->Origin.x+t*RayLine->Direction.x; IPoint.y=RayLine->Origin.y+t*RayLine->Direction.y; IPoint.z=RayLine->Origin.z+t*RayLine->Direction.z; if(fabs(IPoint.x+IPoint.y+IPoint.z)>maxsumcoord) { ObjNum=-1; Color->r=BackgroundColor.r; Color->g=BackgroundColor.g; Color->b=BackgroundColor.b; } else { GetSurfaceColor(&surfcolor, &ObjectArray[ObjNum]->Texture, &IPoint); GetSurfaceNormal(&surfnormal, &IPoint, ObjectArray[ObjNum]); angle=VectorsAngle(&surfnormal,&(RayLine->Direction)); if(angle<PID2) NegVector(&surfnormal,&surfnormal); /* So that the surface-normal always points towards us */ ReflectVector(&reflectvect,&(RayLine->Direction),&surfnormal); Color->r=Color->g=Color->b=0.0; for(i=0;i<NumLights;i++) { dintense=0.0; pintense=0.0; MakeLine(&LightLine,&IPoint,&(LightArray[i]->Location)); if(TestShadowRay(&LightLine,ObjNum)<0) { angle=VectorsAngle(&surfnormal,&(LightLine.Direction)); if(angle<PID2) { dintense=ObjectArray[ObjNum]->Texture.Diffuse*cos(angle); angle=VectorsAngle(&reflectvect,&(LightLine.Direction)); if(angle<PID2) { pintense=ObjectArray[ObjNum]->Texture.Phong*pow(cos(angle),ObjectArray[ObjNum]->Texture.PhongSize); } } } dintense = (dintense > 1.0 ? 1.0 : dintense); pintense = (pintense > 1.0 ? 1.0 : pintense); Color->r+=((dintense*surfcolor.r+pintense)*LightArray[i]->Color.r); Color->g+=((dintense*surfcolor.g+pintense)*LightArray[i]->Color.g); Color->b+=((dintense*surfcolor.b+pintense)*LightArray[i]->Color.b); } Color->r+=surfcolor.r*ObjectArray[ObjNum]->Texture.Ambient; Color->g+=surfcolor.g*ObjectArray[ObjNum]->Texture.Ambient; Color->b+=surfcolor.b*ObjectArray[ObjNum]->Texture.Ambient; if((ObjectArray[ObjNum]->Texture.Reflect.r+ObjectArray[ObjNum]->Texture.Reflect.g+ObjectArray[ObjNum]->Texture.Reflect.b)>EPSILON) { ReflectedRays++; CopyVector(&(ReflectLine.Direction),&reflectvect); CopyPoint(&(ReflectLine.Origin),&IPoint); TraceRay(&ReflectedColor, &ReflectLine, RecurseLevel-1L); Color->r+=(ObjectArray[ObjNum]->Texture.Reflect.r*ReflectedColor.r); Color->g+=(ObjectArray[ObjNum]->Texture.Reflect.g*ReflectedColor.g); Color->b+=(ObjectArray[ObjNum]->Texture.Reflect.b*ReflectedColor.b); } Color->r = (Color->r > 1.0 ? 1.0 : Color->r); Color->g = (Color->g > 1.0 ? 1.0 : Color->g); Color->b = (Color->b > 1.0 ? 1.0 : Color->b); } } else { Color->r=BackgroundColor.r; Color->g=BackgroundColor.g; Color->b=BackgroundColor.b; } } else { Color->r=0.0; /* Return no color (= color black) if recursion- */ Color->g=0.0; /* level <= 0 */ Color->b=0.0; } return(ObjNum); } /********************************************************************** * * TestShadowRay() will trace a given ray and look for object-hits * **********************************************************************/ long TestShadowRay(LINE *RayLine, long CurrentObject) { long i,hit=-1; double t,told=-1; ShadowAttempts++; for(i=0;i<NumObjects;i++) { if(i!=CurrentObject) { t=Intersect_Object(RayLine, ObjectArray[i]); if((t>EPSILON)&&((t<told)||(told<=EPSILON))) { hit=i; told=t; } } } t=told; if(t>1.0) hit=-1; /* Object was beyond light */ if(hit>=0) ShadowHits++; return(hit); }