/* *********************************************************************** * * * 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 "malloc.h" #include "defs.h" #include "globals.h" #include "mathb.h" #include "graphb.h" #include "modelsup.h" static Byte far *Red_Plane; static Byte far *Green_Plane; static Byte far *Blue_Plane; #define xcyc (yc*160)+xc #define xy (y*160)+x void Allocate_Memory() { Facet=farcalloc(((MaxFacet+1)*(MaxVertexNumInFacet+1)), sizeof(int)); Red_Plane=farmalloc(16000); Green_Plane=farmalloc(16000); Blue_Plane=farmalloc(16000); if((Facet==NULL) || (Red_Plane==NULL) || (Green_Plane==NULL) || (Blue_Plane==NULL)) { printf("Not enough memory!\n"); printf("%p\n%p\n%p\n%p\n", Facet, Red_Plane, Green_Plane, Blue_Plane); getch(); exit(1); } } void Free_Memory() { farfree(Facet); farfree(Red_Plane); farfree(Green_Plane); farfree(Blue_Plane); } void Put_Grey_Pixel(int xc, int yc, TDIA Intens) { Byte col; Red_Plane[xcyc]=Intens[0]&255; Green_Plane[xcyc]=Intens[1]&255; Blue_Plane[xcyc]=Intens[2]&255; col=((Intens[0]+Intens[1]+Intens[2])/3); Plot(xc, yc, col); } void Clear_Planes() { _fmemset(Red_Plane, 0, 16000); _fmemset(Green_Plane, 0, 16000); _fmemset(Blue_Plane, 0, 16000); } /* *********************************************************************** * * * Toggle Switches * * * *********************************************************************** VertSort - vertically sort objects */ Boolean VerticalSort; 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(TDA T, TDA S, TDA R) { Matx4x4 XForm; PrepareMatrix(T[0], T[1], T[2], S[0], S[1], S[2], R[0], R[1], R[2], XForm); DoTransform(XForm); } void InvAffineTransformation(TDA T, TDA S, TDA R) { Matx4x4 XForm; PrepareInvMatrix(-T[0], -T[1], -T[2], 1.0/S[0], 1.0/S[1], 1.0/S[2], -R[0], -R[1], -R[2], 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-(float)Angl); Theta=Radians((float)ViewTheta-(float)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) { 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); } } } /* ************************************************************************ * * * 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(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][101]; void InitReflectionBuffer() { int i, j; for(i=0; i<=XBytes; i++) { for(j=0; j>(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)); } /* *********************************************************************** * * * Add Objects to the Objects List Database * * * *********************************************************************** InitObjectBuffer - initialize object buffer AddObject - add object of certain name Scale - scale the object Rotate - rotate the object Translate - translate the object ReflectObject - will this object reflect on a reflective object ObjectColor - color of object AllowSort - is this object sorted Mirrored - is this object reflective */ #define NumObjects 20 int ObjectNum; int LastObject; typedef struct{ Name ObjectName; TDA Translate; TDA Rotate; TDA Scale; Boolean Reflection; TDA AmbColor; TDA DifColor; TDA SpcColor; Byte Gloss; Boolean Sortable; Boolean Mirror; }ObjL; ObjL ObjList[NumObjects+1]; void InitObjectBuffer() { for(ObjectNum=0; ObjectNum<=NumObjects; ObjectNum++) { strset(ObjList[ObjectNum].ObjectName, 0); VecNull(ObjList[ObjectNum].Translate); VecNull(ObjList[ObjectNum].Rotate); VecNull(ObjList[ObjectNum].Scale); ObjList[ObjectNum].Reflection=false; VecNull(ObjList[ObjectNum].AmbColor); VecNull(ObjList[ObjectNum].DifColor); VecNull(ObjList[ObjectNum].SpcColor); ObjList[ObjectNum].Gloss=0; ObjList[ObjectNum].Sortable=false; ObjList[ObjectNum].Mirror=false; } ObjectNum=0; } void AddObject(Name FileName) { ++ObjectNum; strcpy(ObjList[ObjectNum].ObjectName, FileName); LastObject=ObjectNum; } void Scale(float x, float y, float z) { Vec(x, y, z, ObjList[ObjectNum].Scale); } void Rotate(float x, float y, float z) { Vec(-x, -y, -z, ObjList[ObjectNum].Rotate); } void Translate(float x, float y, float z) { Vec(-x, -y, -z, ObjList[ObjectNum].Translate); } void ReflectObject(Boolean State) { ObjList[ObjectNum].Reflection=State; } void ObjAmbColor(float r, float g, float b) { Vec(r, g, b, ObjList[ObjectNum].AmbColor); } void ObjDifColor(float r, float g, float b) { Vec(r, g, b, ObjList[ObjectNum].DifColor); } void ObjSpcColor(float r, float g, float b) { Vec(r, g, b, ObjList[ObjectNum].SpcColor); } void ObjGloss(Byte Col) { ObjList[ObjectNum].Gloss=Col; } void AllowSort(Boolean State) { ObjList[ObjectNum].Sortable=State; } void Mirrored(Boolean State) { ObjList[ObjectNum].Mirror=State; } /* *********************************************************************** * * * The Illumination Model * * * *********************************************************************** Intensity - calculated intensity of point on screen */ TDIA Intensity; void IntensityCalc() { TDA Diffuse; TDA Specular; TDA Color; float CosTheta; float CosAlpha; TDA Ref; float TwoCosTheta; TDA temp; CosTheta=VecDot(SrfNorm, Light); if(CosTheta<=0.0) VecScalMultInt(63.0, ObjList[ObjectNum].AmbColor, Intensity); else { TwoCosTheta=2.0*CosTheta; VecScalMult(TwoCosTheta, SrfNorm, temp); VecNormalize(temp); VecSub(temp, Light, Ref); VecNormalize(Ref); CosAlpha=VecDot(View, Ref); VecScalMult(CosTheta, ObjList[ObjectNum].DifColor, Diffuse); VecScalMult(Power(CosAlpha, ObjList[ObjectNum].Gloss), ObjList[ObjectNum].SpcColor, Specular); VecAdd3(ObjList[ObjectNum].AmbColor, Diffuse, Specular, Color); VecScalMultInt(63.0, Color, Intensity); if(Intensity[0]>63) Intensity[0]=63; if(Intensity[1]>63) Intensity[1]=63; if(Intensity[2]>63) Intensity[2]=63; } } /* *********************************************************************** * * * Routines to Add Edge Reflectors to a Scene * * * *********************************************************************** AddReflectorAtZero - adds edge reflectors at x=-50, y=-50 and z=0 AddReflectors - adds edge reflectors at x=-50, y=-50 and z=-50 */ Boolean EdgeReflectorAtZero; Boolean EdgeReflector; void AddEdgeReflectorsAtZero() { EdgeReflectorAtZero=true; AddObject("GRID.DAT"); Scale(50.0, 50.0, 50.0); Rotate(0.0, 0.0, 0.0); Translate(0.0, 0.0, 0.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); AddObject("GRID.DAT"); Scale(25.0, 25.0, 25.0); Rotate(0.0, 90.0, 0.0); Translate(-50.0, 0.0, 25.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); AddObject("GRID.DAT"); Scale(50.0, 25.0, 25.0); Rotate(-90.0, 0.0, 0.0); Translate(0.0, -50.0, 25.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); } void AddEdgeReflectors() { EdgeReflector=true; AddObject("GRID.DAT"); Scale(50.0, 50.0, 50.0); Rotate(0.0, 0.0, 0.0); Translate(0.0, 0.0, -50.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); AddObject("GRID.DAT"); Scale(50.0, 50.0, 50.0); Rotate(0.0, 90.0, 0.0); Translate(-50.0, 0.0, 0.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); AddObject("GRID.DAT"); Scale(50.0, 50.0, 50.0); Rotate(-90.0, 0.0, 0.0); Translate(0.0, -50.0, 0.0); ReflectObject(false); ObjAmbColor(0.300, 0.300, 0.300); ObjDifColor(0.500, 0.500, 0.500); ObjSpcColor(0.200, 0.200, 0.200); ObjGloss(20); AllowSort(false); Mirrored(true); } /* *********************************************************************** * * * Add Objects To Scene Frrm .SCN Disk File * * * *********************************************************************** AddObjectsToScene - add objects to database from .SCN disk file */ typedef char Strg[6]; Boolean Bool(Strg B) { if((B[0]=='F') || (B[0]=='f')) return(false); else return(true); } FILE *In_File; float Mix, Darken; Byte Last_Object_Num; void AddObjectsToScene() { int i1, i2, i3, i4; float f1, f2, f3; Name ObjectFileName; Byte ObjN; char blank[81]; Strg B; fgets(blank, 80, In_File); fscanf(In_File, "%s %d %d %d %d", B, &i1, &i2, &i3, &i4); Init_Perspective(Bool(B), (float)i1, (float)i2, (float)i3, (float)i4); fscanf(In_File, "%d %d", &i1, &i2); Init_Plotting(i1, i2); GetViewVector(); fscanf(In_File, "%d %d", &i1, &i2); InitLightDirection(i1, i2); GetLightVector(); fscanf(In_File, "%s", B); VertSort(Bool(B)); fscanf(In_File, "%s", B); if(Bool(B)) AddEdgeReflectors(); fscanf(In_File, "%s", B); if(Bool(B)) AddEdgeReflectorsAtZero(); fscanf(In_File, "%f", &f1); Mix=f1; fscanf(In_File, "%f", &f1); Darken=f1; fgets(blank, 80, In_File); fscanf(In_File, "%d", &i1); Last_Object_Num=i1; for(ObjN=0; ObjNmxy) mxy=Face2d[i].y; if(Face2d[i].y=YRes) mxy=YRes-1; for(yc=mny; yc<=mxy; yc++) { mnx=XRes+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>=XRes) mxx=XRes-1; if(mnx<=mxx) { for(xc=mnx; xc<=mxx; xc++) { if(Mirroring) { MakeReflected(xc, yc); VecCopyInt(Intensity, Intens); Put_Grey_Pixel(xc, yc, Intens); } else { if(!(Reflect)) { VecCopyInt(Intensity, Intens); Put_Grey_Pixel(xc, yc, Intens); } else { if(Reflected(xc, yc)) { Intens[0]=(int)((Intensity[0]*Mix+Red_Plane[xcyc]*(1.0-Mix))*Darken); Intens[1]=(int)((Intensity[1]*Mix+Green_Plane[xcyc]*(1.0-Mix))*Darken); Intens[2]=(int)((Intensity[2]*Mix+Blue_Plane[xcyc]*(1.0-Mix))*Darken); Put_Grey_Pixel(xc, yc, Intens); } } } } } } } /* *********************************************************************** * * * Routines for Sorting Objects for Order of Placement on the Screen * * * *********************************************************************** PrepareSort - setup for sorting routines SortObjectsBackToFront - sort for actual objects SortTopToBottom - sort for reflections in Z SortBottomToTop - sort for actual objects SortObjectsFrontToBackInY - sort for reflections in Y SortObjectsFrontToBackInX - sort for reflections in X */ int First; int Last; int FirstObject; Boolean Sorting; Boolean ReflSurface; int NumMirrors; void PrepareSort() { ReflSurface=false; Last=LastObject; if(LastObject==1) { First=Last; FirstObject=LastObject; } else { First=1; while((ObjList[First].Sortable==false) && (First=0.0) { if(ab) SwapData(); } } void OrderX() { for(i=First; iy) && (x>z)) OrderX(); else { if((y>x) && (y>z)) OrderY(); else OrderZ(); } } void SwapDown(float a, float b) { if(a>b) SwapData(); } void SortTopToBottom() { for(i=First; i=0.0) { if(a>b) SwapData(); } else { if(a0) || (Intensity[1]>0) || (Intensity[2]>0)) { GetProjectedCoords(Face3d, Face2d); PutFacet(Face2d); } } } void PlaceObjectOnScreen() { for(FacetNum=1; FacetNum<=LastFacet; FacetNum++) { if((!(Reflect)) && (!(ZReflectedObject)) && (!(YReflectedObject)) && (!(XReflectedObject))) PlaceFacet(false, false, false); else { if(ZReflectedObject) PlaceFacet(false, false, true); else { if(YReflectedObject) PlaceFacet(false, true, false); else { if(XReflectedObject) PlaceFacet(true, false, false); } } } } } Name LastObjectName; Boolean ReflectedObjects; void DisplayReflectiveSurfaces() { strset(LastObjectName, 0); ReflectedObjects=false; Reflect=false; for(ObjectNum=1; ObjectNum1) { DefineReflection(false, true, false); if(Sorting) SortObjectsFrontToBackInY(); if(Sorting && VerticalSort) SortBottomToTop(); if(ReflectedObjects) DisplayReflections(); DefineReflection(true, false, false); if(Sorting) SortObjectsFrontToBackInX(); if(Sorting && VerticalSort) SortBottomToTop(); if(ReflectedObjects) DisplayReflections(); } } DefineReflection(false, false, false); if(Sorting) SortObjectsBackToFront(); if(Sorting && VerticalSort) SortBottomToTop(); DisplayActualImages(); } Name SceneFile; Name Temp_File; Name Pic_File; FILE *Out_File; void Get_Scene_File_Name() { Byte x, y; textcolor(YELLOW); textbackground(BLUE); gotoxy(1, 8); cprintf("Enter File Name -> "); x=wherex(); y=wherey(); textcolor(WHITE+BLINK); cprintf("%s", "SPHRPLAN"); textcolor(YELLOW); gotoxy(x, y); while(!(kbhit())); cprintf(" "); gotoxy(x, y); gets(SceneFile); if(!(strcmp(SceneFile, ""))) strcpy(SceneFile, "SPHRPLAN"); strupr(SceneFile); strcpy(Pic_File, SceneFile); strcpy(Temp_File, SceneFile); strcat(SceneFile, ".SCN"); strcat(Temp_File, ".TMP"); strcat(Pic_File, ".ANI"); } void WriteTmpFile() { Byte x, y; Word LineBuf[160]; Word col, r, g, b; for(y=0; y<100; y++) { for(x=0; x<160; x++) { r=Red_Plane[xy]&62; g=Green_Plane[xy]&62; b=Blue_Plane[xy]&62; col=((r>>1)|(g<<4)|(b<<9)); LineBuf[x]=col; } fwrite(LineBuf, sizeof(LineBuf), 1, Out_File); } } Byte Last_Frame_Num, Frame_Num; Palette_Register PalArray; void Clear_Screen() { Set_Graphics_Mode(160, 100); Init_Palette(PalArray); Set_Palette(PalArray); } #include "process.h" /* *********************************************************************** * * * Main Program * * * *********************************************************************** */ void main() { char com[81]; Allocate_Memory(); Title(); printf("Three Dimensional Modeling Program\n\n"); printf("Program by Christopher D. Watkins\n\n"); printf("'C' Conversion by Larry Sharp\n\n"); Clear_Planes(); InitObjectBuffer(); InitReflectionBuffer(); InitVertexBuffer(); Get_Scene_File_Name(); Clear_Screen(); if((In_File=fopen(SceneFile, "rt"))==NULL) { ungetch(32); Exit_Graphics(); printf("Can't open Input File -> %s!\nHit any key to exit....\n", SceneFile); getch(); exit(1); } if((Out_File=fopen(Temp_File, "wb"))==NULL) { ungetch(32); Exit_Graphics(); printf("Can't open Output File -> %s!\nHit any key to exit....\n", Out_File); getch(); exit(1); } fgets(com, 80, In_File); fgets(com, 80, In_File); fscanf(In_File, "%d", &Last_Frame_Num); putc(Last_Frame_Num, Out_File); for(Frame_Num=0; Frame_Num