From: wilsont@orac.holonet.net (Timothy Wilson)
Newsgroups: rec.games.programmer
Subject: 3D code to those who want it
Date: 11 Oct 92 22:58:37 GMT
Organization: HoloNet (BBS: 510-704-1058)


/* originally developed for alt.3d, but i though some people here
also would like to see it */



#include <math.h>
#include <stdio.h>
/*
#include <graphics.h>
#include <osbind.h>
**** Atari ST only  commands will be commented out */
/* This program was developed on a Atari ST, using Sozobon 1.44i */
/* The graphic commands from the public domain turbo C compatible lib*/

/* With help from George Kyriazis and  Bob Pendelton */
/* thanks guys!! */
/* told you'd be in the credits!! */

/* To speed operations, this program makes its own sin table, converts 
it to longs, and uses integer math instead of doubles or floats */
/* speed more than doubled after i did this. */

/* the bottom part of this text file has longmath.c cut it out, its
another module */


/* any questions should be directed to: wilsont@prism.cs.orst.edu */
/* NOT to wilsont@holonet.net !!! i'll be moving shortly (next week!)*/
 

/* this code is in no way copyrighted, go ahead and grab all you want */
/* this code is for beginners, by a beginner, in no way should it be
taken as a professional work. */

/* upgrades may or maynot be availible. I have a job to deal with, but
if time permits, and if any one asks, I should have the following:
* cheapo scripting for RT animations (games, simulations etc..) 
* fast actual 3D clipping, (right now the computers polygon routine does
the clippin,and only in 2D )
* object creation (based on this program)
*/

/* I really don't understand matrix operations. my equations do the same
thing, and they aren't dogs. */
/* this program is set up to do bit shifts for the sintables ( <<14=16384)
but for some reason, i couln't get the left shift to work.. since it
destroys the sign bit if the number is negative, i left it to do a divide */
/* again, any questions at all, direct them to wilsont@prism.cs.orst.edu */
/* Enjoy this code! */
/*              Timothy Wilson */



typedef struct {
        long x,y,z;
        } Point3;

typedef struct {
        int x,y;
        } Point2;

typedef struct {
        int a,b,c,d;
        int color;
        int viz;
        long midz;
        int own;
        } POLY;

POLY poly[60];  /* all polygons eventually go here for depth sorting */

/* 5 object limit, just to keep it quick */
/* just bump up this number for more objects */

Point3 docalc();


Point3 objc[5];
Point3 objv[5][100];

int NP[5]; /* # of points in object */
int NL[5]; /* # of polys in object */
int NO; /* # of objects */
int NPOLY; /* total number of polygons */
Point3 world[5][40]; /* world coordinates for objects */ 
Point2 pic[5][100];  /* pic coordinates of objects */
Point3 view[5][100];  /* view coordinates of objects */



long  ox,oy,oz;
int theta,phi,zw; /* zw=bank */
int fill;  /* flag for wireframe or filled polygons */


