Proper Subversion configuration.
[newkind] / threed.c
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
37 static unsigned char landscape[LAND_X_MAX+1][LAND_Y_MAX+1];
38
39 static struct point point_list[100];
40
41 #ifdef HACKING
42
43 static void identify_ship(struct univ_object *univ)
44 {
45 char buf[64];
46 int lasv;
47
48 lasv = ship_list[univ->type]->front_laser;
49 if (!(univ->flags & FLG_TACTICAL)) {
50 unsigned flags = univ->flags;
51 sprintf(buf, "%s %s%s%s%s", ship_list[univ->type]->name,
52 (flags & FLG_ANGRY) ? "A" : "",
53 (flags & FLG_TARGET) ? "T" : "",
54 (flags & FLG_HOSTILE) ? "H" : "",
55 (flags & FLG_POLICE) ? "P" : "");
56 } else {
57 unsigned flags = univ->flags;
58 sprintf(buf, "%s (%d) %s%s%s%s", ship_list[univ->type]->name,
59 univ->energy,
60 (flags & FLG_ANGRY) ? "A" : "",
61 (flags & FLG_TARGET) ? "T" : "",
62 (flags & FLG_HOSTILE) ? "H" : "",
63 (flags & FLG_POLICE) ? "P" : "");
64 }
65 gfx_display_text(point_list[lasv].x + 4, point_list[lasv].y + 4, buf);
66 }
67
68 #endif
69
70 /*
71 * The following routine is used to draw a wireframe represtation of a ship.
72 *
73 * caveat: it is a work in progress.
74 * A number of features (such as not showing detail at distance) have not yet been implemented.
75 *
76 */
77
78 void draw_wireframe_ship (struct univ_object *univ)
79 {
80 Matrix trans_mat;
81 int i;
82 int sx,sy,ex,ey;
83 double rx,ry,rz;
84 int visible[32];
85 Vector vec;
86 Vector camera_vec;
87 double cos_angle;
88 double tmp;
89 struct ship_face_normal *ship_norm;
90 int num_faces;
91 struct ship_data *ship;
92 int lasv;
93
94 ship = ship_list[univ->type];
95
96 for (i = 0; i < 3; i++)
97 trans_mat[i] = univ->rotmat[i];
98
99 camera_vec = univ->location;
100 mult_vector (&camera_vec, trans_mat);
101 camera_vec = unit_vector (&camera_vec);
102
103 num_faces = ship->num_faces;
104
105 for (i = 0; i < num_faces; i++)
106 {
107 ship_norm = ship->normals;
108
109 vec.x = ship_norm[i].x;
110 vec.y = ship_norm[i].y;
111 vec.z = ship_norm[i].z;
112
113 if ((vec.x == 0) && (vec.y == 0) && (vec.z == 0))
114 visible[i] = 1;
115 else
116 {
117 vec = unit_vector (&vec);
118 cos_angle = vector_dot_product (&vec, &camera_vec);
119 visible[i] = (cos_angle < -0.2);
120 }
121 }
122
123 tmp = trans_mat[0].y;
124 trans_mat[0].y = trans_mat[1].x;
125 trans_mat[1].x = tmp;
126
127 tmp = trans_mat[0].z;
128 trans_mat[0].z = trans_mat[2].x;
129 trans_mat[2].x = tmp;
130
131 tmp = trans_mat[1].z;
132 trans_mat[1].z = trans_mat[2].y;
133 trans_mat[2].y = tmp;
134
135 for (i = 0; i < ship->num_points; i++)
136 {
137 vec.x = ship->points[i].x;
138 vec.y = ship->points[i].y;
139 vec.z = ship->points[i].z;
140
141 mult_vector (&vec, trans_mat);
142
143 rx = vec.x + univ->location.x;
144 ry = vec.y + univ->location.y;
145 rz = vec.z + univ->location.z;
146
147 sx = (rx * 256) / rz;
148 sy = (ry * 256) / rz;
149
150 sy = -sy;
151
152 sx += 128;
153 sy += 96;
154
155 sx *= GFX_SCALE;
156 sy *= GFX_SCALE;
157
158 point_list[i].x = sx;
159 point_list[i].y = sy;
160
161 }
162
163 for (i = 0; i < ship->num_lines; i++)
164 {
165 if (visible[ship->lines[i].face1] ||
166 visible[ship->lines[i].face2])
167 {
168 sx = point_list[ship->lines[i].start_point].x;
169 sy = point_list[ship->lines[i].start_point].y;
170
171 ex = point_list[ship->lines[i].end_point].x;
172 ey = point_list[ship->lines[i].end_point].y;
173
174 gfx_draw_line (sx, sy, ex, ey);
175 }
176 }
177
178
179 if (univ->flags & FLG_FIRING)
180 {
181 lasv = ship_list[univ->type]->front_laser;
182 gfx_draw_line (point_list[lasv].x, point_list[lasv].y,
183 univ->location.x > 0 ? 0 : 511, rand255() * 2);
184 }
185
186 #ifdef HACKING
187 if (identify)
188 identify_ship(univ);
189 #endif
190 }
191
192
193
194
195 /*
196 * Hacked version of the draw ship routine to display solid ships...
197 * This needs a lot of tidying...
198 *
199 * Check for hidden surface supplied by T.Harte.
200 */
201
202 void draw_solid_ship (struct univ_object *univ)
203 {
204 int i;
205 int sx,sy;
206 double rx,ry,rz;
207 struct vector vec;
208 struct vector camera_vec;
209 double tmp;
210 struct ship_face *face_data;
211 int num_faces;
212 int num_points;
213 int poly_list[16];
214 int zavg;
215 struct ship_solid *solid_data;
216 struct ship_data *ship;
217 Matrix trans_mat;
218 int lasv;
219 int col;
220
221 solid_data = &ship_solids[univ->type];
222 ship = ship_list[univ->type];
223
224 for (i = 0; i < 3; i++)
225 trans_mat[i] = univ->rotmat[i];
226
227 camera_vec = univ->location;
228 mult_vector (&camera_vec, trans_mat);
229 camera_vec = unit_vector (&camera_vec);
230
231 num_faces = solid_data->num_faces;
232 face_data = solid_data->face_data;
233
234 /*
235 for (i = 0; i < num_faces; i++)
236 {
237 vec.x = face_data[i].norm_x;
238 vec.y = face_data[i].norm_y;
239 vec.z = face_data[i].norm_z;
240
241 vec = unit_vector (&vec);
242 cos_angle = vector_dot_product (&vec, &camera_vec);
243
244 visible[i] = (cos_angle < -0.13);
245 }
246 */
247
248 tmp = trans_mat[0].y;
249 trans_mat[0].y = trans_mat[1].x;
250 trans_mat[1].x = tmp;
251
252 tmp = trans_mat[0].z;
253 trans_mat[0].z = trans_mat[2].x;
254 trans_mat[2].x = tmp;
255
256 tmp = trans_mat[1].z;
257 trans_mat[1].z = trans_mat[2].y;
258 trans_mat[2].y = tmp;
259
260
261 for (i = 0; i < ship->num_points; i++)
262 {
263 vec.x = ship->points[i].x;
264 vec.y = ship->points[i].y;
265 vec.z = ship->points[i].z;
266
267 mult_vector (&vec, trans_mat);
268
269 rx = vec.x + univ->location.x;
270 ry = vec.y + univ->location.y;
271 rz = vec.z + univ->location.z;
272
273 if (rz <= 0)
274 rz = 1;
275
276 sx = (rx * 256) / rz;
277 sy = (ry * 256) / rz;
278
279 sy = -sy;
280
281 sx += 128;
282 sy += 96;
283
284 sx *= GFX_SCALE;
285 sy *= GFX_SCALE;
286
287 point_list[i].x = sx;
288 point_list[i].y = sy;
289 point_list[i].z = rz;
290
291 }
292
293 for (i = 0; i < num_faces; i++)
294 {
295 if (((point_list[face_data[i].p1].x - point_list[face_data[i].p2].x) *
296 (point_list[face_data[i].p3].y - point_list[face_data[i].p2].y) -
297 (point_list[face_data[i].p1].y - point_list[face_data[i].p2].y) *
298 (point_list[face_data[i].p3].x - point_list[face_data[i].p2].x)) <= 0)
299 {
300 num_points = face_data[i].points;
301
302 poly_list[0] = point_list[face_data[i].p1].x;
303 poly_list[1] = point_list[face_data[i].p1].y;
304 zavg = point_list[face_data[i].p1].z;
305
306 poly_list[2] = point_list[face_data[i].p2].x;
307 poly_list[3] = point_list[face_data[i].p2].y;
308 zavg = MAX(zavg,point_list[face_data[i].p2].z);
309
310 if (num_points > 2)
311 {
312 poly_list[4] = point_list[face_data[i].p3].x;
313 poly_list[5] = point_list[face_data[i].p3].y;
314 zavg = MAX(zavg,point_list[face_data[i].p3].z);
315 }
316
317 if (num_points > 3)
318 {
319 poly_list[6] = point_list[face_data[i].p4].x;
320 poly_list[7] = point_list[face_data[i].p4].y;
321 zavg = MAX(zavg,point_list[face_data[i].p4].z);
322 }
323
324 if (num_points > 4)
325 {
326 poly_list[8] = point_list[face_data[i].p5].x;
327 poly_list[9] = point_list[face_data[i].p5].y;
328 zavg = MAX(zavg,point_list[face_data[i].p5].z);
329 }
330
331 if (num_points > 5)
332 {
333 poly_list[10] = point_list[face_data[i].p6].x;
334 poly_list[11] = point_list[face_data[i].p6].y;
335 zavg = MAX(zavg,point_list[face_data[i].p6].z);
336 }
337
338 if (num_points > 6)
339 {
340 poly_list[12] = point_list[face_data[i].p7].x;
341 poly_list[13] = point_list[face_data[i].p7].y;
342 zavg = MAX(zavg,point_list[face_data[i].p7].z);
343 }
344
345 if (num_points > 7)
346 {
347 poly_list[14] = point_list[face_data[i].p8].x;
348 poly_list[15] = point_list[face_data[i].p8].y;
349 zavg = MAX(zavg,point_list[face_data[i].p8].z);
350 }
351
352
353 gfx_render_polygon (face_data[i].points, poly_list, face_data[i].colour, zavg);
354
355 }
356 }
357
358 if (univ->flags & FLG_FIRING)
359 {
360 lasv = ship_list[univ->type]->front_laser;
361 col = (univ->type == SHIP_VIPER) ? GFX_COL_CYAN : GFX_COL_WHITE;
362
363 gfx_render_line (point_list[lasv].x, point_list[lasv].y,
364 univ->location.x > 0 ? 0 : 511, rand255() * 2,
365 point_list[lasv].z, col);
366 }
367
368 #if 0
369 {
370 double cx = univ->location.x;
371 double cy = univ->location.y;
372 double cz = univ->location.z;
373 if (cz <= 0) cz = 1;
374 cx = (cx * 256) / cz + 128;
375 cy = -(cy * 256) / cz + 96;
376 gfx_draw_circle(cx * GFX_SCALE, cy * GFX_SCALE, sqrt(ship_list[univ->type]->size) * 256 /
377 cz * GFX_SCALE, GFX_COL_RED);
378 }
379 #endif
380
381 #ifdef HACKING
382 if (identify)
383 identify_ship(univ);
384 #endif
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
396 int 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
425 void 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
448 int 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
468 int 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
489 void 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
522 void 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
561 void 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
589 void 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
634 void 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
675 void 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
689 void 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
734 void 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
796 void 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
828 void 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
859 void 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
1018 void 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