chiark / gitweb /
Buttload of hacking.
[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 static 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 }
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
82 void 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         }
189
190         if (identify)
191           identify_ship(univ);
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
204 void 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         }
369
370         if (identify)
371           identify_ship(univ);
372 }
373
374
375
376
377
378 /*
379  * Colour map used to generate a SNES Elite style planet.
380  * This is a quick hack and needs tidying up.
381  */
382
383 int snes_planet_colour[] =
384 {
385         102, 102,
386         134, 134, 134, 134,
387         167, 167, 167, 167,
388         213, 213,
389         255,
390         83,83,83,83,
391         122,
392         83,83,
393         249,249,249,249, 
394         83,
395         122,
396         249,249,249,249,249,249,
397         83, 83,
398         122,
399         83,83, 83, 83,
400         255,
401         213, 213,
402         167,167, 167, 167,
403         134,134, 134, 134,
404         102, 102
405 }; 
406
407
408 /*
409  * Generate a landscape map for a SNES Elite style planet.
410  */
411
412 void generate_snes_landscape (void)
413 {
414         int x,y;
415         int colour;
416         
417         for (y = 0; y <= LAND_Y_MAX; y++)
418         {
419                 colour = snes_planet_colour[y * (sizeof(snes_planet_colour)/sizeof(int)) / LAND_Y_MAX];  
420                 for (x = 0; x <= LAND_X_MAX; x++)
421                 {
422                         landscape[x][y] = colour;               
423                 }
424         }       
425 }
426
427
428
429
430 /*
431  * Guassian random number generator.
432  * Returns a number between -7 and +8 with Gaussian distribution.
433  */
434
435 int grand (void)
436 {
437         int i;
438         int r;
439         
440         r = 0;
441         for (i = 0; i < 12; i++)
442                 r += randint() & 15;
443         
444         r /= 12;
445         r -= 7;
446
447         return r;
448 }
449
450
451 /*
452  * Calculate the midpoint between two given points.
453  */
454
455 int calc_midpoint (int sx, int sy, int ex, int ey)
456 {
457         int a,b,n;
458
459         a = landscape[sx][sy];
460         b = landscape[ex][ey];
461         
462         n = ((a + b) / 2) + grand();
463         if (n < 0)
464                 n = 0;
465         if (n > 255)
466                 n = 255;
467         
468         return n;
469
470
471
472 /*
473  * Calculate a square on the midpoint map.
474  */
475
476 void midpoint_square (int tx, int ty, int w)
477 {
478         int mx,my;
479         int bx,by;
480         int d;
481
482         d = w / 2;      
483         mx = tx + d;
484         my = ty + d;
485         bx = tx + w;
486         by = ty + w;
487         
488         landscape[mx][ty] = calc_midpoint(tx,ty,bx,ty);
489         landscape[mx][by] = calc_midpoint(tx,by,bx,by);
490         landscape[tx][my] = calc_midpoint(tx,ty,tx,by);
491         landscape[bx][my] = calc_midpoint(bx,ty,bx,by);
492         landscape[mx][my] = calc_midpoint(tx,my,bx,my); 
493
494         if (d == 1)
495                 return;
496         
497         midpoint_square (tx,ty,d);
498         midpoint_square (mx,ty,d);
499         midpoint_square (tx,my,d);
500         midpoint_square (mx,my,d);
501 }
502
503
504 /*
505  * Generate a fractal landscape.
506  * Uses midpoint displacement method.
507  */
508
509 void generate_fractal_landscape (int rnd_seed)
510 {
511         int x,y,d,h;
512         double dist;
513         int dark;
514         int old_seed;
515         
516         old_seed = get_rand_seed();
517         set_rand_seed(rnd_seed);
518         
519         d = LAND_X_MAX / 8;
520         
521         for (y = 0; y <= LAND_Y_MAX; y += d)
522                 for (x = 0; x <= LAND_X_MAX; x += d)
523                         landscape[x][y] = randint() & 255;
524
525         for (y = 0; y < LAND_Y_MAX; y += d)
526                 for (x = 0; x < LAND_X_MAX; x += d)     
527                         midpoint_square (x,y,d);
528
529         for (y = 0; y <= LAND_Y_MAX; y++)
530         {
531                 for (x = 0; x <= LAND_X_MAX; x++)
532                 {
533                         dist = x*x + y*y;
534                         dark = dist > 10000;
535                         h = landscape[x][y];
536                         if (h > 166)
537                                 landscape[x][y] = dark ? GFX_COL_GREEN_1 : GFX_COL_GREEN_2;
538                         else 
539                                 landscape[x][y] = dark ? GFX_COL_BLUE_2 : GFX_COL_BLUE_1;
540
541                 }
542         }
543
544         set_rand_seed (old_seed);
545 }
546
547
548 void generate_landscape (int rnd_seed)
549 {
550         switch (planet_render_style)
551         {
552                 case 0:         /* Wireframe... do nothing for now... */
553                         break;
554                 
555                 case 1:
556                         /* generate_green_landscape (); */
557                         break;
558                 
559                 case 2:
560                         generate_snes_landscape();
561                         break;
562                 
563                 case 3:
564                         generate_fractal_landscape (rnd_seed);
565                         break;
566         }
567 }
568
569  
570  
571 /*
572  * Draw a line of the planet with appropriate rotation.
573  */
574
575
576 void render_planet_line (int xo, int yo, int x, int y, int radius, int vx, int vy)
577 {
578         int lx, ly;
579         int rx, ry;
580         int colour;
581         int sx,sy;
582         int ex;
583         int div;
584
585         sy = y + yo;
586         
587         if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
588                 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
589                 return;
590                                            
591         sx = xo - x;
592         ex = xo + x;
593         
594         rx = -x * vx - y * vy;
595         ry = -x * vy + y * vx;
596         rx += radius << 16;
597         ry += radius << 16;
598         div = radius << 10;      /* radius * 2 * LAND_X_MAX >> 16 */
599         
600                 
601         for (; sx <= ex; sx++)
602         {
603                 if ((sx >= (GFX_VIEW_TX + GFX_X_OFFSET)) && (sx <= (GFX_VIEW_BX + GFX_X_OFFSET)))
604                 {
605                         lx = rx / div;
606                         ly = ry / div;
607                         colour = landscape[lx][ly];
608  
609                         gfx_fast_plot_pixel (sx, sy, colour);
610                 }
611                 rx += vx;
612                 ry += vy;
613         }
614 }
615
616
617 /*
618  * Draw a solid planet.  Based on Doros circle drawing alogorithm.
619  */
620
621 void render_planet (int xo, int yo, int radius, struct vector *vec)
622 {
623         int x,y;
624         int s;
625         int vx,vy;
626
627         xo += GFX_X_OFFSET;
628         yo += GFX_Y_OFFSET;
629         
630         vx = vec[1].x * 65536;
631         vy = vec[1].y * 65536;  
632         
633         s = radius;
634         x = radius;
635         y = 0;
636
637         s -= x + x;
638         while (y <= x)
639         {
640                 render_planet_line (xo, yo, x, y, radius, vx, vy);
641                 render_planet_line (xo, yo, x,-y, radius, vx, vy);
642                 render_planet_line (xo, yo, y, x, radius, vx, vy);
643                 render_planet_line (xo, yo, y,-x, radius, vx, vy);
644                 
645                 s += y + y + 1;
646                 y++;
647                 if (s >= 0)
648                 {
649                         s -= x + x + 2;
650                         x--;
651                 }                               
652         }
653 }
654
655
656 /*
657  * Draw a wireframe planet.
658  * At the moment we just draw a circle.
659  * Need to add in the two arcs that the original Elite had.
660  */
661
662 void draw_wireframe_planet (int xo, int yo, int radius, struct vector *vec)
663 {
664         gfx_draw_circle (xo, yo, radius, GFX_COL_WHITE);
665 }
666
667
668 /*
669  * Draw a planet.
670  * We can currently do three different types of planet...
671  * - Wireframe.
672  * - Fractal landscape.
673  * - SNES Elite style.
674  */
675
676 void draw_planet (struct univ_object *planet)
677 {
678         int x,y;
679         int radius;
680         
681         x = (planet->location.x * 256) / planet->location.z;
682         y = (planet->location.y * 256) / planet->location.z;
683
684         y = -y;
685         
686         x += 128;
687         y += 96;
688
689         x *= GFX_SCALE;
690         y *= GFX_SCALE;
691         
692         radius = 6291456 / planet->distance;
693 //      radius = 6291456 / ship_vec.z;   /* Planets are BIG! */
694
695         radius *= GFX_SCALE;
696
697         if ((x + radius <  0) ||
698                 (x - radius > 511) ||
699                 (y + radius < 0) ||
700                 (y - radius > 383))
701                 return; 
702
703         switch (planet_render_style)
704         {
705                 case 0:
706                         draw_wireframe_planet (x, y, radius, planet->rotmat);
707                         break;
708                 
709                 case 1:
710                         gfx_draw_filled_circle (x, y, radius, GFX_COL_GREEN_1);
711                         break;
712
713                 case 2:
714                 case 3:
715                         render_planet (x, y, radius, planet->rotmat);
716                         break;
717         }
718 }
719
720
721 void render_sun_line (int xo, int yo, int x, int y, int radius)
722 {
723         int sy = yo + y;
724         int sx,ex;
725         int colour;
726         int dx,dy;
727         int distance;
728         int inner,outer;
729         int inner2;
730         int mix;
731
732         if ((sy < GFX_VIEW_TY + GFX_Y_OFFSET) ||
733                 (sy > GFX_VIEW_BY + GFX_Y_OFFSET))
734                 return;
735         
736         sx = xo - x;
737         ex = xo + x;
738
739         sx -= (radius * (2 + (randint() & 7))) >> 8;
740         ex += (radius * (2 + (randint() & 7))) >> 8;
741         
742         if ((sx > GFX_VIEW_BX + GFX_X_OFFSET) ||
743                 (ex < GFX_VIEW_TX + GFX_X_OFFSET))
744                 return;
745         
746         if (sx < GFX_VIEW_TX + GFX_X_OFFSET)
747                 sx = GFX_VIEW_TX + GFX_X_OFFSET;
748         
749         if (ex > GFX_VIEW_BX + GFX_X_OFFSET)
750                 ex = GFX_VIEW_BX + GFX_X_OFFSET;
751
752         inner = (radius * (200 + (randint() & 7))) >> 8;
753         inner *= inner;
754         
755         inner2 = (radius * (220 + (randint() & 7))) >> 8;
756         inner2 *= inner2;
757         
758         outer = (radius * (239 + (randint() & 7))) >> 8;
759         outer *= outer; 
760
761         dy = y * y;
762         dx = sx - xo;
763         
764         for (; sx <= ex; sx++,dx++)
765         {
766                 mix = (sx ^ y) & 1;
767                 distance = dx * dx + dy;
768
769                 if (distance < inner)
770                         colour = GFX_COL_WHITE;
771                 else if (distance < inner2)
772                         colour = GFX_COL_YELLOW_4;
773                 else if (distance < outer)
774                         colour = GFX_ORANGE_3;
775                 else
776                         colour = mix ? GFX_ORANGE_1 : GFX_ORANGE_2;
777                 
778                 gfx_fast_plot_pixel (sx, sy, colour);
779         }       
780 }
781
782
783 void render_sun (int xo, int yo, int radius)
784 {
785         int x,y;
786         int s;
787         
788         xo += GFX_X_OFFSET;
789         yo += GFX_Y_OFFSET;
790         
791         s = -radius;
792         x = radius;
793         y = 0;
794
795         // s -= x + x;
796         while (y <= x)
797         {
798                 render_sun_line (xo, yo, x, y, radius);
799                 render_sun_line (xo, yo, x,-y, radius);
800                 render_sun_line (xo, yo, y, x, radius);
801                 render_sun_line (xo, yo, y,-x, radius);
802                 
803                 s += y + y + 1;
804                 y++;
805                 if (s >= 0)
806                 {
807                         s -= x + x + 2;
808                         x--;
809                 }                               
810         }
811 }
812
813
814
815 void draw_sun (struct univ_object *planet)
816 {
817         int x,y;
818         int radius;
819         
820         x = (planet->location.x * 256) / planet->location.z;
821         y = (planet->location.y * 256) / planet->location.z;
822
823         y = -y;
824         
825         x += 128;
826         y += 96;
827
828         x *= GFX_SCALE;
829         y *= GFX_SCALE;
830         
831         radius = 6291456 / planet->distance;
832
833         radius *= GFX_SCALE;
834
835         if ((x + radius <  0) ||
836                 (x - radius > 511) ||
837                 (y + radius < 0) ||
838                 (y - radius > 383))
839                 return; 
840
841         render_sun (x, y, radius);
842 }
843
844
845
846 void draw_explosion (struct univ_object *univ)
847 {
848         int i;
849         int z;
850         int q;
851         int pr;
852         int px,py;
853         int cnt;
854         int sizex,sizey,psx,psy;
855         Matrix trans_mat;
856         int sx,sy;
857         double rx,ry,rz;
858         int visible[32];
859         struct vector vec;
860         struct vector camera_vec;
861         double cos_angle;
862         double tmp;
863         struct ship_face_normal *ship_norm;
864         struct ship_point *sp;
865         struct ship_data *ship;
866         int np;
867         int old_seed;
868         
869         
870         if (univ->exp_delta > 251)
871         {
872                 univ->flags |= FLG_REMOVE;
873                 return;
874         }
875         
876         univ->exp_delta += 4;
877
878         if (univ->location.z <= 0)
879                 return;
880
881         ship = ship_list[univ->type];
882         
883         for (i = 0; i < 3; i++)
884                 trans_mat[i] = univ->rotmat[i];
885                 
886         camera_vec = univ->location;
887         mult_vector (&camera_vec, trans_mat);
888         camera_vec = unit_vector (&camera_vec);
889         
890         ship_norm = ship->normals;
891         
892         for (i = 0; i < ship->num_faces; i++)
893         {
894                 vec.x = ship_norm[i].x;
895                 vec.y = ship_norm[i].y;
896                 vec.z = ship_norm[i].z;
897
898                 vec = unit_vector (&vec);
899                 cos_angle = vector_dot_product (&vec, &camera_vec);
900
901                 visible[i] = (cos_angle < -0.13);
902         }
903
904         tmp = trans_mat[0].y;
905         trans_mat[0].y = trans_mat[1].x;
906         trans_mat[1].x = tmp;
907
908         tmp = trans_mat[0].z;
909         trans_mat[0].z = trans_mat[2].x;
910         trans_mat[2].x = tmp;
911
912         tmp = trans_mat[1].z;
913         trans_mat[1].z = trans_mat[2].y;
914         trans_mat[2].y = tmp;
915         
916         sp = ship->points;
917         np = 0;
918         
919         for (i = 0; i < ship->num_points; i++)
920         {
921                 if (visible[sp[i].face1] || visible[sp[i].face2] ||
922                         visible[sp[i].face3] || visible[sp[i].face4])
923                 {
924                         vec.x = sp[i].x;
925                         vec.y = sp[i].y;
926                         vec.z = sp[i].z;
927
928                         mult_vector (&vec, trans_mat);
929
930                         rx = vec.x + univ->location.x;
931                         ry = vec.y + univ->location.y;
932                         rz = vec.z + univ->location.z;
933
934                         sx = (rx * 256) / rz;
935                         sy = (ry * 256) / rz;
936
937                         sy = -sy;
938
939                         sx += 128;
940                         sy += 96;
941
942                         sx *= GFX_SCALE;
943                         sy *= GFX_SCALE;
944
945                         point_list[np].x = sx;
946                         point_list[np].y = sy;
947                         np++;
948                 }
949         }
950
951         
952         z = (int)univ->location.z;
953         
954         if (z >= 0x2000)
955                 q = 254;
956         else
957                 q = (z / 32) | 1;
958
959         pr = (univ->exp_delta * 256) / q;
960         
961 //      if (pr > 0x1C00)
962 //              q = 254;
963 //      else
964
965         q = pr / 32;    
966                 
967         old_seed = get_rand_seed();
968         set_rand_seed (univ->exp_seed);
969
970         for (cnt = 0; cnt < np; cnt++)
971         {
972                 sx = point_list[cnt].x;
973                 sy = point_list[cnt].y;
974         
975                 for (i = 0; i < 16; i++)
976                 {
977                         px = rand255() - 128;
978                         py = rand255() - 128;           
979
980                         px = (px * q) / 256;
981                         py = (py * q) / 256;
982                 
983                         px = px + px + sx;
984                         py = py + py + sy;
985
986                         sizex = (randint() & 1) + 1;
987                         sizey = (randint() & 1) + 1;
988
989                         for (psy = 0; psy < sizey; psy++)
990                                 for (psx = 0; psx < sizex; psx++)               
991                                         gfx_plot_pixel (px+psx, py+psy, GFX_COL_WHITE);
992                 }
993         }
994
995         set_rand_seed (old_seed);
996 }
997
998
999
1000 /*
1001  * Draws an object in the universe.
1002  * (Ship, Planet, Sun etc).
1003  */
1004
1005 void draw_ship (struct univ_object *ship)
1006 {
1007
1008         if ((current_screen != SCR_FRONT_VIEW) && (current_screen != SCR_REAR_VIEW) && 
1009                 (current_screen != SCR_LEFT_VIEW) && (current_screen != SCR_RIGHT_VIEW) &&
1010                 (current_screen != SCR_INTRO_ONE) && (current_screen != SCR_INTRO_TWO) &&
1011                 (current_screen != SCR_GAME_OVER) && (current_screen != SCR_ESCAPE_POD))
1012                 return;
1013         
1014         if ((ship->flags & FLG_DEAD) && !(ship->flags & FLG_EXPLOSION))
1015         {
1016                 ship->flags |= FLG_EXPLOSION;
1017                 ship->exp_seed = randint();
1018                 ship->exp_delta = 18; 
1019         }
1020
1021         if (ship->flags & FLG_EXPLOSION)
1022         {
1023                 draw_explosion (ship);
1024                 return;
1025         }
1026         
1027         if (ship->location.z <= 0)      /* Only display ships in front of us. */
1028                 return;
1029
1030         if (ship->type == SHIP_PLANET)
1031         {
1032                 draw_planet (ship);
1033                 return;
1034         }
1035
1036         if (ship->type == SHIP_SUN)
1037         {
1038                 draw_sun (ship);
1039                 return;
1040         }
1041         
1042         if ((fabs(ship->location.x) > ship->location.z) ||      /* Check for field of vision. */
1043                 (fabs(ship->location.y) > ship->location.z))
1044                 return;
1045                 
1046         if (wireframe)
1047                 draw_wireframe_ship (ship);
1048         else
1049                 draw_solid_ship (ship);
1050 }
1051