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