/* ------------------------------------------------------------------ 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; irot_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; inumpoints; 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; iclip_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; iclip_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; iclip_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; ilast_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; ilast_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; inext = 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; ii_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; jpoly; while(pg) { for(i=j; icentre.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; nnumpoints; 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 */