/* *********************************************************************** * * * 3-D Modeling and Shading Routines for * * Objects Constructed of Facets * * * * Program by * * Christopher D. Watkins * * * * 'C' conversion by * * Larry Sharp * * * *********************************************************************** */ #include "stdio.h" #include "dos.h" #include "conio.h" #include "math.h" #include "string.h" #include "alloc.h" #include "math.inc" #include "graph.inc" #include "model.inc" /* *********************************************************************** * * * Toggle Switches * * * *********************************************************************** DoPreview - display verticies DoWireFrame - display wireframe DoSolidModel - display solid model VertSort - vertically sort objects */ Boolean Preview; Boolean WireFrame; Boolean SolidModel; Boolean VerticalSort; void DoPreview(Boolean State) { Preview=State; } void DoWireFrame(Boolean State) { WireFrame=State; } void DoSolidModel(Boolean State) { SolidModel=State; } void VertSort(Boolean Sort) { VerticalSort=Sort; } /* *********************************************************************** * * * Affine Transformations * * * *********************************************************************** AffineTransformation - translate, rotate and scale verticies for viewing InvAffineTransformation - return verticies to original value */ void DoTransform(Matx4x4 XForm) { TDA temp, temp2; for(VertexNum=1; VertexNum<=LastVertex; VertexNum++) { VecScalMultI(InvScaleData, Vertex[VertexNum], temp2); Transform(temp2, XForm, temp); VecScalMultInt(ScaleImage, temp, Vertex[VertexNum]); } } void DoInvTransform(Matx4x4 XForm) { TDA temp, temp2; for(VertexNum=1; VertexNum<=LastVertex; VertexNum++) { VecScalMultI(InvScaleImage, Vertex[VertexNum], temp2); Transform(temp2, XForm, temp); VecScalMultInt(ScaleData, temp, Vertex[VertexNum]); } } void AffineTransformation(float Tx, float Ty, float Tz, float Sx, float Sy, float Sz, float Rx, float Ry, float Rz) { Matx4x4 XForm; PrepareMatrix(Tx, Ty, Tz, Sx, Sy, Sz, Rx, Ry, Rz, XForm); DoTransform(XForm); } void InvAffineTransformation(float Tx, float Ty, float Tz, float Sx, float Sy, float Sz, float Rx, float Ry, float Rz) { Matx4x4 XForm; PrepareInvMatrix(-Tx, -Ty, -Tz, 1.0/Sx, 1.0/Sy, 1.0/Sz, -Rx, -Ry, -Rz, XForm); DoInvTransform(XForm); } /* *********************************************************************** * * * Viewer and Light Source Vectors * * * *********************************************************************** GetViewVector - unit vector in direction of viewer InitLightDirection - get direction for light source GetLightVector - unit vector in direction of light source */ #define ViewPhi 270 #define ViewTheta 90 TDA View; void GetViewVector() { float Phi, Theta; float x, y, z; Phi=Radians((float)ViewPhi-Angl); Theta=Radians((float)ViewTheta-Tilt); x=sin(Theta)*cos(Phi); y=sin(Theta)*sin(Phi); z=cos(Theta); Vec(x, y, z, View); } float LightPhi; float LightTheta; void InitLightDirection(int LgtPhi, int LgtTheta) { printf("Light Direction is %d around the z-Axis and\n", LgtPhi); printf(" %d off the z-Axis\n", LgtTheta); LightPhi=(float)LgtPhi; LightTheta=(float)LgtTheta; } TDA Light; void GetLightVector() { float Phi, Theta; float x, y, z; Phi=Radians(LightPhi); Theta=Radians(LightTheta); x=sin(Theta)*cos(Phi); y=sin(Theta)*sin(Phi); z=cos(Theta); Vec(x, y, z, Light); } /* *********************************************************************** * * * Surface Normal Vector * * * *********************************************************************** GetSurfaceNormalVector - unit vector normal to surface */ TDA SrfNorm; void GetSurfaceNormalVector(VoxelArray Face3d) { float Length, Length2; TDA Dir1; TDA Dir2; TDA Temp1; TDA Temp2; TDA Temp3; TDA SrfNorm2; VecCopy(Face3d[2], Temp1); VecCopy(Face3d[1], Temp2); VecCopy(Face3d[LastVertexNumInFacet], Temp3); VecSub(Temp1, Temp2, Dir1); VecSub(Temp3, Temp2, Dir2); VecCross(Dir1, Dir2, SrfNorm); Length=VecLen(SrfNorm); VecCopy(Face3d[LastVertexNumInFacet], Temp1); VecCopy(Face3d[LastVertexNumInFacet-1], Temp2); VecCopy(Face3d[LastVertexNumInFacet-2], Temp3); VecSub(Temp1, Temp2, Dir1); VecSub(Temp3, Temp2, Dir2); VecCross(Dir1, Dir2, SrfNorm2); Length2=VecLen(SrfNorm2); if(Length==0.0) VecScalMult(1.0/Length2, SrfNorm2, SrfNorm); else { if(Length2==0.0) VecScalMult(1.0/Length, SrfNorm, SrfNorm); else { VecScalMult(1.0/Length, SrfNorm, SrfNorm); VecScalMult(1.0/Length2, SrfNorm2, SrfNorm2); VecAdd(SrfNorm, SrfNorm2, SrfNorm); VecScalMult(0.5, SrfNorm, SrfNorm); } } } /* *********************************************************************** * * * The Illumination Model * * * *********************************************************************** Intensity - calculated intensity of point on screen */ Byte Intensity() { float Ambient=0.30; float DifRfl=0.50; float SpcRfl=0.20; float Gloss=5.0; float CosTheta; float CosAlpha; TDA Ref; float TwoCosTheta; TDA temp; CosTheta=VecDot(SrfNorm, Light); if(CosTheta<=0.0) return(Round(MaxInten*Ambient)); else { TwoCosTheta=2.0*CosTheta; VecScalMult(TwoCosTheta, SrfNorm, temp); VecNormalize(temp); VecSub(temp, Light, Ref); VecNormalize(Ref); CosAlpha=VecDot(View, Ref); return(Round(MaxInten*(Ambient+DifRfl*CosTheta+SpcRfl*pow(CosAlpha, Gloss)))); } } /* ************************************************************************ * * * Facet Visibility Test * * * ************************************************************************ Visible - determine if facet is visible */ Boolean Reflect; Boolean MirrorX; Boolean MirrorY; Boolean MirrorZ; Boolean Visible(VoxelArray Face3d) { float CosBeta; float nvx, nvy, nvz; TDA temp, v; Boolean vt; GetSurfaceNormalVector(Face3d); VecCopy(View, v); if((!(Preview || WireFrame)) && Reflect && MirrorZ) v[2]=-v[2]; VecElemMult(1.0, SrfNorm, v, temp); UnVec(temp, &nvx, &nvy, &nvz); vt=true; CosBeta=nvx+nvy+nvz; if((MirrorZ || (!(MirrorX || MirrorY))) && (CosBeta<0.0)) vt=false; else { CosBeta=-nvx+nvy+nvz; if(MirrorX && (CosBeta<0.0)) vt=false; else { CosBeta=nvx-nvy+nvz; if(MirrorY && (CosBeta<0.0)) vt=false; } } return(vt); } /* *********************************************************************** * * * Reflection Screen Buffer * * * *********************************************************************** Stores the reflective states of all screen pixel locations InitReflectionBuffer - clear reflective states Reflected - indicates whether or not reflective MakeReflected - makes a screen location reflective */ #define XBytes 39 Byte Refl[XBytes+1][MaxY+1]; void InitReflectionBuffer() { int i, j; for(i=0; i<=XBytes; i++) { for(j=0; j<=MaxY; j++) Refl[i][j]=0; } } Boolean Reflected(int x, int y) { Byte tmp; tmp=Refl[x/8][y]&(128>>(x%8)); if(tmp==0) return(false); else return(true); } void MakeReflected(int x, int y) { Refl[x/8][y]=Refl[x/8][y]|(128>>(x%8)); } #include "addobjs.inc" /* *********************************************************************** * * * Polygonal Facet Fill Routine * * * *********************************************************************** GetProjectedCoords - 3D point mapped onto 2D screen PutFacet2 - fills a facet */ void GetProjectedCoords(VoxelArray Face3d, PixelArray Face2d) { float xt, yt, zt; for(VertexNumInFacet=1; VertexNumInFacet<=LastVertexNumInFacet; VertexNumInFacet++) { UnVec(Face3d[VertexNumInFacet], &xt, &yt, &zt); if(Reflect) { if(MirrorZ) { zt=-zt; if(EdgeReflector && (!(EdgeReflectorAtZero))) zt-=200.0; } else { if(MirrorY) { yt=-yt; if(EdgeReflector || EdgeReflectorAtZero) yt-=200.0; } else { if(MirrorX) { xt=-xt; if(EdgeReflector || EdgeReflectorAtZero) xt-=200.0; } } } } MapCoordinates(xt, yt, zt, &Face2d[VertexNumInFacet].x, &Face2d[VertexNumInFacet].y); } Face2d[LastVertexNumInFacet+1]=Face2d[1]; } Boolean Mirroring; void PutFacet2(PixelArray Face2d, Byte Color, Byte Intens) { int xc, yc; int i, x; int OldVertNum; int VertNum; int mnx, mxx; int mny, mxy; float slope; if(Intens<1) return; if(Reflect && (Intens!=1)) { --Intens; if(Intens!=2) { --Intens; if(Intens!=3) --Intens; } } mny=Face2d[1].y; mxy=Face2d[1].y; for(i=2; i<=LastVertexNumInFacet; i++) { if(Face2d[i].y>mxy) mxy=Face2d[i].y; if(Face2d[i].yMaxY) mxy=MaxY; for(yc=mny; yc<=mxy; yc++) { mnx=MaxX+1; mxx=-1; OldVertNum=LastVertexNumInFacet; for(VertNum=1; VertNum<=LastVertexNumInFacet; VertNum++) { if((Face2d[OldVertNum].y>=yc) || (Face2d[VertNum].y>=yc)) { if((Face2d[OldVertNum].y<=yc) || (Face2d[VertNum].y<=yc)) { if(Face2d[OldVertNum].y != Face2d[VertNum].y) { slope=(float)(Face2d[VertNum].x-Face2d[OldVertNum].x)/ (float)(Face2d[VertNum].y-Face2d[OldVertNum].y); x=Round(slope*(float)((yc-Face2d[OldVertNum].y))+ Face2d[OldVertNum].x); if(xmxx) mxx=x; } } } OldVertNum=VertNum; } if(mnx<0) mnx=0; if(mxx>MaxX) mxx=MaxX; if(mnx<=mxx) { for(xc=mnx; xc<=mxx; xc++) { if(Mirroring) { MakeReflected(xc, yc); PutPixel(xc, yc, Color, Intens); } else { if(!(Reflect)) PutPixel(xc, yc, Color, Intens); else { if(Reflected(xc, yc)) PutPixel(xc, yc, Color, Intens); } } } } } } /* *********************************************************************** * * * Load Description File and Scene Data * * * *********************************************************************** LoadDescAndScene - loads description file ".DES" and scene data */ Strg B; Name SceneFile; void GetSceneFile() { int i; Byte x, y; printf("\nEnter File Name -> "); x=wherex(); y=wherey(); gets(SceneFile); if(!(strcmp(SceneFile, ""))) { strcpy(SceneFile, "CUBEPLAN"); gotoxy(x, y); puts(SceneFile); } puts(""); for(i=0; i