main()
{
int i,ch;
Point3 p;
Point2 cc;
/* int graphdriver,graphmode; */

char out[30];
Point3 chk;
long offx,offy,offz;
/* long block,altscreen,oldscreen,hscreen,orgscreen; */
long sx,sy;
int ob;
int step;
long dx,dy,dz;



fill=1;

/* reserve memory for other screen
block=Malloc(0x7E00L);
altscreen= (block+256) & 0x00FFFF00;
*/

offx=0;
offy=0;
offz=2;
step=2;

/*
graphdriver=SC1224;
graphmode=SC1224LO;
*/



ox=0;
oy=0;
oz=-50;
theta=0;
phi=0;
zw=0;


makesintab();


loaddat();

/* set up screen 
oldscreen=(long)Physbase();
orgscreen=oldscreen;

set to lowres

Setscreen(altscreen,oldscreen,0);
initgraph(&graphdriver,&graphmode,"");
*/

while(1)
{
/* clear the hidden page */
/*  cleardevice(); */



for (ob=0;ob<NO;ob++)
for (i=0;i<NP[ob];i++)
        {

/* convert from object coord sys to world sys */

        world[ob][i].x=objc[ob].x+objv[ob][i].x;
        world[ob][i].y=objc[ob].y+objv[ob][i].y;
        world[ob][i].z=objc[ob].z+objv[ob][i].z;

        p.x=world[ob][i].x;
        p.y=world[ob][i].y;
        p.z=world[ob][i].z;

/* use world coords  to generate view coords */
        chk=docalc(p);
        view[ob][i].x=chk.x;
        view[ob][i].y=chk.y;
        view[ob][i].z=chk.z;
        
/* convert to screen(picture)  coordinates */

        sx=((chk.x)*128 ) /chk.z;
        sy=((chk.y)*128) /chk.z;

/* convert to computer coordinates */
        pic[ob][i].x=160+(int) sx;
        pic[ob][i].y=100+(int) sy; 

        }


vizit(); /* determines polygon visibility (all of them) */

sortply(); /* combine and sort all polys here */

drawall(); /* draw those polygons */

/* get a key from the keyboard 
if (Bconstat(2)) 
        ch=Bconin(2) & 255;
  else ch=0;
*/


switch(ch)
        {
        case 0: break;

        case '+': 
        oz+=step;
        break;
        case '-' : 
        oz-=step;
        break;

        case '6': theta+=5;
        break;
        case '8': phi+=5;
        break;
        case '2': phi-=5;
        break;
        case '1': zw-=5;
        break;
        case '3': zw+=5;
        break;
        case '4': theta-=5;
        break;
        case 'x':
        /* exit routine, restores modes, colors and original page 
                Setscreen(orgscreen,orgscreen,1);
                 restorecrtmode();
                 Mfree(block);
                closegraph();
        */
                exit(0);
                break;

        case 'a': oy+=step;
                break;
        case 'z': oy-=step;
                break;
        case 'q': ox-=step;
                break;
        case 'w': ox+=step;
                break;
        case 'f': fill=1;
                break;
        case 'g': fill=0;
                break;
        
        }

/* checks for out of bounds for degrees */
if (theta<0) theta+=360;
if (phi<0) phi+=360;
if (theta>360) theta-=360;
if (phi>360) phi-=360;
if (zw<0) zw+=360;
if (zw>360) zw-=360;


/* number keys determine stepping for movement */
if ((ch>49) && (ch<58))
        step=ch-48;

/* page flip to the new screen 
hscreen=altscreen;
altscreen=oldscreen;
oldscreen=hscreen;

Setscreen(altscreen,oldscreen,-1L);
*/ 
} /* while */

} /* end of main */


/* finds points of polygon, and draws it( using a built-in polygon routine ) */

drawply(q)
int q;
{
int p1,p2,p3,p4;
int xyp[8];
int col;
int pat;
int ob;

p1=poly[q].a;
p2=poly[q].b;
p3=poly[q].c;
p4=poly[q].d; /* grabs point numbers */
ob=poly[q].own; /* which object owns this polygon */

xyp[0]=pic[ob][p1].x;
xyp[1]=pic[ob][p1].y;

xyp[2]=pic[ob][p2].x;
xyp[3]=pic[ob][p2].y;

xyp[4]=pic[ob][p3].x;
xyp[5]=pic[ob][p3].y;

xyp[6]=pic[ob][p4].x;
xyp[7]=pic[ob][p4].y; /* fills the polygon point coord array */

col=poly[q].color;  /* get color */
/* draw the polygon with xyp[] 

setcolor(col);

if (fill){
        setfillstyle(1,col);
        fillpoly(4,xyp); /* call system routine to draw poly */
        }
 else drawpoly(4,xyp);
*/


}



/* sort all polygons */

sortply()
{
int i,j;
long z1,z2,z3,z4,max;
POLY sav;
int ob;

for (i=0;i<NPOLY;i++)
        {
        ob=poly[i].own;
        /* calculate the middle Z's for depth sorting */
        z1=view[ob][ poly[i].a ].z;
        z2=view[ob][ poly[i].b ].z;
        z3=view[ob][ poly[i].c ].z;
        z4=view[ob][ poly[i].d ].z;
        poly[i].midz=(z1+z2+z3+z4) /4;

        }


/* simple sort */

for (i=0;i<NPOLY-1;i++)
        for(j=i+1;j<NPOLY;j++)
                if (poly[i].midz<poly[j].midz) 
                                {
                                sav=poly[i];
                                poly[i]=poly[j];
                                poly[j]=sav;
                                }

}

vizit()
{
int i;

for (i=0;i<NPOLY;i++)
        poly[i].viz=visible(i);
}

drawall()
{

int i;

/* first poly is closest */

for (i=NPOLY-1;i>=0;i--)
        if (poly[i].viz)     /* if visible, draw that polygon */
                drawply(i);
}



