Add restart game option, and remapped keys setting.
[newkind] / threed.c
CommitLineData
84bbd123 1/*
2 * Elite - The New Kind.
3 *
4 * Reverse engineered from the BBC disk version of Elite.
5 * Additional material by C.J.Pinder.
6 *
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.
9 *
10 * email: <christian@newkind.co.uk>
11 *
12 */
13
14#include <string.h>
15#include <stdlib.h>
16#include <stdio.h>
17#include <math.h>
18#include <ctype.h>
19
20#include "config.h"
21#include "elite.h"
22#include "gfx.h"
23#include "planet.h"
24#include "vector.h"
25#include "shipdata.h"
26#include "shipface.h"
27#include "threed.h"
28#include "space.h"
29#include "random.h"
30
31#define MAX(x,y) (((x) > (y)) ? (x) : (y))
32
33
34#define LAND_X_MAX 128
35#define LAND_Y_MAX 128
36
37static unsigned char landscape[LAND_X_MAX+1][LAND_Y_MAX+1];
38
39static struct point point_list[100];
40
1a8abebd 41static void identify_ship(struct univ_object *univ)
42{
43 char buf[64];
44 int lasv;
45
46 lasv = ship_list[univ->type]->front_laser;
47 if (!(univ->flags & FLG_TACTICAL)) {
48#ifdef HACKING
49 unsigned flags = univ->flags;
50 sprintf(buf, "%s %s%s%s%s", ship_list[univ->type]->name,
51 (flags & FLG_ANGRY) ? "A" : "",
52 (flags & FLG_TARGET) ? "T" : "",
53 (flags & FLG_HOSTILE) ? "H" : "",
54 (flags & FLG_POLICE) ? "P" : "");
55#else
56 sprintf(buf, "%s", ship_list[univ->type]->name);
57#endif
58 } else {
59#ifdef HACKING
60 unsigned flags = univ->flags;
61 sprintf(buf, "%s (%d) %s%s%s%s", ship_list[univ->type]->name,
62 univ->energy,
63 (flags & FLG_ANGRY) ? "A" : "",
64 (flags & FLG_TARGET) ? "T" : "",
65 (flags & FLG_HOSTILE) ? "H" : "",
66 (flags & FLG_POLICE) ? "P" : "");
67#else
68 sprintf(buf, "%s (%d)", ship_list[univ->type]->name, univ->energy);
69#endif
70 }
71 gfx_display_text(point_list[lasv].x + 4, point_list[lasv].y + 4, buf);
72}
84bbd123 73
74/*
75 * The following routine is used to draw a wireframe represtation of a ship.
76 *
77 * caveat: it is a work in progress.
78 * A number of features (such as not showing detail at distance) have not yet been implemented.
79 *
80 */
81
82void draw_wireframe_ship (struct univ_object *univ)
83{
84 Matrix trans_mat;
85 int i;
86 int sx,sy,ex,ey;
87 double rx,ry,rz;
88 int visible[32];
89 Vector vec;
90 Vector camera_vec;
91 double cos_angle;
92 double tmp;
93 struct ship_face_normal *ship_norm;
94 int num_faces;
95 struct ship_data *ship;
96 int lasv;
97
98 ship = ship_list[univ->type];
99
100 for (i = 0; i < 3; i++)
101 trans_mat[i] = univ->rotmat[i];
102
103 camera_vec = univ->location;
104 mult_vector (&camera_vec, trans_mat);
105 camera_vec = unit_vector (&camera_vec);
106
107 num_faces = ship->num_faces;
108
109 for (i = 0; i < num_faces; i++)
110 {
111 ship_norm = ship->normals;
112
113 vec.x = ship_norm[i].x;
114 vec.y = ship_norm[i].y;
115 vec.z = ship_norm[i].z;
116
117 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
118 visible[i] = 1;
119 else
120 {
121 vec = unit_vector (&vec);
122 cos_angle = vector_dot_product (&vec, &camera_vec);
123 visible[i] = (cos_angle < -0.2);
124 }
125 }
126
127 tmp = trans_mat[0].y;
128 trans_mat[0].y = trans_mat[1].x;
129 trans_mat[1].x = tmp;
130
131 tmp = trans_mat[0].z;
132 trans_mat[0].z = trans_mat[2].x;
133 trans_mat[2].x = tmp;
134
135 tmp = trans_mat[1].z;
136 trans_mat[1].z = trans_mat[2].y;
137 trans_mat[2].y = tmp;
138
139 for (i = 0; i < ship->num_points; i++)
140 {
141 vec.x = ship->points[i].x;
142 vec.y = ship->points[i].y;
143 vec.z = ship->points[i].z;
144
145 mult_vector (&vec, trans_mat);
146
147 rx = vec.x + univ->location.x;
148 ry = vec.y + univ->location.y;
149 rz = vec.z + univ->location.z;
150
151 sx = (rx * 256) / rz;
152 sy = (ry * 256) / rz;
153
154 sy = -sy;
155
156 sx += 128;
157 sy += 96;
158
159 sx *= GFX_SCALE;
160 sy *= GFX_SCALE;
161
162 point_list[i].x = sx;
163 point_list[i].y = sy;
164
165 }
166
167 for (i = 0; i < ship->num_lines; i++)
168 {
169 if (visible[ship->lines[i].face1] ||
170 visible[ship->lines[i].face2])
171 {
172 sx = point_list[ship->lines[i].start_point].x;
173 sy = point_list[ship->lines[i].start_point].y;
174
175 ex = point_list[ship->lines[i].end_point].x;
176 ey = point_list[ship->lines[i].end_point].y;
177
178 gfx_draw_line (sx, sy, ex, ey);
179 }
180 }
181
182
183 if (univ->flags & FLG_FIRING)
184 {
185 lasv = ship_list[univ->type]->front_laser;
186 gfx_draw_line (point_list[lasv].x, point_list[lasv].y,
187 univ->location.x > 0 ? 0 : 511, rand255() * 2);
188 }
1a8abebd 189
190 if (identify)
191 identify_ship(univ);
84bbd123 192}
193
194
195
196
197/*
198 * Hacked version of the draw ship routine to display solid ships...
199 * This needs a lot of tidying...
200 *
201 * Check for hidden surface supplied by T.Harte.
202 */
203
204void draw_solid_ship (struct univ_object *univ)
205{
206 int i;
207 int sx,sy;
208 double rx,ry,rz;
209 struct vector vec;
210 struct vector camera_vec;
211 double tmp;
212 struct ship_face *face_data;
213 int num_faces;
214 int num_points;
215 int poly_list[16];
216 int zavg;
217 struct ship_solid *solid_data;
218 struct ship_data *ship;
219 Matrix trans_mat;
220 int lasv;
221 int col;
222
223 solid_data = &ship_solids[univ->type];
224 ship = ship_list[univ->type];
225
226 for (i = 0; i < 3; i++)
227 trans_mat[i] = univ->rotmat[i];
228
229 camera_vec = univ->location;
230 mult_vector (&camera_vec, trans_mat);
231 camera_vec = unit_vector (&camera_vec);
232
233 num_faces = solid_data->num_faces;
234 face_data = solid_data->face_data;
235
236/*
237 for (i = 0; i < num_faces; i++)
238 {
239 vec.x = face_data[i].norm_x;
240 vec.y = face_data[i].norm_y;
241 vec.z = face_data[i].norm_z;
242
243 vec = unit_vector (&vec);
244 cos_angle = vector_dot_product (&vec, &camera_vec);
245
246 visible[i] = (cos_angle < -0.13);
247 }
248*/
249
250 tmp = trans_mat[0].y;
251 trans_mat[0].y = trans_mat[1].x;
252 trans_mat[1].x = tmp;
253
254 tmp = trans_mat[0].z;
255 trans_mat[0].z = trans_mat[2].x;
256 trans_mat[2].x = tmp;
257
258 tmp = trans_mat[1].z;
259 trans_mat[1].z = trans_mat[2].y;
260 trans_mat[2].y = tmp;
261
262
263 for (i = 0; i < ship->num_points; i++)
264 {
265 vec.x = ship->points[i].x;
266 vec.y = ship->points[i].y;
267 vec.z = ship->points[i].z;
268
269 mult_vector (&vec, trans_mat);
270
271 rx = vec.x + univ->location.x;
272 ry = vec.y + univ->location.y;
273 rz = vec.z + univ->location.z;
274
275 if (rz <= 0)
276 rz = 1;
277
278 sx = (rx * 256) / rz;
279 sy = (ry * 256) / rz;
280
281 sy = -sy;
282
283 sx += 128;
284 sy += 96;
285
286 sx *= GFX_SCALE;
287 sy *= GFX_SCALE;
288
289 point_list[i].x = sx;
290 point_list[i].y = sy;
291 point_list[i].z = rz;
292
293 }
294
295 for (i = 0; i < num_faces; i++)
296 {
297 if (((point_list[face_data[i].p1].x - point_list[face_data[i].p2].x) *
298 (point_list[face_data[i].p3].y - point_list[face_data[i].p2].y) -
299 (point_list[face_data[i].p1].y - point_list[face_data[i].p2].y) *
300 (point_list[face_data[i].p3].x - point_list[face_data[i].p2].x)) <= 0)
301 {
302 num_points = face_data[i].points;
303
304 poly_list[0] = point_list[face_data[i].p1].x;
305 poly_list[1] = point_list[face_data[i].p1].y;
306 zavg = point_list[face_data[i].p1].z;
307
308 poly_list[2] = point_list[face_data[i].p2].x;
309 poly_list[3] = point_list[face_data[i].p2].y;
310 zavg = MAX(zavg,point_list[face_data[i].p2].z);
311
312 if (num_points > 2)
313 {
314 poly_list[4] = point_list[face_data[i].p3].x;
315 poly_list[5] = point_list[face_data[i].p3].y;
316 zavg = MAX(zavg,point_list[face_data[i].p3].z);
317 }
318
319 if (num_points > 3)
320 {
321 poly_list[6] = point_list[face_data[i].p4].x;
322 poly_list[7] = point_list[face_data[i].p4].y;
323 zavg = MAX(zavg,point_list[face_data[i].p4].z);
324 }
325
326 if (num_points > 4)
327 {
328 poly_list[8] = point_list[face_data[i].p5].x;
329 poly_list[9] = point_list[face_data[i].p5].y;
330 zavg = MAX(zavg,point_list[face_data[i].p5].z);
331 }
332
333 if (num_points > 5)
334 {
335 poly_list[10] = point_list[face_data[i].p6].x;
336 poly_list[11] = point_list[face_data[i].p6].y;
337 zavg = MAX(zavg,point_list[face_data[i].p6].z);
338 }
339
340 if (num_points > 6)
341 {
342 poly_list[12] = point_list[face_data[i].p7].x;
343 poly_list[13] = point_list[face_data[i].p7].y;
344 zavg = MAX(zavg,point_list[face_data[i].p7].z);
345 }
346
347 if (num_points > 7)
348 {
349 poly_list[14] = point_list[face_data[i].p8].x;
350 poly_list[15] = point_list[face_data[i].p8].y;
351 zavg = MAX(zavg,point_list[face_data[i].p8].z);
352 }
353
354
355 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
356
357 }
358 }
359
360 if (univ->flags & FLG_FIRING)
361 {
362 lasv = ship_list[univ->type]->front_laser;
363 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
364
365 gfx_render_line (point_list[lasv].x, point_list[lasv].y,
366 univ->location.x > 0 ? 0 : 511, rand255() * 2,
367 point_list[lasv].z, col);
368 }
1a8abebd 369
9c3e6768 370#if 0
371 {
372 double cx = univ->location.x;
373 double cy = univ->location.y;
374 double cz = univ->location.z;
375 if (cz <= 0) cz = 1;
376 cx = (cx * 256) / cz + 128;
377 cy = -(cy * 256) / cz + 96;
378 gfx_draw_circle(cx * GFX_SCALE, cy * GFX_SCALE, sqrt(ship_list[univ->type]->size) * 256 /
379 cz * GFX_SCALE, GFX_COL_RED);
380 }
381#endif
382
1a8abebd 383 if (identify)
384 identify_ship(univ);
84bbd123 385}
386
387
388
389
390
391/*
392 * Colour map used to generate a SNES Elite style planet.
393 * This is a quick hack and needs tidying up.
394 */
395
396int snes_planet_colour[] =
397{
398 102, 102,
399 134, 134, 134, 134,
400 167, 167, 167, 167,
401 213, 213,
402 255,
403 83,83,83,83,
404 122,
405 83,83,
406 249,249,249,249,
407 83,
408 122,
409 249,249,249,249,249,249,
410 83, 83,
411 122,
412 83,83, 83, 83,
413 255,
414 213, 213,
415 167,167, 167, 167,
416 134,134, 134, 134,
417 102, 102
418};
419
420
421/*
422 * Generate a landscape map for a SNES Elite style planet.
423 */
424
425void generate_snes_landscape (void)
426{
427 int x,y;
428 int colour;
429
430 for (y = 0; y <= LAND_Y_MAX; y++)
431 {
432 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];
433 for (x = 0; x <= LAND_X_MAX; x++)
434 {
435 landscape[x][y] = colour;
436 }
437 }
438}
439
440
441
442
443/*
444 * Guassian random number generator.
445 * Returns a number between -7 and +8 with Gaussian distribution.
446 */
447
448int grand (void)
449{
450 int i;
451 int r;
452
453 r = 0;
454 for (i = 0; i < 12; i++)
455 r += randint() & 15;
456
457 r /= 12;
458 r -= 7;
459
460 return r;
461}
462
463
464/*
465 * Calculate the midpoint between two given points.
466 */
467
468int calc_midpoint (int sx, int sy, int ex, int ey)
469{
470 int a,b,n;
471
472 a = landscape[sx][sy];
473 b = landscape[ex][ey];
474
475 n = ((a + b) / 2) + grand();
476 if (n < 0)
477 n = 0;
478 if (n > 255)
479 n = 255;
480
481 return n;
482}
483
484
485/*
486 * Calculate a square on the midpoint map.
487 */
488
489void midpoint_square (int tx, int ty, int w)
490{
491 int mx,my;
492 int bx,by;
493 int d;
494
495 d = w / 2;
496 mx = tx + d;
497 my = ty + d;
498 bx = tx + w;
499 by = ty + w;
500
501 landscape[mx][ty] = calc_midpoint(tx,ty,bx,ty);
502 landscape[mx][by] = calc_midpoint(tx,by,bx,by);
503 landscape[tx][my] = calc_midpoint(tx,ty,tx,by);
504 landscape[bx][my] = calc_midpoint(bx,ty,bx,by);
505 landscape[mx][my] = calc_midpoint(tx,my,bx,my);
506
507 if (d == 1)
508 return;
509
510 midpoint_square (tx,ty,d);
511 midpoint_square (mx,ty,d);
512 midpoint_square (tx,my,d);
513 midpoint_square (mx,my,d);
514}
515
516
517/*
518 * Generate a fractal landscape.
519 * Uses midpoint displacement method.
520 */
521
522void generate_fractal_landscape (int rnd_seed)
523{
524 int x,y,d,h;
525 double dist;
526 int dark;
527 int old_seed;
528
529 old_seed = get_rand_seed();
530 set_rand_seed(rnd_seed);
531
532 d = LAND_X_MAX / 8;
533
534 for (y = 0; y <= LAND_Y_MAX; y += d)
535 for (x = 0; x <= LAND_X_MAX; x += d)
536 landscape[x][y] = randint() & 255;
537
538 for (y = 0; y < LAND_Y_MAX; y += d)
539 for (x = 0; x < LAND_X_MAX; x += d)
540 midpoint_square (x,y,d);
541
542 for (y = 0; y <= LAND_Y_MAX; y++)
543 {
544 for (x = 0; x <= LAND_X_MAX; x++)
545 {
546 dist = x*x + y*y;
547 dark = dist > 10000;
548 h = landscape[x][y];
549 if (h > 166)
550 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
551 else
552 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
553
554 }
555 }
556
557 set_rand_seed (old_seed);
558}
559
560
561void generate_landscape (int rnd_seed)
562{
563 switch (planet_render_style)
564 {
565 case 0: /* Wireframe... do nothing for now... */
566 break;
567
568 case 1:
569 /* generate_green_landscape (); */
570 break;
571
572 case 2:
573 generate_snes_landscape();
574 break;
575
576 case 3:
577 generate_fractal_landscape (rnd_seed);
578 break;
579 }
580}
581
582
583
584/*
585 * Draw a line of the planet with appropriate rotation.
586 */
587
588
589void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
590{
591 int lx, ly;
592 int rx, ry;
593 int colour;
594 int sx,sy;
595 int ex;
596 int div;
597
598 sy = y + yo;
599
600 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
601 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
602 return;
603
604 sx = xo - x;
605 ex = xo + x;
606
607 rx = -x * vx - y * vy;
608 ry = -x * vy + y * vx;
609 rx += radius << 16;
610 ry += radius << 16;
611 div = radius << 10; /* radius * 2 * LAND_X_MAX >> 16 */
612
613
614 for (; sx <= ex; sx++)
615 {
616 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
617 {
618 lx = rx / div;
619 ly = ry / div;
620 colour = landscape[lx][ly];
621
622 gfx_fast_plot_pixel (sx, sy, colour);
623 }
624 rx += vx;
625 ry += vy;
626 }
627}
628
629
630/*
631 * Draw a solid planet. Based on Doros circle drawing alogorithm.
632 */
633
634void render_planet (int xo, int yo, int radius, struct vector *vec)
635{
636 int x,y;
637 int s;
638 int vx,vy;
639
640 xo += GFX_X_OFFSET;
641 yo += GFX_Y_OFFSET;
642
643 vx = vec[1].x * 65536;
644 vy = vec[1].y * 65536;
645
646 s = radius;
647 x = radius;
648 y = 0;
649
650 s -= x + x;
651 while (y <= x)
652 {
653 render_planet_line (xo, yo, x, y, radius, vx, vy);
654 render_planet_line (xo, yo, x,-y, radius, vx, vy);
655 render_planet_line (xo, yo, y, x, radius, vx, vy);
656 render_planet_line (xo, yo, y,-x, radius, vx, vy);
657
658 s += y + y + 1;
659 y++;
660 if (s >= 0)
661 {
662 s -= x + x + 2;
663 x--;
664 }
665 }
666}
667
668
669/*
670 * Draw a wireframe planet.
671 * At the moment we just draw a circle.
672 * Need to add in the two arcs that the original Elite had.
673 */
674
675void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
676{
677 gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
678}
679
680
681/*
682 * Draw a planet.
683 * We can currently do three different types of planet...
684 * - Wireframe.
685 * - Fractal landscape.
686 * - SNES Elite style.
687 */
688
689void draw_planet (struct univ_object *planet)
690{
691 int x,y;
692 int radius;
693
694 x = (planet->location.x * 256) / planet->location.z;
695 y = (planet->location.y * 256) / planet->location.z;
696
697 y = -y;
698
699 x += 128;
700 y += 96;
701
702 x *= GFX_SCALE;
703 y *= GFX_SCALE;
704
705 radius = 6291456 / planet->distance;
706// radius = 6291456 / ship_vec.z; /* Planets are BIG! */
707
708 radius *= GFX_SCALE;
709
710 if ((x + radius < 0) ||
711 (x - radius > 511) ||
712 (y + radius < 0) ||
713 (y - radius > 383))
714 return;
715
716 switch (planet_render_style)
717 {
718 case 0:
719 draw_wireframe_planet (x, y, radius, planet->rotmat);
720 break;
721
722 case 1:
723 gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
724 break;
725
726 case 2:
727 case 3:
728 render_planet (x, y, radius, planet->rotmat);
729 break;
730 }
731}
732
733
734void render_sun_line (int xo, int yo, int x, int y, int radius)
735{
736 int sy = yo + y;
737 int sx,ex;
738 int colour;
739 int dx,dy;
740 int distance;
741 int inner,outer;
742 int inner2;
743 int mix;
744
745 if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
746 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
747 return;
748
749 sx = xo - x;
750 ex = xo + x;
751
752 sx -= (radius * (2 + (randint() & 7))) >> 8;
753 ex += (radius * (2 + (randint() & 7))) >> 8;
754
755 if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
756 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
757 return;
758
759 if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
760 sx = GFX_VIEW_TX + GFX_X_OFFSET;
761
762 if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
763 ex = GFX_VIEW_BX + GFX_X_OFFSET;
764
765 inner = (radius * (200 + (randint() & 7))) >> 8;
766 inner *= inner;
767
768 inner2 = (radius * (220 + (randint() & 7))) >> 8;
769 inner2 *= inner2;
770
771 outer = (radius * (239 + (randint() & 7))) >> 8;
772 outer *= outer;
773
774 dy = y * y;
775 dx = sx - xo;
776
777 for (; sx <= ex; sx++,dx++)
778 {
779 mix = (sx ^ y) & 1;
780 distance = dx * dx + dy;
781
782 if (distance < inner)
783 colour = GFX_COL_WHITE;
784 else if (distance < inner2)
785 colour = GFX_COL_YELLOW_4;
786 else if (distance < outer)
787 colour = GFX_ORANGE_3;
788 else
789 colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
790
791 gfx_fast_plot_pixel (sx, sy, colour);
792 }
793}
794
795
796void render_sun (int xo, int yo, int radius)
797{
798 int x,y;
799 int s;
800
801 xo += GFX_X_OFFSET;
802 yo += GFX_Y_OFFSET;
803
804 s = -radius;
805 x = radius;
806 y = 0;
807
808 // s -= x + x;
809 while (y <= x)
810 {
811 render_sun_line (xo, yo, x, y, radius);
812 render_sun_line (xo, yo, x,-y, radius);
813 render_sun_line (xo, yo, y, x, radius);
814 render_sun_line (xo, yo, y,-x, radius);
815
816 s += y + y + 1;
817 y++;
818 if (s >= 0)
819 {
820 s -= x + x + 2;
821 x--;
822 }
823 }
824}
825
826
827
828void draw_sun (struct univ_object *planet)
829{
830 int x,y;
831 int radius;
832
833 x = (planet->location.x * 256) / planet->location.z;
834 y = (planet->location.y * 256) / planet->location.z;
835
836 y = -y;
837
838 x += 128;
839 y += 96;
840
841 x *= GFX_SCALE;
842 y *= GFX_SCALE;
843
844 radius = 6291456 / planet->distance;
845
846 radius *= GFX_SCALE;
847
848 if ((x + radius < 0) ||
849 (x - radius > 511) ||
850 (y + radius < 0) ||
851 (y - radius > 383))
852 return;
853
854 render_sun (x, y, radius);
855}
856
857
858
859void draw_explosion (struct univ_object *univ)
860{
861 int i;
862 int z;
863 int q;
864 int pr;
865 int px,py;
866 int cnt;
867 int sizex,sizey,psx,psy;
868 Matrix trans_mat;
869 int sx,sy;
870 double rx,ry,rz;
871 int visible[32];
872 struct vector vec;
873 struct vector camera_vec;
874 double cos_angle;
875 double tmp;
876 struct ship_face_normal *ship_norm;
877 struct ship_point *sp;
878 struct ship_data *ship;
879 int np;
880 int old_seed;
881
882
883 if (univ->exp_delta > 251)
884 {
885 univ->flags |= FLG_REMOVE;
886 return;
887 }
888
889 univ->exp_delta += 4;
890
891 if (univ->location.z <= 0)
892 return;
893
894 ship = ship_list[univ->type];
895
896 for (i = 0; i < 3; i++)
897 trans_mat[i] = univ->rotmat[i];
898
899 camera_vec = univ->location;
900 mult_vector (&camera_vec, trans_mat);
901 camera_vec = unit_vector (&camera_vec);
902
903 ship_norm = ship->normals;
904
905 for (i = 0; i < ship->num_faces; i++)
906 {
907 vec.x = ship_norm[i].x;
908 vec.y = ship_norm[i].y;
909 vec.z = ship_norm[i].z;
910
911 vec = unit_vector (&vec);
912 cos_angle = vector_dot_product (&vec, &camera_vec);
913
914 visible[i] = (cos_angle < -0.13);
915 }
916
917 tmp = trans_mat[0].y;
918 trans_mat[0].y = trans_mat[1].x;
919 trans_mat[1].x = tmp;
920
921 tmp = trans_mat[0].z;
922 trans_mat[0].z = trans_mat[2].x;
923 trans_mat[2].x = tmp;
924
925 tmp = trans_mat[1].z;
926 trans_mat[1].z = trans_mat[2].y;
927 trans_mat[2].y = tmp;
928
929 sp = ship->points;
930 np = 0;
931
932 for (i = 0; i < ship->num_points; i++)
933 {
934 if (visible[sp[i].face1] || visible[sp[i].face2] ||
935 visible[sp[i].face3] || visible[sp[i].face4])
936 {
937 vec.x = sp[i].x;
938 vec.y = sp[i].y;
939 vec.z = sp[i].z;
940
941 mult_vector (&vec, trans_mat);
942
943 rx = vec.x + univ->location.x;
944 ry = vec.y + univ->location.y;
945 rz = vec.z + univ->location.z;
946
947 sx = (rx * 256) / rz;
948 sy = (ry * 256) / rz;
949
950 sy = -sy;
951
952 sx += 128;
953 sy += 96;
954
955 sx *= GFX_SCALE;
956 sy *= GFX_SCALE;
957
958 point_list[np].x = sx;
959 point_list[np].y = sy;
960 np++;
961 }
962 }
963
964
965 z = (int)univ->location.z;
966
967 if (z >= 0x2000)
968 q = 254;
969 else
970 q = (z / 32) | 1;
971
972 pr = (univ->exp_delta * 256) / q;
973
974// if (pr > 0x1C00)
975// q = 254;
976// else
977
978 q = pr / 32;
979
980 old_seed = get_rand_seed();
981 set_rand_seed (univ->exp_seed);
982
983 for (cnt = 0; cnt < np; cnt++)
984 {
985 sx = point_list[cnt].x;
986 sy = point_list[cnt].y;
987
988 for (i = 0; i < 16; i++)
989 {
990 px = rand255() - 128;
991 py = rand255() - 128;
992
993 px = (px * q) / 256;
994 py = (py * q) / 256;
995
996 px = px + px + sx;
997 py = py + py + sy;
998
999 sizex = (randint() & 1) + 1;
1000 sizey = (randint() & 1) + 1;
1001
1002 for (psy = 0; psy < sizey; psy++)
1003 for (psx = 0; psx < sizex; psx++)
1004 gfx_plot_pixel (px+psx, py+psy, GFX_COL_WHITE);
1005 }
1006 }
1007
1008 set_rand_seed (old_seed);
1009}
1010
1011
1012
1013/*
1014 * Draws an object in the universe.
1015 * (Ship, Planet, Sun etc).
1016 */
1017
1018void draw_ship (struct univ_object *ship)
1019{
1020
1021 if ((current_screen != SCR_FRONT_VIEW) && (current_screen != SCR_REAR_VIEW) &&
1022 (current_screen != SCR_LEFT_VIEW) && (current_screen != SCR_RIGHT_VIEW) &&
1023 (current_screen != SCR_INTRO_ONE) && (current_screen != SCR_INTRO_TWO) &&
1024 (current_screen != SCR_GAME_OVER) && (current_screen != SCR_ESCAPE_POD))
1025 return;
1026
1027 if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
1028 {
1029 ship->flags |= FLG_EXPLOSION;
1030 ship->exp_seed = randint();
1031 ship->exp_delta = 18;
1032 }
1033
1034 if (ship->flags & FLG_EXPLOSION)
1035 {
1036 draw_explosion (ship);
1037 return;
1038 }
1039
1040 if (ship->location.z <= 0) /* Only display ships in front of us. */
1041 return;
1042
1043 if (ship->type == SHIP_PLANET)
1044 {
1045 draw_planet (ship);
1046 return;
1047 }
1048
1049 if (ship->type == SHIP_SUN)
1050 {
1051 draw_sun (ship);
1052 return;
1053 }
1054
1055 if ((fabs(ship->location.x) > ship->location.z) || /* Check for field of vision. */
1056 (fabs(ship->location.y) > ship->location.z))
1057 return;
1058
1059 if (wireframe)
1060 draw_wireframe_ship (ship);
1061 else
1062 draw_solid_ship (ship);
1063}
1064