Metropoli BBS
VIEWER: model.c MODE: TEXT (ASCII)
/* ***********************************************************************
   *									 *
   *		    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);
}
[ RETURN TO DIRECTORY ]