/* *********************************************************************** * * * z-Buffer Rendering Package * * * * Program by * * Christopher D. Watkins * * * * 'C' conversion by * * Larry Sharp * * * *********************************************************************** The data is in an integer valued (MaxRes+1 x MaxRes+1 x 32768) cube where an integer height value is stored in a cell at (x, y) The height value is then scaled to fit into the unit cube tilt = 0 for side view and tilt = 90 for top view looking from top view : x-axis is right while y-axis is up looking from side view : x-axis is right while y-axis is in */ #include "stdio.h" #include "stdlib.h" #include "dos.h" #include "conio.h" #include "math.h" #include "string.h" #include "math.inc" #include "graph.inc" #include "render.inc" /* *********************************************************************** * * * Toggle Switches * * * *********************************************************************** InitGround - allows Height[i][j] = 0 to be plotted InitScale - show image at half scale */ Boolean ShowGround; void InitGround(Boolean Ground) { if(Ground) ShowGround=true; else ShowGround=false; } Boolean HalfScale; void InitScale(Boolean HlfScl) { if(HlfScl) HalfScale=true; else HalfScale=false; } /* *********************************************************************** * * * Screen Procedures * * * *********************************************************************** Pixel - the place interpolated pixels routine InitPixBuf - intialize the pixel buffer */ #define MaxBufs 3 typedef Byte PixBuffer[(MaxRes*2)+1]; typedef PixBuffer PixBuf[MaxBufs+1]; PixBuf PixBufColor; PixBuf PixBufInten; PixBuf NullPixBuf; int TwoMaxRes; void ClearPixBuf(int Buf1, int Buf2) { Byte i; Word j, k; j=MaxRes*2; for(i=Buf1; i<=Buf2; i++) { for(k=0; k<=j; k++) { PixBufColor[i][k]=NullPixBuf[i][k]; PixBufInten[i][k]=NullPixBuf[i][k]; } } } void CopyPixBuf(int Buf1, int Buf2) { Word i; Word j; j=MaxRes*2; for(i=0; i<=j; i++) { PixBufColor[Buf2][i]=PixBufColor[Buf1][i]; PixBufInten[Buf2][i]=PixBufInten[Buf1][i]; } } void InterpolateX(int buf, int buf1, int buf2) { int i; for(i=0; i<=TwoMaxRes; i++) { if(random(2)==1) PixBufColor[buf][i]=PixBufColor[buf1][i]; else PixBufColor[buf][i]=PixBufColor[buf2][i]; PixBufInten[buf][i]=(PixBufInten[buf1][i]+PixBufInten[buf2][i])/2; } } void InterpolateY(int buf) { int i, k; for(i=0; i0) BufNum=MaxBuf; else { if(ColNum==0) BufNum=1; } } else { if(FoundFirstCol) BufNum=MaxBuf; else { if(ColNum>0) { OldCol=ColNum; BufNum=1; FoundFirstCol=true; } } } if(ColNum==2) { if(OldCol==1) { InterpolatePixBuf(); DisplayPixBuf(1, MaxBuf); OldCol=ColNum; CopyPixBuf(MaxBuf, 1); ClearPixBuf(2, MaxBuf); return; } } if(OldCol==ColNum-1) { InterpolatePixBuf(); DisplayPixBuf(2, MaxBuf); OldCol=ColNum; CopyPixBuf(MaxBuf, 1); ClearPixBuf(2, MaxBuf); return; } PixBufColor[BufNum][RowNum]=DisplayColor; PixBufInten[BufNum][RowNum]=Inten; } } void InitPixBuf() { int i, j; randomize(); OldCol=1; TwoMaxRes=2*MaxRes; FoundFirstCol=false; for(i=1; i<=MaxBufs; i++) { for(j=0; j<=TwoMaxRes; j++) NullPixBuf[i][j]=0; } if(HalfScale) MaxBuf=1; else MaxBuf=MaxBufs; ClearPixBuf(1, MaxBufs); } /* *********************************************************************** * * * Viewer and Light Source Vectors * * * *********************************************************************** Viewer - the viewer unit vector InitLightDirection - set the light direction GetLightVector - the light direction unit vector */ TDA View; float SinViewPhi; float CosViewPhi; float VPhi; float Vx, Vy, Vz; void GetViewVector() { Vx=0.0; Vy=-CosViewPhi; Vz=SinViewPhi; Vec(Vx, Vy, Vz, View); } void Viewer(float DPhi) { VPhi=Radians(DPhi); SinViewPhi=sin(VPhi); CosViewPhi=cos(VPhi); GetViewVector(); } float LightPhi; float LightTheta; void InitLightDirection(float Phi, float Theta) { LightPhi=Phi; LightTheta=Theta; } 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); } /* *********************************************************************** * * * The Illumination Model * * * *********************************************************************** InitSpread - choose the spread for the normal calculation Intensity - calculate the intensity of a pixel */ #define Ambient 0.15 #define DifRfl 0.45 #define SpcRfl 0.40 #define Gloss 2 int Spread; float CosTheta; float CosAlpha; TDA SrfNorm; TDA Ref; void InitSpread(int SpreadOfCalc) { Spread=SpreadOfCalc; } int i1, j1; void GetNormal() { float dx, dy, dz; if(j1-1<0) Vec(0.0, 0.0, 1.0, SrfNorm); else { dx=(float)(Height[i1][j1]-Height[i1+1][j1])/(float) Scaling; dy=(float)(Height[i1][j1-1]-Height[i1][j1])/(float) Scaling; dz=1.0/(float)(Res-1); Vec(dx, dy, dz, SrfNorm); VecNormalize(SrfNorm); } } void GetSurfaceNormalVector(int i, int j, int Spread) { TDA SrfNormSum; int Cells; VecNull(SrfNormSum); Cells=Sqr(2*Spread+1); for(i1=(i-Spread); i1<=(i+Spread); i1++) { for(j1=(j-Spread); j1<=(j+Spread); j1++) { GetNormal(); VecAdd(SrfNormSum, SrfNorm, SrfNormSum); } } VecScalMult(1.0/(float) Cells, SrfNormSum, SrfNorm); } void GetReflectedVector() { float TwoCosTheta; TDA temp; TwoCosTheta=2.0*CosTheta; VecScalMult(TwoCosTheta, SrfNorm, temp); VecNormalize(temp); VecSub(temp, Light, Ref); VecNormalize(Ref); } int Intensity(int i, int j) { GetSurfaceNormalVector(i, j, Spread); CosTheta=VecDot(SrfNorm, Light); if(CosTheta<0.0) return(Round(MaxInten*Ambient)); else { GetReflectedVector(); CosAlpha=VecDot(View, Ref); return(Round(MaxInten*(Ambient+DifRfl*CosTheta+SpcRfl*pow(CosAlpha, Gloss)))); } } /* *********************************************************************** * * * Load Description Data * * * *********************************************************************** LoadDescription - load description of object */ #define MaxDiv 6 int NumHgtDiv; int GroundColor; int HeightColor[MaxDiv+1]; int TopColor; int HeightLimit[MaxDiv+1]; typedef char Strg[10]; Boolean Bool(Strg B) { if(!(strcmp(B, "false"))) return(false); else return(true); } void LoadDescription(Name FileName) { char B[10]; int I1, I2; int i; float fi1, fi2; strcpy(B, "\n"); strcat(FileName, ".DES"); TextDiskFile=fopen(FileName, "r+t"); puts(""); fscanf(TextDiskFile, "%s", &B); InitScale(Bool(B)); if(Bool(B)) printf("Scale=Half\n\n"); else printf("Scale=Full\n\n"); fscanf(TextDiskFile, "%s", &B); InitGround(Bool(B)); if(!(Bool(B))) printf("Ground coloring off\n"); fgets(B, 9, TextDiskFile); I1=atoi(fgets(B, 9, TextDiskFile)); GroundColor=I1; if(ShowGround) { printf("Ground Color = "); GetObjectColor(I1); } NumHgtDiv=atoi(fgets(B, 9, TextDiskFile)); for(i=1; i<=NumHgtDiv; i++) { I2=atoi(fgets(B, 9, TextDiskFile)); HeightColor[i]=I2; printf("Color below %d / %d = ", i, NumHgtDiv); GetObjectColor(I2); } I1=atoi(fgets(B, 9, TextDiskFile)); TopColor=I1; printf("Top Color = "); GetObjectColor(I1); puts(""); I1=atoi(fgets(B, 9, TextDiskFile)); InitSpread(I1); printf("Normal Calculation Spread = %d\n\n", I1); fi1=atof(fgets(B, 9, TextDiskFile)); fi2=atof(fgets(B, 9, TextDiskFile)); InitLightDirection(fi1, fi2); printf("Light Direction is %4f around the z-Axis and\n", fi1); printf(" %4f off of the z-Axis\n\n", fi2); fi1=atof(fgets(B, 9, TextDiskFile)); Viewer(fi1); GetLightVector(); printf("Tilt of xy-Plane = %4f \n\n", fi1); I1=atoi(fgets(B, 9, TextDiskFile)); YOffset=I1; printf("Y Offset = %d\n", I1); fclose(TextDiskFile); } /* *********************************************************************** * * * Display the Height Field * * * *********************************************************************** DisplayHeightField - calculate pixel positions and interpolate intensities */ int Max; int II, JJ; int p0, p1; int horizon; int Pix; int OldPix; int NewPix; int PP; void Interpolate() { float h; h=(float)(PP-p0)/(p1-p0); Pix=Round((h*OldPix+(1.0-h)*NewPix)); Pixel(II, PP, Pix); --PP; } void AboveHorizon() { OldPix=Intensity(II, JJ); Pixel(II, p1, OldPix); PP=p1-1; if((ShowGround) && (PP>horizon)) { NewPix=Intensity(II, JJ-1); while(PP>horizon) Interpolate(); } horizon=p1; } int Proj(float y, float z) { return(Round(Res*(y*SinViewPhi+z*CosViewPhi))); } void DisplayHeightField() { int n; int L1, L2; for(n=1; n<=NumHgtDiv; n++) HeightLimit[n]=n*(Max/NumHgtDiv); for(II=(0+Spread); II<=((Res-1)-Spread); II++) { p0=Proj(0.0, (float) Height[II][0]/Scaling); horizon=p0; for(JJ=(1+Spread); JJ<=((Res-1)-Spread); JJ++) { if(Height[II][JJ]==0) { if(ShowGround) DisplayColor=GroundColor; else goto L1; } else { for(n=1; n<=NumHgtDiv; n++) { if(Height[II][JJ]horizon) AboveHorizon(); p0=p1; L1:; } } } void FindMax() { int i, j; Max=0; for(i=0; i<=MaxRes; i++) { for(j=0; j<=MaxRes; j++) { if(Height[i][j]>Max) Max=Height[i][j]; } } } /* *********************************************************************** * * * Place the Special Add-Ons to the Screen * * * *********************************************************************** PlaceAddOnsToScreen - special additions such as lightning and moons */ #include "addons.inc" void PlaceAddOnsToScreen(Name ObjectFile) { if(!(strcmp(ObjectFile, "CPM1"))) { JuliaSet(0.0, 1.0, 0, Res/3, Res, Res, BLUE); MapJuliaSetToSphere(-0.15652, -1.03225, -3*Res/4, -Res/2, 35, 90, 90, MAGENTA); } if(!(strcmp(ObjectFile, "CPM2"))) { JuliaSet(0.0, 1.0, 0, Res/3, Res, Res, RED); MapJuliaSetToSphere(-0.15652, -1.03225, -3*Res/4, -Res/2, 35, 90, 90, BLUE); } if(!(strcmp(ObjectFile, "CPMJ1"))) { JuliaSet(0.0, 1.0, 0, Res/3, Res, Res, LIGHTGRAY); MapJuliaSetToSphere(-0.15652, -1.03225, -3*Res/4, -Res/2, 35, 90, 90, YELLOW); } if(!(strcmp(ObjectFile, "CPMJ2"))) { Sky(0, 0, Res, Res, CYAN); MapJuliaSetToSphere(-0.15652, -1.03225, -3*Res/4, -Res/2, 35, 90, 90, MAGENTA); } } /* *********************************************************************** * * * Main Program * * * *********************************************************************** */ Name OF2; void main() { Title(); printf("z-Buffer Rendering System\n\n"); ClearHeightBuffer(); GetObjectFile(); strcpy(OF2, ObjectFile); LoadDescription(ObjectFile); printf("\nHit any key...."); getch(); InitPixBuf(); strcpy(ObjectFile, OF2); LoadHeightBuffer(ObjectFile); InitGraphics(); InitPalette2(Color); SetPalette(Color); FindMax(); strcpy(ObjectFile, OF2); PlaceAddOnsToScreen(ObjectFile); DisplayHeightField(); ExitGraphics(); }