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