chiark / gitweb /
72a56cf0f46f994b4491d3328b8c646236a352a1
[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 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
383         if (identify)
384           identify_ship(univ);
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