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 | |
9c3e6768 |
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 | |
1a8abebd |
383 | if (identify) |
384 | identify_ship(univ); |
84bbd123 |
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 | |