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 | |
1a8abebd |
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 | } |
84bbd123 |
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 | } |
1a8abebd |
189 | |
190 | if (identify) |
191 | identify_ship(univ); |
84bbd123 |
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 | } |
1a8abebd |
369 | |
370 | if (identify) |
371 | identify_ship(univ); |
84bbd123 |
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 | |