/* ***********************************************************************
* *
* 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].y<mny)
mny=Face2d[i].y;
}
if(mny<0)
mny=0;
if(mxy>MaxY)
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(x<mnx)
mnx=x;
if(x>mxx)
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<strlen(SceneFile); i++)
SceneFile[i]=toupper(SceneFile[i]);
}
void LoadDescAndScene(Name FileName)
{
FILE *TextDiskFile;
TextDiskFile=fopen(FileName, "r+t");
fscanf(TextDiskFile, "%s", B);
PutAxisAndPalette(Bool(B));
if(Bool(B))
printf("Axis and Palette Display On\n");
else
printf("Axis and Palette Display Off\n");
fscanf(TextDiskFile, "%s", B);
DoSolidModel(Bool(B));
if(Bool(B))
printf("Solid Model Display On\n");
else
printf("Solid Model Display Off\n");
if(SolidModel)
{
fscanf(TextDiskFile, "%s", B);
fscanf(TextDiskFile, "%s", B);
DoPreview(false);
DoWireFrame(false);
}
else
{
fscanf(TextDiskFile, "%s", B);
DoPreview(Bool(B));
if(Bool(B))
printf("Vertex Display On\n");
else
printf("Vertex Display Off\n");
fscanf(TextDiskFile, "%s", B);
DoWireFrame(Bool(B));
if(Bool(B))
printf("Wire Frame Display On\n");
else
printf("Wire Frame Display Off\n");
}
fscanf(TextDiskFile, "%s", B);
fclose(TextDiskFile);
if(Bool(B))
{
printf("Loading Scene from Disk File\n");
GetSceneFile();
AddObjectsToSceneFromDiskFile(SceneFile);
}
else
{
printf("Loading Scene from Procedure\n\n");
AddObjectsToSceneFromProcedure();
}
printf("Hit any key....\n");
getch();
}
#include "dispobjs.inc"
/* ***********************************************************************
* *
* Main Program *
* *
***********************************************************************
*/
void main()
{
Facet=farcalloc(((MaxFacet+1)*(MaxVertexNumInFacet+1)), sizeof(int));
if(Facet==0)
{
printf("Not enough memory!\n");
getch();
exit(1);
}
Title();
printf("3-D Modeling Program\n\n");
InitReflectionBuffer();
InitVertexBuffer();
InitObjectBuffer();
LoadDescAndScene("MODEL.DES");
InitGraphics();
AxisAndPalette();
if(DrawAxisAndPalette)
WaitForKey();
DisplayObjectsInScene();
ExitGraphics();
farfree(Facet);
}