← Back to contents
C source, ASCII text
— 15K bytes
— 1994-01-01
/*
------------------------------------------------------------------
Black Nebula
File : 3drout.c
Programmer: Colin Adams
Date: 4/3/91
Last Modified : 10/6/91
------------------------------------------------------------------
*/
#define D3ROUT
#define AMIGA_INCLUDES
#include "3d.h"
extern object myship;
extern short swapflag, U_rot;
extern short num_active[];
extern struct BitMap my_bit_map;
extern struct BitMap back_bit_map;
short store1 = 0, store2 = 0;
/* ------------------------------------------------------------------
Fast Sin/Cos Routines
------------------------------------------------------------------
*/
double deg(int degrees)
/* converts degrees to radians */
{
double test = degrees;
double one8 = 180;
return 3.141592654/(one8/test);
}
void TrigSetUp(void)
{
register int i;
FILE *fp;
if(!(fp=fopen("trig.pre","r")))
{
printf("Creating trig tables...\n");
for(i=0; i<=90; i++)
{
sintable[i] = ((double) sin(deg(i)) * 65536);
costable[i] = ((double) cos(deg(i)) * 65536);
}
/* precalculate sin/cos for all quadrants */
for(i=91; i<=360; i++)
{
short six = 0, cix = 0, rot = i;
if(rot>=271)
{
rot = 360 - rot;
six = 1;
}
else if(rot>=181)
{
rot -= 180;
six = cix = 1;
}
else if(rot>=91)
{
rot = 180 - rot;
cix = 1;
}
cix = cix ? -1 : 1;
six = six ? -1 : 1;
sintable[i] = ((double) sin(deg(rot)) * 65536)*six;
costable[i] = ((double) cos(deg(rot)) * 65536)*cix;
}
printf("Saving...\n");
if(!(fp = fopen("trig.pre","w")))
{
printf("Failed to save trig data!!!\n");
return;
}
fwrite((void *) &sintable[0], sizeof(int), 361, fp);
fwrite((void *) &costable[0], sizeof(int), 361, fp);
fclose(fp);
}
else
{
fread((void *) &sintable[0], sizeof(int), 361, fp);
fread((void *) &costable[0], sizeof(int), 361, fp);
fclose(fp);
}
}
/* ------------------------------------------------------------------
Random Number Functions
------------------------------------------------------------------
*/
void SetRandom(void)
{
long t;
time(&t);
srand((int) t);
}
int getrandom(int a, int b)
{
return (rand() % (1+b-a)) + a;
}
/* ------------------------------------------------------------------
Routines for Object Manipulation
------------------------------------------------------------------
*/
void Rotate_Obj_Abs(object *obj, short x, short y, short z)
{
obj->rot_x = x;
obj->rot_y = y;
obj->rot_z = z;
}
void Rotate_Obj_Rel(object *obj, short x, short y, short z)
{
if((obj->rot_x += x)>=360)
obj->rot_x -= 360;
else if(obj->rot_x<0)
obj->rot_x += 360;
if((obj->rot_y += y)>=360)
obj->rot_y -= 360;
else if(obj->rot_y<0)
obj->rot_y += 360;
if((obj->rot_z += z)>=360)
obj->rot_z -= 360;
else if(obj->rot_z<0)
obj->rot_z += 360;
}
void Translate_Obj_Abs(object *obj, short x, short y, short z)
{
obj->trans_x = x;
obj->trans_y = y;
obj->trans_z = z;
}
void Translate_Obj_Rel(object *obj, short x, short y, short z)
{
obj->trans_x += x;
obj->trans_y += y;
obj->trans_z += z;
}
void Destroy_Object(object *obj)
/* pretty obvious what this does */
{
polygon *p, *nextp;
p = obj->poly;
while(p)
{
nextp = (polygon *) p->next;
free(p);
p = nextp;
}
free(obj);
}
void Save_Object(object *obj, char *filename)
{
FILE *fp;
polygon *p;
int zero = 0, one = 1;
if(!(fp=fopen(filename,"w")))
{
printf("Disk Error : Couldn't open the file for output!\n");
return;
}
fwrite((void *) &(obj->type), sizeof(char), 1, fp);
fwrite((void *) &(obj->start_x), sizeof(short), 1, fp);
fwrite((void *) &(obj->start_y), sizeof(short), 1, fp);
fwrite((void *) &(obj->start_z), sizeof(short), 1, fp);
fwrite((void *) &(obj->numpoints), sizeof(short), 1, fp);
fwrite((void *) &(obj->radius), sizeof(short), 1, fp);
fwrite((void *) &(obj->objpoints[0]), sizeof(point), MAX_OBJ_POINTS, fp);
p = obj->poly;
while(p)
{
fwrite((void *) &one, sizeof(int), 1, fp);
fwrite((void *) &(p->numpoints), sizeof(char), 1, fp);
fwrite((void *) &(p->colour), sizeof(short), 1, fp);
fwrite((void *) &(p->centre), sizeof(point), 1, fp);
fwrite((void *) &(p->p[0]), sizeof(short), MAX_POINTS, fp);
p = (polygon *) p->next;
}
fwrite((void *) &zero, sizeof(int), 1, fp);
fclose(fp);
printf("Object saved to file.\n");
}
int Load_Object(object *obj, char *filename)
{
FILE *fp;
polygon *p;
int i;
if(!(fp=fopen(filename,"r")))
{
printf("Disk Error : Couldn't open the file for input!\n");
return 0;
}
fread((void *) &(obj->type), sizeof(char), 1, fp);
fread((void *) &(obj->start_x), sizeof(short), 1, fp);
fread((void *) &(obj->start_y), sizeof(short), 1, fp);
fread((void *) &(obj->start_z), sizeof(short), 1, fp);
fread((void *) &(obj->numpoints), sizeof(short), 1, fp);
fread((void *) &(obj->radius), sizeof(short), 1, fp);
fread((void *) &(obj->objpoints[0]), sizeof(point), MAX_OBJ_POINTS, fp);
fread((void *) &i, sizeof(int), 1, fp);
if(i)
{
obj->poly = (polygon *) malloc(sizeof(polygon));
p = obj->poly;
fread((void *) &(p->numpoints), sizeof(char), 1, fp);
fread((void *) &(p->colour), sizeof(short), 1, fp);
fread((void *) &(p->centre), sizeof(point), 1, fp);
fread((void *) &(p->p[0]), sizeof(short), MAX_POINTS, fp);
fread((void *) &i, sizeof(int), 1, fp);
while(i)
{
p->last_num = p->clip_num = p->last_num2 = 0;
p->next = (polygon *) malloc(sizeof(polygon));
p = (polygon *) p->next;
fread((void *) &(p->numpoints), sizeof(char), 1, fp);
fread((void *) &(p->colour), sizeof(short), 1, fp);
fread((void *) &(p->centre), sizeof(point), 1, fp);
fread((void *) &(p->p[0]), sizeof(short), MAX_POINTS, fp);
fread((void *) &i, sizeof(int), 1, fp);
}
p->next = NULL;
}
fclose(fp);
return 1;
}
object *CreateObject(void)
{
object *obj;
if(!(obj = (object *) malloc(sizeof(object))))
{
printf("Fatal Error : Not enough memory!\n");
CleanUpandExit();
}
obj->poly = NULL;
obj->start_x = obj->start_y = obj->start_z = 0;
obj->type = obj->centre_x = obj->centre_y = obj->centre_z = 0;
obj->trans_x = obj->trans_y = obj->trans_z = 500;
obj->rot_x = obj->rot_y = obj->rot_z = 0;
obj->velocity = 5;
obj->heading = 0;
return obj;
}
void AddPoly(object *obj, polygon *p)
{
polygon *point = obj->poly;
if(point)
{
while(point->next)
point = (polygon *) point->next;
point->next = p;
p->next = NULL;
}
else
{
obj->poly = p;
p->next = NULL;
}
}
void SpinThatObject(object *obj)
/*
Spins an object around the axies. Seems to be a bottleneck, so will
have to be converted to 68k. Anyone with a faster algorithm please tell
me, as this is the fastest one I know.
*/
{
register short i;
register short xrot = obj->rot_x;
register short yrot = obj->rot_y;
register short zrot = obj->rot_z;
for(i=1; i<=obj->numpoints; i++)
{
register int x,y,z;
x = obj->objpoints[i].x;
y = obj->objpoints[i].y;
z = obj->objpoints[i].z;
/* rotate a point around the z axis */
if(zrot)
{
register int temp, temp2, temp3;
temp = x;
temp2 = costable[zrot];
temp3 = sintable[zrot];
x = ((temp2*temp)>>16) - ((temp3*y)>>16);
y = ((temp3*temp)>>16) + ((temp2*y)>>16);
}
/* rotate a point around the x axis */
if(xrot)
{
register int temp, temp2, temp3;
temp = y;
temp2 = costable[xrot];
temp3 = sintable[xrot];
y = ((temp2*temp)>>16) - ((temp3*z)>>16);
z = ((temp3*temp)>>16) + ((temp2*z)>>16);
}
/* rotate a point around the y axis */
if(yrot)
{
register int temp, temp2, temp3;
temp = z;
temp2 = costable[yrot];
temp3 = sintable[yrot];
z = ((temp2*temp)>>16) - ((temp3*x)>>16);
x = ((temp3*temp)>>16) + ((temp2*x)>>16);
}
/* move back to points */
manipulate_x[i] = x;
manipulate_y[i] = y;
manipulate_z[i] = z;
}
}
void SpinObjCentres(void)
/* another use of my rotate code */
{
register short i;
for(i=0; i<no_objects; i++)
{
register object *obj = active_list[i];
register int x,y,z;
register short xrot = obj->rot_x;
register short yrot = obj->rot_y;
register short zrot = obj->rot_z;
x = obj->start_x;
y = obj->start_y;
z = obj->start_z;
/* rotate a point around the z axis */
if(zrot)
{
register int temp, temp2, temp3;
temp = x;
temp2 = costable[zrot];
temp3 = sintable[zrot];
x = ((temp2*temp)>>16) - ((temp3*y)>>16);
y = ((temp3*temp)>>16) + ((temp2*y)>>16);
}
/* rotate a point around the x axis */
if(xrot)
{
register int temp, temp2, temp3;
temp = y;
temp2 = costable[xrot];
temp3 = sintable[xrot];
y = ((temp2*temp)>>16) - ((temp3*z)>>16);
z = ((temp3*temp)>>16) + ((temp2*z)>>16);
}
/* rotate a point around the y axis */
if(yrot)
{
register int temp, temp2, temp3;
temp = z;
temp2 = costable[yrot];
temp3 = sintable[yrot];
z = ((temp2*temp)>>16) - ((temp3*x)>>16);
x = ((temp3*temp)>>16) + ((temp2*x)>>16);
}
/* move back to points */
obj->centre_x = x;
obj->centre_y = y;
obj->centre_z = z;
}
}
void PrepareObject(object *obj)
{
polygon *pg = obj->poly;
register short i;
if(!(obj->drawme))
return;
SpinThatObject(obj);
for(i=1; i<=obj->numpoints; i++) /* do translation */
{
manipulate_x[i] += obj->trans_x;
manipulate_y[i] += obj->trans_y;
manipulate_z[i] += obj->trans_z;
}
DepthSort(obj); /* sort polygons by depth from eye */
/* convert all points in object to 2d */
for(i=1; i<=obj->numpoints; i++)
{
get2d(manipulate_x[i], manipulate_y[i], manipulate_z[i]);
obj->pointx[i] = x;
obj->pointy[i] = y;
}
/* work out what points are in each polygon, then clip them */
while(pg)
{
for(i=0; i<pg->numpoints; i++)
{
pg->x[i] = obj->pointx[pg->p[i]];
pg->y[i] = obj->pointy[pg->p[i]];
}
if(!pg->back_face)
polygon_clip(pg); /* creates a new polygon clipped */
pg = (polygon *) pg->next;
}
}
void DrawObject(object *obj)
/* can only be used on an object that has already been clipped and
arranged in drawing order */
{
register int j = 0;
register polygon *pg;
pg = obj->draworder[j];
obj->lastdraw2 = obj->lastdrawme;
obj->lastdrawme = obj->drawme;
if(!(obj->drawme))
return;
while(pg) /* list is only terminated with a NULL */
{
register int i;
if(!pg->back_face)
{
SetAPen(rastport, pg->colour);
MoveTo(pg->clip_x[0], pg->clip_y[0]);
for(i=1; i<pg->clip_num; i++)
DrawTo(pg->clip_x[i], pg->clip_y[i]);
FillArea();
}
if(swapflag)
{
store1 = 1;
pg->last_num = pg->clip_num;
for(i=0; i<pg->clip_num; i++)
{
pg->last_x[i] = pg->clip_x[i];
pg->last_y[i] = pg->clip_y[i];
}
}
else
{
store2 = 1;
pg->last_num2 = pg->clip_num;
for(i=0; i<pg->clip_num; i++)
{
pg->last_x2[i] = pg->clip_x[i];
pg->last_y2[i] = pg->clip_y[i];
}
}
j++;
pg = obj->draworder[j];
}
}
void EraseObject(object *obj)
/* can only be used on an object that has already been drawn */
{
polygon *pg;
if(!(obj->lastdraw2))
return;
pg = obj->poly;
SetAPen(rastport, 0);
if(swapflag)
{
if(store1)
{
while(pg)
{
register int i;
if(pg->last_num)
{
MoveTo(pg->last_x[0], pg->last_y[0]);
for(i=1; i<pg->last_num; i++)
DrawTo(pg->last_x[i], pg->last_y[i]);
FillArea();
}
pg = (polygon *) pg->next;
}
}
}
else
{
if(store2)
{
while(pg)
{
register int i;
if(pg->last_num2)
{
MoveTo(pg->last_x2[0], pg->last_y2[0]);
for(i=1; i<pg->last_num2; i++)
DrawTo(pg->last_x2[i], pg->last_y2[i]);
FillArea();
}
pg = (polygon *) pg->next;
}
}
}
}
void AddObject(char *filename, short type)
{
object *obj;
int i;
for(i=0; i<MAX_OBJECTS; i++)
{
obj = CreateObject();
if(!(Load_Object(obj, filename)))
{
printf("Failed to load %s\n",filename);
free(obj);
return;
}
memcpy(&obj_types[type][i], obj, sizeof(object));
free(obj);
}
}
void SetUpExplosions(void)
{
int i;
for(i=0; i<MAX_EXPLOSIONS; i++)
{
explosions[i].type = EXPLOSION;
explosions[i].radius = 2500;
if(!(explosions[i].poly = malloc(sizeof(polygon))))
{
printf("Error creating explosions!\n");
CleanUpandExit();
}
explosions[i].poly->next = NULL;
explosions[i].poly->last_num = explosions[i].poly->last_num2 = 0;
}
}
void AddNewObject(short type, short x, short y, short z)
{
register int i;
register object *obj;
for(i=0; i<MAX_OBJECTS; i++)
{
if(!obj_free[type][i])
{
obj = &obj_types[type][i];
Translate_Obj_Abs(obj, x, y, z);
obj->i_am_dying = obj->lastdrawme = obj->lastdraw2 = 0;
obj->timeinflight = 0;
if(type==MYMISSILE || type==GUIDEDMISSILE)
{
obj->velocity = 30;
obj->heading = View_Angle;
obj->target = NULL;
if(type==MYMISSILE)
Rotate_Obj_Abs(obj, 0, View_Angle, 180);
else
Rotate_Obj_Abs(obj, 0, View_Angle, 0);
}
if(type==PLAYER || type==MAMBA)
Rotate_Obj_Abs(obj, 90, 0, 0);
obj->explode = 0;
obj_free[type][i] = 1;
active_list[no_objects] = obj;
no_objects++;
num_active[type]++;
return;
}
}
}
void KillAllObjects(void)
{
unsigned char i, j;
for(j=0; j<NO_OBJ_TYPES; j++)
{
for(i=0; i<MAX_OBJECTS; i++)
obj_free[j][i] = 0;
num_active[j] = 0;
}
for(i=0; i<MAX_EXPLOSIONS; i++)
exp_free[i] = 0;
no_objects = 0;
am_i_dead = 0;
}
void CreateExplosion(object *obj)
/*
Cool routine to blow an object into it's polygons. Takes a while though,
so I'll have to fix it up a bit. Looks damn nice though...
*/
{
register int i, j = 0;
register polygon *pg = obj->poly;
while(pg)
{
for(i=j; i<MAX_EXPLOSIONS; i++)
{
if(!exp_free[i]) /* is free ! */
{
register int n;
explosions[i].lastdrawme = explosions[i].lastdraw2 = 0;
explosions[i].drawme = 1;
explosions[i].explode = 0;
explosions[i].i_am_dying = 0;
explosions[i].type = EXPLOSION;
explosions[i].centre_x = pg->centre.x;
explosions[i].centre_y = pg->centre.y;
explosions[i].centre_z = pg->centre.z;
explosions[i].timeinflight = getrandom(5,25); /* time will last */
explosions[i].poly->numpoints = explosions[i].numpoints =
pg->numpoints;
explosions[i].poly->colour = pg->colour;
explosions[i].poly->centre = pg->centre;
for(n=0; n<pg->numpoints; n++)
explosions[i].poly->p[n] = n + 1;
for(n=1; n<=pg->numpoints; n++)
explosions[i].objpoints[n] = obj->objpoints[pg->p[n-1]];
Translate_Obj_Abs(&explosions[i], obj->trans_x,
obj->trans_y, obj->trans_z);
Rotate_Obj_Abs(&explosions[i], obj->rot_x,
obj->rot_y, obj->rot_z);
explosions[i].velocity = getrandom(0,10);
explosions[i].heading = getrandom(0,360);
explosions[i].up_or_down = getrandom(0,2);
exp_free[i] = 1; /* not free */
active_list[no_objects] = &explosions[i];
no_objects++;
break;
}
}
j = i; /* by doing this, I can search in order n instead of n^2 */
pg = (polygon *) pg->next;
}
StartSound(1);
}
/* end of module */