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