2 * Elite - The New Kind.
4 * Reverse engineered from the BBC disk version of Elite.
5 * Additional material by C.J.Pinder.
7 * The original Elite code is (C) I.Bell & D.Braben 1984.
8 * This version re-engineered in C by C.J.Pinder 1999-2001.
10 * email: <christian@newkind.co.uk>
31 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
34 #define LAND_X_MAX 128
35 #define LAND_Y_MAX 128
37 static unsigned char landscape[LAND_X_MAX+1][LAND_Y_MAX+1];
39 static struct point point_list[100];
43 * The following routine is used to draw a wireframe represtation of a ship.
45 * caveat: it is a work in progress.
46 * A number of features (such as not showing detail at distance) have not yet been implemented.
50 void draw_wireframe_ship (struct univ_object *univ)
61 struct ship_face_normal *ship_norm;
63 struct ship_data *ship;
66 ship = ship_list[univ->type];
68 for (i = 0; i < 3; i++)
69 trans_mat[i] = univ->rotmat[i];
71 camera_vec = univ->location;
72 mult_vector (&camera_vec, trans_mat);
73 camera_vec = unit_vector (&camera_vec);
75 num_faces = ship->num_faces;
77 for (i = 0; i < num_faces; i++)
79 ship_norm = ship->normals;
81 vec.x = ship_norm[i].x;
82 vec.y = ship_norm[i].y;
83 vec.z = ship_norm[i].z;
85 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
89 vec = unit_vector (&vec);
90 cos_angle = vector_dot_product (&vec, &camera_vec);
91 visible[i] = (cos_angle < -0.2);
96 trans_mat[0].y = trans_mat[1].x;
100 trans_mat[0].z = trans_mat[2].x;
101 trans_mat[2].x = tmp;
103 tmp = trans_mat[1].z;
104 trans_mat[1].z = trans_mat[2].y;
105 trans_mat[2].y = tmp;
107 for (i = 0; i < ship->num_points; i++)
109 vec.x = ship->points[i].x;
110 vec.y = ship->points[i].y;
111 vec.z = ship->points[i].z;
113 mult_vector (&vec, trans_mat);
115 rx = vec.x + univ->location.x;
116 ry = vec.y + univ->location.y;
117 rz = vec.z + univ->location.z;
119 sx = (rx * 256) / rz;
120 sy = (ry * 256) / rz;
130 point_list[i].x = sx;
131 point_list[i].y = sy;
135 for (i = 0; i < ship->num_lines; i++)
137 if (visible[ship->lines[i].face1] ||
138 visible[ship->lines[i].face2])
140 sx = point_list[ship->lines[i].start_point].x;
141 sy = point_list[ship->lines[i].start_point].y;
143 ex = point_list[ship->lines[i].end_point].x;
144 ey = point_list[ship->lines[i].end_point].y;
146 gfx_draw_line (sx, sy, ex, ey);
151 if (univ->flags & FLG_FIRING)
153 lasv = ship_list[univ->type]->front_laser;
154 gfx_draw_line (point_list[lasv].x, point_list[lasv].y,
155 univ->location.x > 0 ? 0 : 511, rand255() * 2);
163 * Hacked version of the draw ship routine to display solid ships...
164 * This needs a lot of tidying...
166 * Check for hidden surface supplied by T.Harte.
169 void draw_solid_ship (struct univ_object *univ)
175 struct vector camera_vec;
177 struct ship_face *face_data;
182 struct ship_solid *solid_data;
183 struct ship_data *ship;
188 solid_data = &ship_solids[univ->type];
189 ship = ship_list[univ->type];
191 for (i = 0; i < 3; i++)
192 trans_mat[i] = univ->rotmat[i];
194 camera_vec = univ->location;
195 mult_vector (&camera_vec, trans_mat);
196 camera_vec = unit_vector (&camera_vec);
198 num_faces = solid_data->num_faces;
199 face_data = solid_data->face_data;
202 for (i = 0; i < num_faces; i++)
204 vec.x = face_data[i].norm_x;
205 vec.y = face_data[i].norm_y;
206 vec.z = face_data[i].norm_z;
208 vec = unit_vector (&vec);
209 cos_angle = vector_dot_product (&vec, &camera_vec);
211 visible[i] = (cos_angle < -0.13);
215 tmp = trans_mat[0].y;
216 trans_mat[0].y = trans_mat[1].x;
217 trans_mat[1].x = tmp;
219 tmp = trans_mat[0].z;
220 trans_mat[0].z = trans_mat[2].x;
221 trans_mat[2].x = tmp;
223 tmp = trans_mat[1].z;
224 trans_mat[1].z = trans_mat[2].y;
225 trans_mat[2].y = tmp;
228 for (i = 0; i < ship->num_points; i++)
230 vec.x = ship->points[i].x;
231 vec.y = ship->points[i].y;
232 vec.z = ship->points[i].z;
234 mult_vector (&vec, trans_mat);
236 rx = vec.x + univ->location.x;
237 ry = vec.y + univ->location.y;
238 rz = vec.z + univ->location.z;
243 sx = (rx * 256) / rz;
244 sy = (ry * 256) / rz;
254 point_list[i].x = sx;
255 point_list[i].y = sy;
256 point_list[i].z = rz;
260 for (i = 0; i < num_faces; i++)
262 if (((point_list[face_data[i].p1].x - point_list[face_data[i].p2].x) *
263 (point_list[face_data[i].p3].y - point_list[face_data[i].p2].y) -
264 (point_list[face_data[i].p1].y - point_list[face_data[i].p2].y) *
265 (point_list[face_data[i].p3].x - point_list[face_data[i].p2].x)) <= 0)
267 num_points = face_data[i].points;
269 poly_list[0] = point_list[face_data[i].p1].x;
270 poly_list[1] = point_list[face_data[i].p1].y;
271 zavg = point_list[face_data[i].p1].z;
273 poly_list[2] = point_list[face_data[i].p2].x;
274 poly_list[3] = point_list[face_data[i].p2].y;
275 zavg = MAX(zavg,point_list[face_data[i].p2].z);
279 poly_list[4] = point_list[face_data[i].p3].x;
280 poly_list[5] = point_list[face_data[i].p3].y;
281 zavg = MAX(zavg,point_list[face_data[i].p3].z);
286 poly_list[6] = point_list[face_data[i].p4].x;
287 poly_list[7] = point_list[face_data[i].p4].y;
288 zavg = MAX(zavg,point_list[face_data[i].p4].z);
293 poly_list[8] = point_list[face_data[i].p5].x;
294 poly_list[9] = point_list[face_data[i].p5].y;
295 zavg = MAX(zavg,point_list[face_data[i].p5].z);
300 poly_list[10] = point_list[face_data[i].p6].x;
301 poly_list[11] = point_list[face_data[i].p6].y;
302 zavg = MAX(zavg,point_list[face_data[i].p6].z);
307 poly_list[12] = point_list[face_data[i].p7].x;
308 poly_list[13] = point_list[face_data[i].p7].y;
309 zavg = MAX(zavg,point_list[face_data[i].p7].z);
314 poly_list[14] = point_list[face_data[i].p8].x;
315 poly_list[15] = point_list[face_data[i].p8].y;
316 zavg = MAX(zavg,point_list[face_data[i].p8].z);
320 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
325 if (univ->flags & FLG_FIRING)
327 lasv = ship_list[univ->type]->front_laser;
328 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
330 gfx_render_line (point_list[lasv].x, point_list[lasv].y,
331 univ->location.x > 0 ? 0 : 511, rand255() * 2,
332 point_list[lasv].z, col);
341 * Colour map used to generate a SNES Elite style planet.
342 * This is a quick hack and needs tidying up.
345 int snes_planet_colour[] =
358 249,249,249,249,249,249,
371 * Generate a landscape map for a SNES Elite style planet.
374 void generate_snes_landscape (void)
379 for (y = 0; y <= LAND_Y_MAX; y++)
381 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];
382 for (x = 0; x <= LAND_X_MAX; x++)
384 landscape[x][y] = colour;
393 * Guassian random number generator.
394 * Returns a number between -7 and +8 with Gaussian distribution.
403 for (i = 0; i < 12; i++)
414 * Calculate the midpoint between two given points.
417 int calc_midpoint (int sx, int sy, int ex, int ey)
421 a = landscape[sx][sy];
422 b = landscape[ex][ey];
424 n = ((a + b) / 2) + grand();
435 * Calculate a square on the midpoint map.
438 void midpoint_square (int tx, int ty, int w)
450 landscape[mx][ty] = calc_midpoint(tx,ty,bx,ty);
451 landscape[mx][by] = calc_midpoint(tx,by,bx,by);
452 landscape[tx][my] = calc_midpoint(tx,ty,tx,by);
453 landscape[bx][my] = calc_midpoint(bx,ty,bx,by);
454 landscape[mx][my] = calc_midpoint(tx,my,bx,my);
459 midpoint_square (tx,ty,d);
460 midpoint_square (mx,ty,d);
461 midpoint_square (tx,my,d);
462 midpoint_square (mx,my,d);
467 * Generate a fractal landscape.
468 * Uses midpoint displacement method.
471 void generate_fractal_landscape (int rnd_seed)
478 old_seed = get_rand_seed();
479 set_rand_seed(rnd_seed);
483 for (y = 0; y <= LAND_Y_MAX; y += d)
484 for (x = 0; x <= LAND_X_MAX; x += d)
485 landscape[x][y] = randint() & 255;
487 for (y = 0; y < LAND_Y_MAX; y += d)
488 for (x = 0; x < LAND_X_MAX; x += d)
489 midpoint_square (x,y,d);
491 for (y = 0; y <= LAND_Y_MAX; y++)
493 for (x = 0; x <= LAND_X_MAX; x++)
499 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
501 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
506 set_rand_seed (old_seed);
510 void generate_landscape (int rnd_seed)
512 switch (planet_render_style)
514 case 0: /* Wireframe... do nothing for now... */
518 /* generate_green_landscape (); */
522 generate_snes_landscape();
526 generate_fractal_landscape (rnd_seed);
534 * Draw a line of the planet with appropriate rotation.
538 void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
549 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
550 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
556 rx = -x * vx - y * vy;
557 ry = -x * vy + y * vx;
560 div = radius << 10; /* radius * 2 * LAND_X_MAX >> 16 */
563 for (; sx <= ex; sx++)
565 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
569 colour = landscape[lx][ly];
571 gfx_fast_plot_pixel (sx, sy, colour);
580 * Draw a solid planet. Based on Doros circle drawing alogorithm.
583 void render_planet (int xo, int yo, int radius, struct vector *vec)
592 vx = vec[1].x * 65536;
593 vy = vec[1].y * 65536;
602 render_planet_line (xo, yo, x, y, radius, vx, vy);
603 render_planet_line (xo, yo, x,-y, radius, vx, vy);
604 render_planet_line (xo, yo, y, x, radius, vx, vy);
605 render_planet_line (xo, yo, y,-x, radius, vx, vy);
619 * Draw a wireframe planet.
620 * At the moment we just draw a circle.
621 * Need to add in the two arcs that the original Elite had.
624 void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
626 gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
632 * We can currently do three different types of planet...
634 * - Fractal landscape.
635 * - SNES Elite style.
638 void draw_planet (struct univ_object *planet)
643 x = (planet->location.x * 256) / planet->location.z;
644 y = (planet->location.y * 256) / planet->location.z;
654 radius = 6291456 / planet->distance;
655 // radius = 6291456 / ship_vec.z; /* Planets are BIG! */
659 if ((x + radius < 0) ||
660 (x - radius > 511) ||
665 switch (planet_render_style)
668 draw_wireframe_planet (x, y, radius, planet->rotmat);
672 gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
677 render_planet (x, y, radius, planet->rotmat);
683 void render_sun_line (int xo, int yo, int x, int y, int radius)
694 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
695 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
701 sx -= (radius * (2 + (randint() & 7))) >> 8;
702 ex += (radius * (2 + (randint() & 7))) >> 8;
704 if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
705 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
708 if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
709 sx = GFX_VIEW_TX + GFX_X_OFFSET;
711 if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
712 ex = GFX_VIEW_BX + GFX_X_OFFSET;
714 inner = (radius * (200 + (randint() & 7))) >> 8;
717 inner2 = (radius * (220 + (randint() & 7))) >> 8;
720 outer = (radius * (239 + (randint() & 7))) >> 8;
726 for (; sx <= ex; sx++,dx++)
729 distance = dx * dx + dy;
731 if (distance < inner)
732 colour = GFX_COL_WHITE;
733 else if (distance < inner2)
734 colour = GFX_COL_YELLOW_4;
735 else if (distance < outer)
736 colour = GFX_ORANGE_3;
738 colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
740 gfx_fast_plot_pixel (sx, sy, colour);
745 void render_sun (int xo, int yo, int radius)
760 render_sun_line (xo, yo, x, y, radius);
761 render_sun_line (xo, yo, x,-y, radius);
762 render_sun_line (xo, yo, y, x, radius);
763 render_sun_line (xo, yo, y,-x, radius);
777 void draw_sun (struct univ_object *planet)
782 x = (planet->location.x * 256) / planet->location.z;
783 y = (planet->location.y * 256) / planet->location.z;
793 radius = 6291456 / planet->distance;
797 if ((x + radius < 0) ||
798 (x - radius > 511) ||
803 render_sun (x, y, radius);
808 void draw_explosion (struct univ_object *univ)
816 int sizex,sizey,psx,psy;
822 struct vector camera_vec;
825 struct ship_face_normal *ship_norm;
826 struct ship_point *sp;
827 struct ship_data *ship;
832 if (univ->exp_delta > 251)
834 univ->flags |= FLG_REMOVE;
838 univ->exp_delta += 4;
840 if (univ->location.z <= 0)
843 ship = ship_list[univ->type];
845 for (i = 0; i < 3; i++)
846 trans_mat[i] = univ->rotmat[i];
848 camera_vec = univ->location;
849 mult_vector (&camera_vec, trans_mat);
850 camera_vec = unit_vector (&camera_vec);
852 ship_norm = ship->normals;
854 for (i = 0; i < ship->num_faces; i++)
856 vec.x = ship_norm[i].x;
857 vec.y = ship_norm[i].y;
858 vec.z = ship_norm[i].z;
860 vec = unit_vector (&vec);
861 cos_angle = vector_dot_product (&vec, &camera_vec);
863 visible[i] = (cos_angle < -0.13);
866 tmp = trans_mat[0].y;
867 trans_mat[0].y = trans_mat[1].x;
868 trans_mat[1].x = tmp;
870 tmp = trans_mat[0].z;
871 trans_mat[0].z = trans_mat[2].x;
872 trans_mat[2].x = tmp;
874 tmp = trans_mat[1].z;
875 trans_mat[1].z = trans_mat[2].y;
876 trans_mat[2].y = tmp;
881 for (i = 0; i < ship->num_points; i++)
883 if (visible[sp[i].face1] || visible[sp[i].face2] ||
884 visible[sp[i].face3] || visible[sp[i].face4])
890 mult_vector (&vec, trans_mat);
892 rx = vec.x + univ->location.x;
893 ry = vec.y + univ->location.y;
894 rz = vec.z + univ->location.z;
896 sx = (rx * 256) / rz;
897 sy = (ry * 256) / rz;
907 point_list[np].x = sx;
908 point_list[np].y = sy;
914 z = (int)univ->location.z;
921 pr = (univ->exp_delta * 256) / q;
929 old_seed = get_rand_seed();
930 set_rand_seed (univ->exp_seed);
932 for (cnt = 0; cnt < np; cnt++)
934 sx = point_list[cnt].x;
935 sy = point_list[cnt].y;
937 for (i = 0; i < 16; i++)
939 px = rand255() - 128;
940 py = rand255() - 128;
948 sizex = (randint() & 1) + 1;
949 sizey = (randint() & 1) + 1;
951 for (psy = 0; psy < sizey; psy++)
952 for (psx = 0; psx < sizex; psx++)
953 gfx_plot_pixel (px+psx, py+psy, GFX_COL_WHITE);
957 set_rand_seed (old_seed);
963 * Draws an object in the universe.
964 * (Ship, Planet, Sun etc).
967 void draw_ship (struct univ_object *ship)
970 if ((current_screen != SCR_FRONT_VIEW) && (current_screen != SCR_REAR_VIEW) &&
971 (current_screen != SCR_LEFT_VIEW) && (current_screen != SCR_RIGHT_VIEW) &&
972 (current_screen != SCR_INTRO_ONE) && (current_screen != SCR_INTRO_TWO) &&
973 (current_screen != SCR_GAME_OVER) && (current_screen != SCR_ESCAPE_POD))
976 if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
978 ship->flags |= FLG_EXPLOSION;
979 ship->exp_seed = randint();
980 ship->exp_delta = 18;
983 if (ship->flags & FLG_EXPLOSION)
985 draw_explosion (ship);
989 if (ship->location.z <= 0) /* Only display ships in front of us. */
992 if (ship->type == SHIP_PLANET)
998 if (ship->type == SHIP_SUN)
1004 if ((fabs(ship->location.x) > ship->location.z) || /* Check for field of vision. */
1005 (fabs(ship->location.y) > ship->location.z))
1009 draw_wireframe_ship (ship);
1011 draw_solid_ship (ship);