Point3 docalc(p)    /* takes a point and converts it based on view angles */
Point3 p;
{
Point3 res;
Point3 t;
Point3 des;

/* set up system to rotate around observer */

t.x=(p.x)-ox;
t.y=(p.y)-oy;
t.z=(p.z)-oz;

res.x=t.x;
res.y=t.y;
res.z=t.z;
/* more like an airplane if bank goes first */

des.x=dc2(res.x,zw)-ds2(res.y,zw);
des.y=dc2(res.y,zw)+ds2(res.x,zw);
res.x=des.x;
res.y=des.y;

/*pitch */
des.y=dc2(res.y,phi)-ds2(res.z,phi);
des.z=dc2(res.z,phi)+ds2(res.y,phi);
res.y=des.y;
res.z=des.z;

/* heading */

des.x=dc2(res.x,theta)-ds2(res.z,theta);
des.z=dc2(res.z,theta)+ds2(res.x,theta);
res.x=des.x;
res.z=-des.z;
 
return (res);
}



visible(q)
int q;
{
Point3 P,Q,S,R;
long c;
char out[40];
int ob;


ob=poly[q].own;
/* find surface normal */
/* requires  polygon points to be ordered clockwise */
/* while looking straight on to the visible side of the polygon */

P.x=view[ob] [ poly[q].b ].x - view[ob] [ poly[q].a].x;
P.y=view[ob][ poly[q].b ].y - view[ob][ poly[q].a].y;
P.z=view[ob][ poly[q].b ].z - view[ob][ poly[q].a].z;


Q.x=view[ob][ poly[q].c ].x - view[ob][ poly[q].a].x;
Q.y=view[ob][ poly[q].c ].y - view[ob][ poly[q].a].y;
Q.z=view[ob][ poly[q].c ].z - view[ob][ poly[q].a].z;


R.x=P.y*Q.z-P.z*Q.y;
R.y=P.z*Q.x-P.x*Q.z;
R.z=P.x*Q.y-P.y*Q.x;
/* find vector from eye to polygon */

S.x=-view[ob][ poly[q].a ].x;
S.y=-view[ob][ poly[q].a ].y;
S.z=-view[ob][ poly[q].a ].z;
/* calculate scalar product */

c= (long)S.x*(long)R.x+(long)S.y*(long)R.y+(long)S.z*(long)R.z;
/* if the result is greater than one, the two vectors face in the 
general same direction */


if (c<0) return 1;

/* face turned away from viewer */
return 0;
}





/* load in the objects from file plot.dat */
loaddat()
{
FILE *fdata;
int i,j;
int ob;
int pc=0;

fdata=fopen("plot.dat","rb");
if (!fdata) exit(10);

fscanf(fdata,"%d",&NO);  /* read in number of objects */
for (ob=0;ob<NO;ob++)
{
        fscanf(fdata,"%d",&NP[ob]); /*read in #points for this object */
      fscanf(fdata,"%ld %ld %ld",&objc[ob].x,&objc[ob].y,&objc[ob].z);  
        for (i=0;i<NP[ob];i++)
                fscanf(fdata,"%ld %ld %ld",&objv[ob][i].x,&objv[ob][i].y,&objv[ob][i].z);


        fscanf(fdata,"%d",&NL[ob]);   /* number of polygons */

        for(i=0;i<NL[ob];i++)
                {
               fscanf(fdata,"%d %d %d %d %d",&poly[pc].a,&poly[pc].b,&poly[pc].c,&poly[pc].d,&poly[pc].color);
                poly[pc].own=ob;  /* give this polygon an owner */
                pc++;
                }

} /* object loop */

NPOLY=pc; /* set global */


fclose(fdata);
}






/*************************** CUT HERE ************************/
/**   the int math module, so you can change the math easier */
/** if you want to that is.                                  */
/** cut out and name it longmath or something like that      */
/*************************************************************/


#include <math.h>

long sintab[361];
long ds2();
long dc2();
long Sin2();
long Cos2();



long ds2(w,d)
long w;
int d;

{
long l;

l=w*Sin2(d);

return( l/16384);
}

long dc2(w,d)
long w;
int d;
{
long l;

l=w*Cos2(d);

return( l/16384);
}


long Sin2(deg)
int deg;
{

if (deg<0) deg+=360;
return( sintab[deg] );

}

long Cos2(deg)
int deg;
{

return( Sin2(90-deg) );

}



   
#define DTOR  0.017453

makesintab()
{
int i;
long t;
double d,d2;

for (i=0;i<=360;i++)
        {
        d=i;
        d2=sin(DTOR*d)*16384;
        t=(long)d2;
        sintab[i]=t;
        }

}