1 /* render routines that replaces the game rendering by OpenGL rendering
3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 * 1. Each game's rendering is capured:
23 * a: call to render_capture_start()
24 * b: several calls to render_capture_event() to capture all data
25 * c: call to render_capture_stop()
26 * 2. The captured motion is then interpolated to get smooth motion:
27 * - new_motion for motion of current/recent capture
28 * - old_motion for motion of previous capture
29 * - interpolation for interpolated result
30 * 3. The complete scene is rendered:
31 * - render_all_items() calls the render_item() for each item
32 * - All items before shadows on the ground are rendered first
33 * - Then all items with shadows are rendered
34 * - Then all items after shadows are rendered
35 * - The recent capture (NEW) is rendered
36 * - Interpolation result is taken into account
45 #include "../libsdl/print.h"
46 #include "../libcpu/m68k.h"
47 #include "../libcpu/m68kcpu.h"
48 #include "../libcpu/execute.h"
49 #include "../libopengl/opengl.h"
50 #include "mercenary.h"
52 #define GL3_PROTOTYPES 1
56 //#define DEBUG_VERTEX
60 #define ELEVATION_SKY_NIGHT -0.05 /* elevation of darkest sky */
61 #define ELEVATION_SKY_DAY 0.3 /* elevation of brightest sky */
62 #define ELEVATION_STARS_NIGHT -0.1 /* elevation of brightest stars */
63 #define ELEVATION_STARS_DAY 0.1 /* elevation of no stars */
64 #define ELEVATION_SHADOW_MIN 0.03 /* elevation of shadow begin */
65 #define ELEVATION_SHADOW_MAX 0.3 /* elevation of darkest shadow */
66 #define SHADOW_LEVEL 0.9 /* opacity of darkest shadow */
68 #define MAX_POLYGON 16 /* number of polygon corners (vertices) */
69 #define MAX_VERTEX 0x100 /* this is the value range, these are 64 vertices */
70 #define MAX_INTERIOR_VERTEX 0x400 /* do we need that much? */
71 #define MAX_INTERSTARS 80 /* always 80 stars */
72 #define MAX_MOVING_OBJECTS 16 /* maximum number of moving objects (used for interpolation) */
73 #define MAX_EXPLOSION 256 /* how many explosion particles can be stored in one object */
74 #define PLANET_VERTICES 128
75 #define PLANET_STRETCH 1.19 /* stretch horizontally (this compensates NTSC/PAL line ratio of 625/525)*/
76 #define EXPLOSION_VERTICES 16
77 #define EXPLOSION_STRETCH 1.19 /* as above */
78 #define SIGHT_DIST 78.74 /* distanc of sights in inch */
79 #define FIX_OBJECT_SCALE 16 /* intercity... */
80 #define FIX_OBJECT_SCALE_TAG 2 /* line in faces of persons */
89 * render item definition and structures
93 enum render_item_type {
94 RENDER_ITEM_OBJECT_INFO,
95 RENDER_ITEM_VERTICES_0,
96 RENDER_ITEM_VERTICES_1,
97 RENDER_ITEM_VERTICES_2,
98 RENDER_ITEM_VERTICES_INTERIOR,
101 RENDER_ITEM_OBJECT_POLYGON,
102 RENDER_ITEM_OBJECT_LINE,
103 RENDER_ITEM_BEACON_POINT,
104 RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
105 RENDER_ITEM_BUILDING_EXTERIOR_LINE,
106 RENDER_ITEM_BUILDING_INTERIOR_1TO4,
107 RENDER_ITEM_BUILDING_INTERIOR_5TO6,
108 RENDER_ITEM_BUILDING_INTERIOR_WALL,
109 RENDER_ITEM_COMET_POLYGON,
110 RENDER_ITEM_ROAD_LINE,
111 RENDER_ITEM_ROAD_POLYGON,
112 RENDER_ITEM_TAG_LINE_OBJECT,
113 RENDER_ITEM_TAG_LINE_OTHER,
114 RENDER_ITEM_TAG_POLYGON_OBJECT,
115 RENDER_ITEM_TAG_POLYGON_OTHER,
118 RENDER_ITEM_INTERSTELLAR_STARS,
119 RENDER_ITEM_INTERSTELLAR_SUN,
120 RENDER_ITEM_ISLAND_POLYGON,
122 RENDER_ITEM_EXPLOSION,
123 RENDER_ITEM_SHADOW_BUILDING_POLYGON,
124 RENDER_ITEM_SHADOW_BUILDING_LINE,
125 RENDER_ITEM_SHADOW_OBJECT_POLYGON,
126 RENDER_ITEM_SHADOW_OBJECT_LINE,
129 struct render_item_info {
132 int32_t east, height, north;
135 struct render_item_vertices {
136 double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
139 struct render_item_vertices_interior {
140 uint8_t set[MAX_INTERIOR_VERTEX >> 2];
141 double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
144 struct render_item_sky {
145 double red, green, blue;
148 struct render_item_ground {
149 double red, green, blue;
152 struct render_item_polygon {
153 double red, green, blue;
155 int vertex[MAX_POLYGON];
158 struct render_item_interior14 {
159 double red, green, blue;
164 struct render_item_interior56 {
165 double red, green, blue;
172 struct render_item_line {
173 double red, green, blue;
177 struct render_item_point {
178 double red, green, blue;
182 struct render_item_planet {
183 double front_red, front_green, front_blue;
184 double back_red, back_green, back_blue;
189 struct render_item_stars {
196 struct render_item_interstars {
197 uint8_t color[MAX_INTERSTARS];
198 int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
202 struct render_item_explosion {
203 double red, green, blue;
204 int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
205 double size[MAX_EXPLOSION];
209 struct render_item_shadow_polygon {
210 int32_t x_pos, y_pos, z_pos;
212 int32_t x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
215 struct render_item_shadow_line {
216 int32_t x_pos, y_pos, z_pos;
217 int32_t x[2], y[2], z[2];
220 typedef struct render_item {
221 struct render_item *next;
222 enum render_item_type type;
224 struct render_item_info info;
225 struct render_item_vertices vertices;
226 struct render_item_vertices_interior vertices_interior;
227 struct render_item_sky sky;
228 struct render_item_ground ground;
229 struct render_item_polygon polygon;
230 struct render_item_line line;
231 struct render_item_point point;
232 struct render_item_interior14 interior14;
233 struct render_item_interior56 interior56;
234 struct render_item_planet planet;
235 struct render_item_stars stars;
236 struct render_item_interstars interstars;
237 struct render_item_explosion explosion;
238 struct render_item_shadow_polygon shadow_polygon;
239 struct render_item_shadow_line shadow_line;
243 /* information about motion in each game rendering */
244 typedef struct motion {
245 int32_t position_east, position_height, position_north;
246 double orientation_roll, orientation_pitch, orientation_yaw;
247 uint16_t orientation_raw_yaw;
248 int16_t orientation_raw_pitch;
250 double planet_inclination, planet_azimuth;
253 /* information about interpolation between two game renedrings */
254 typedef struct interpolation {
255 double offset_east, offset_height, offset_north;
256 double orientation_roll, orientation_pitch, orientation_yaw;
257 double orientation_raw_yaw, orientation_raw_pitch;
258 double planet_inclination, planet_azimuth;
259 int object_id[MAX_MOVING_OBJECTS];
260 double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
262 render_item_t *interior;
263 render_item_t *planets;
266 #define GET_ORIENTATION \
267 double roll = interpolation.orientation_roll; \
268 double pitch = interpolation.orientation_pitch; \
269 double yaw = interpolation.orientation_yaw
271 #define GET_ORIENTATION_FIX \
272 roll = motion_new.orientation_roll; \
273 pitch = motion_new.orientation_pitch; \
274 yaw = motion_new.orientation_yaw
276 /* rendering options */
277 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
278 static int improve_stars; /* stars are rendered spherical */
279 static int fix_sky_rotation; /* sky will rotate correctly by rotating planets/comet by 180 degrees */
280 static int draw_shadows; /* render shadows */
281 static double planet_aspect, explosion_aspect; /* aspect ratio */
283 static double debug_opacity;
284 static double frustum_slope_64, frustum_slope_fov;
286 /* states while collecting render items */
287 static motion_t motion_old, motion_new;
288 static int32_t old_height_offset = 0, new_height_offset = 0;
289 static interpolation_t interpolation;
290 static int ground_index, last_ground_index = -1;
291 static int interior_level12 = 0;
292 static int interior_level34 = 0;
293 static int tag_is_object;
294 /* current render item list */
295 static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
296 /* previous render item list */
297 static render_item_t *render_list_old = NULL;
298 /* current item to be processed */
299 static render_item_t *render_item;
300 /* current object info */
301 static render_item_t *render_item_object_info;
302 /* current vertices */
303 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
304 static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
306 /* states while rendering */
308 double stars_bright; /* the brightness of stars */
309 double shadow_level; /* how 'dark' the shadow is (that is darker at day) */
310 double sun_pos_x, sun_pos_y, sun_pos_z;
311 double sky_color_red, sky_color_green, sky_color_blue;
317 static void render_item_add(enum render_item_type type)
319 render_item = calloc(1, sizeof(render_item_t));
321 print_error("No memory, must abort!\n");
324 render_item->type = type;
325 *render_list_end = render_item;
326 render_list_end = &render_item->next;
329 static void flush_old_items(void)
331 /* flush old render list */
332 while (render_list_old) {
333 render_item = render_list_old;
334 render_list_old = render_list_old->next;
339 /* rendering starts, initialize variables */
340 void render_capture_start(double _fov, int _extend_roads, int _smooth_planets, int _improve_stars, int _fix_sky_rotation, int _round_planets, int _shadows, int debug)
342 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
343 printf("start rendering a new frame...\n");
348 /* move new render list to old render list */
349 render_list_old = render_list_new;
350 /* setup new render list */
351 render_list_new = NULL;
352 render_list_end = &render_list_new;
354 /* move new motion to old motion */
355 memcpy(&motion_old, &motion_new, sizeof(motion_old));
357 /* set rendering options */
359 extend_roads = _extend_roads;
360 fix_sky_rotation = _fix_sky_rotation;
361 improve_stars = _improve_stars;
362 planet_aspect = (_round_planets) ? 1.0 : PLANET_STRETCH;
363 explosion_aspect = (_round_planets) ? 1.0 : EXPLOSION_STRETCH;
364 draw_shadows = _shadows;
365 /* set some transpareny, if debugging is enabled */
366 debug_opacity = (debug) ? 0.5 : 1.0;
368 /* calculate slope of 64 degree frustum and current FOV's frustum */
369 frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
370 frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
373 mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
374 /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
375 mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
376 mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
377 motion_new.planet_rotation = motion_old.planet_rotation;
378 mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth, _smooth_planets);
380 render_item_object_info = NULL;
381 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
382 render_item_vertices_planets = NULL;
383 render_item_vertices_interior = NULL;
385 /* detect elevator movement */
386 old_height_offset = new_height_offset;
388 new_height_offset = motion_new.position_height - motion_old.position_height;
390 /* detect switching between space (-1) and over ground (>=0) */
391 last_ground_index = ground_index;
397 void render_capture_stop(void)
399 /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
400 if (!render_list_new) {
401 render_list_new = render_list_old;
402 render_list_end = &render_list_new;
403 render_list_old = NULL;
408 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
413 /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
415 palette = mercenary_palette_render();
416 color = m68k_read_memory_16(palette + index);
418 printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
420 if (color >= 0x8000) {
422 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
425 *red = (double)((color >> 8) & 0xf) / 15.0;
426 *green = (double)((color >> 4) & 0xf) / 15.0;
427 *blue = (double)(color & 0xf) / 15.0;
430 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
437 printf("color is given as 0x%04x\n", color);
440 /* color conversion: see for example M3: 0x4f830 */
441 if (color < 0x8000) {
442 /* use given color but shift it left by 1 */
445 printf("using given color, color is now 0x%04x\n", color);
447 } else if ((color & 0xff) < 0x80) {
448 gamecolor2gl_index(red, green, blue, color & 0xf);
451 /* use given index from pre-defined palette */
452 index = color & 0x7e;
453 palette = mercenary_palette_predefined();
454 color = m68k_read_memory_16(palette + index);
456 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
458 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
459 if (nesting++ == 8) {
460 print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
465 *red = (double)((color >> 8) & 0xf) / 15.0;
466 *green = (double)((color >> 4) & 0xf) / 15.0;
467 *blue = (double)(color & 0xf) / 15.0;
470 static int32_t wrap_int28(int32_t value)
477 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z, double scale)
480 print_info("Vertex %d is not a multiple of four!\n", vertex);
483 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
484 if (vertex < 0x100) {
485 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
486 render_item_add(RENDER_ITEM_VERTICES_0);
487 /* copy vertices that have been captured already */
488 if (render_item_vertices_0)
489 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
490 render_item_vertices_0 = render_item;
493 if (vertex < 0x200) {
494 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
495 render_item_add(RENDER_ITEM_VERTICES_1);
496 /* copy vertices that have been captured already */
497 if (render_item_vertices_1)
498 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
499 render_item_vertices_1 = render_item;
503 if (vertex < 0x300) {
504 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
505 render_item_add(RENDER_ITEM_VERTICES_2);
506 /* copy vertices that have been captured already */
507 if (render_item_vertices_2)
508 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
509 render_item_vertices_2 = render_item;
513 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
518 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
520 /* use absolute position */
521 render_item->u.vertices.x[vertex] = (double)x * scale + motion_new.position_east;
522 render_item->u.vertices.y[vertex] = (double)y * scale + motion_new.position_height;
523 render_item->u.vertices.z[vertex] = (double)z * scale + motion_new.position_north;
526 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix);
528 static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
531 print_info("Vertex %d is not a multiple of four!\n", vertex);
534 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
535 if (vertex >= MAX_VERTEX) {
536 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
539 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
540 render_item_add(RENDER_ITEM_VERTICES_0);
541 /* copy vertices that have been captured already */
542 if (render_item_vertices_0)
543 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
544 render_item_vertices_0 = render_item;
548 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
550 render_item->u.vertices.x[vertex] = x;
551 render_item->u.vertices.y[vertex] = y;
552 render_item->u.vertices.z[vertex] = z;
555 static void store_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y1, int32_t y2, int32_t y3, int32_t y4, int32_t z)
558 print_info("Vertex is not a multiple of four!\n");
561 if (vertex >= MAX_INTERIOR_VERTEX) {
562 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
565 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
566 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
569 printf("storing %s coordinates: vertex=%d, x=%d, y=%d;%d;%d;%d, z=%d\n", what, vertex, x, y1, y2, y3, y4, z);
571 /* use absolute position */
572 x += motion_new.position_east;
573 y1 += motion_new.position_height;
574 y2 += motion_new.position_height;
575 y3 += motion_new.position_height;
576 y4 += motion_new.position_height;
577 z += motion_new.position_north;
578 render_item->u.vertices_interior.x[vertex] = (double)x;
579 render_item->u.vertices_interior.y[0] = (double)y1;
580 render_item->u.vertices_interior.y[1] = (double)y2;
581 render_item->u.vertices_interior.y[2] = (double)y3;
582 render_item->u.vertices_interior.y[3] = (double)y4;
583 render_item->u.vertices_interior.z[vertex] = (double)z;
584 render_item->u.vertices_interior.set[vertex] = 1;
587 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
589 double out_x, out_y, out_z;
591 /* rotate yaw (German: Gier, turn view to the right) */
593 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
594 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
598 /* rotate pitch (German: Nick, turn head down) */
600 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
601 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
605 /* rotate roll (tilt head to the right) */
607 out_x = (*x) * cos(roll) - (*y) * sin(roll);
608 out_y = (*x) * sin(roll) + (*y) * cos(roll);
614 /* clear screen color (sky / universe) */
615 static void clear_screen(int index)
618 printf("clear screen:\n");
621 /* allocate render item */
622 render_item_add(RENDER_ITEM_SKY);
625 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
627 /* store for later use after planets have been rendered */
628 ground_index = index;
632 static void draw_ground(void)
634 /* no ground in space :) */
635 if (ground_index < 0)
639 printf("add ground plane:\n");
642 /* allocate render item */
643 render_item_add(RENDER_ITEM_GROUND);
646 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
650 static void info_object(int moving)
653 printf("add object's info:\n");
656 /* allocate render item */
657 render_item_add(RENDER_ITEM_OBJECT_INFO);
660 render_item->u.info.moving = moving;
662 mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
663 render_item_object_info = render_item;
666 /* coordinates ready for an object */
667 static void coord_object(void)
671 x = (int16_t)REG_D[3];
672 x += (int32_t)REG_A[1];
673 y = (int16_t)REG_D[4];
674 y += (int32_t)REG_A[2];
675 z = (int16_t)REG_D[5];
676 z += (int32_t)REG_A[3];
677 store_coord("object", REG_A[0], x, y, z, 1.0);
680 /* polygon of object */
681 static void poly_object(int mercenary)
683 uint32_t vertex_address = REG_A[0], va;
689 printf("add object's polygon:\n");
692 /* allocate render item */
693 render_item_add(RENDER_ITEM_OBJECT_POLYGON);
697 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
700 color = m68k_read_memory_8(vertex_address++) << 8;
701 color |= m68k_read_memory_8(vertex_address++);
702 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
705 /* the vertex list is zero-terminated */
707 for (i = 0; i < MAX_POLYGON; i++) {
708 vertex = m68k_read_memory_8(va++);
709 if (vertex == 0 && i)
711 render_item->u.polygon.vertex[i] = vertex;
713 render_item->u.polygon.vertices = i;
715 /* apply only to not fixed objects (a fixed may be taxi interior) */
716 if (render_item_object_info && render_item_object_info->u.info.moving) {
717 /* allocate shadow item */
718 render_item_add(RENDER_ITEM_SHADOW_OBJECT_POLYGON);
719 render_item->u.shadow_polygon.x_pos = -motion_new.position_east;
720 render_item->u.shadow_polygon.y_pos = -motion_new.position_height;
721 render_item->u.shadow_polygon.z_pos = -motion_new.position_north;
723 /* the vertex list is zero-terminated */
725 for (i = 0; i < MAX_POLYGON; i++) {
726 vertex = m68k_read_memory_8(va++);
727 if (vertex == 0 && i)
729 rc = use_coord("object", vertex, &x, &y, &z, 1);
732 render_item->u.shadow_polygon.x[i] = x + motion_new.position_east;
733 render_item->u.shadow_polygon.y[i] = y + motion_new.position_height;
734 render_item->u.shadow_polygon.z[i] = z + motion_new.position_north;
736 render_item->u.shadow_polygon.vertices = i;
741 static void line_object(void)
743 uint32_t vertex_address = REG_A[0], va;
749 printf("add object's line:\n");
752 /* allocate render item */
753 render_item_add(RENDER_ITEM_OBJECT_LINE);
756 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
760 vertex = m68k_read_memory_8(va++);
761 render_item->u.line.vertex[0] = vertex;
762 vertex = m68k_read_memory_8(va++);
763 render_item->u.line.vertex[1] = vertex;
765 /* allocate shadow item */
766 render_item_add(RENDER_ITEM_SHADOW_OBJECT_LINE);
767 render_item->u.shadow_line.x_pos = -motion_new.position_east;
768 render_item->u.shadow_line.y_pos = -motion_new.position_height;
769 render_item->u.shadow_line.z_pos = -motion_new.position_north;
771 /* apply only to not fixed objects (a fixed may be taxi interior) */
772 if (render_item_object_info && render_item_object_info->u.info.moving) {
774 vertex = m68k_read_memory_8(va++);
775 rc = use_coord("object", vertex, &x, &y, &z, 1);
778 render_item->u.shadow_line.x[0] = x + motion_new.position_east;
779 render_item->u.shadow_line.y[0] = y + motion_new.position_height;
780 render_item->u.shadow_line.z[0] = z + motion_new.position_north;
781 vertex = m68k_read_memory_8(va++);
782 rc = use_coord("object", vertex, &x, &y, &z, 1);
785 render_item->u.shadow_line.x[1] = x + motion_new.position_east;
786 render_item->u.shadow_line.y[1] = y + motion_new.position_height;
787 render_item->u.shadow_line.z[1] = z + motion_new.position_north;
791 /* coordinates ready for a beacon */
792 static void coord_beacon(void)
796 /* only 28 bits seem to be a correct signed int value */
797 x = (int32_t)(REG_D[3] << 4) / 16;
798 y = (int32_t)(REG_D[4] << 4) / 16;
799 z = (int32_t)(REG_D[5] << 4) / 16;
800 store_coord("beacon", 0, x, y, z, 1.0);
803 /* point of beacon */
804 static void point_beacon(void)
807 printf("add beacon's point:\n");
810 /* allocate render item */
811 render_item_add(RENDER_ITEM_BEACON_POINT);
814 gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
817 render_item->u.point.vertex = 0;
820 /* coordinates ready for a building (exterior) */
821 static void coord_building_exterior(void)
825 x = (int32_t)REG_D[3];
826 y = (int32_t)REG_D[4];
827 z = (int32_t)REG_D[5];
828 store_coord("building exterior", REG_A[0], x, y, z, 1.0);
831 /* polygon of building (exterior) */
832 static void poly_building_exterior(void)
835 uint32_t vertex_address = REG_A[0];
840 printf("add building's polygon:\n");
843 /* allocate render item */
844 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
847 color = m68k_read_memory_8(vertex_address++) << 8;
848 color |= m68k_read_memory_8(vertex_address++);
849 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
851 /* the vertex list is zero-terminated */
852 for (i = 0; i < MAX_POLYGON; i++) {
853 vertex = m68k_read_memory_8(vertex_address++);
854 if (vertex == 0 && i)
856 render_item->u.polygon.vertex[i] = vertex | 0x100;
858 render_item->u.polygon.vertices = i;
861 /* line of building (exterior) */
862 static void line_building_exterior(void)
864 uint32_t vertex_address = REG_A[0];
868 printf("add building's line:\n");
871 /* allocate render item */
872 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
875 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
878 vertex = m68k_read_memory_8(vertex_address++);
879 render_item->u.line.vertex[0] = vertex | 0x100;
880 vertex = m68k_read_memory_8(vertex_address++);
881 render_item->u.line.vertex[1] = vertex | 0x100;
884 /* coordinates ready for a building (interior) */
885 static void coord_building_interior(void)
888 int32_t height1, height2, height3, height4;
890 mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
891 store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
894 /* polygon of building (interior) */
895 static void poly_building_interior1to4(int level)
902 printf("add roof/floor's polygon at level %d:\n", level);
905 /* allocate render item */
906 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
909 color = m68k_read_memory_8(REG_A[0]) << 8;
910 color |= m68k_read_memory_8(REG_A[0] + 1);
911 gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
913 /* four vertices, one level */
914 for (i = 0; i < 4; i++) {
915 vertex = REG_A[(2 + i)];
916 render_item->u.interior14.vertex[i] = vertex;
918 render_item->u.interior14.level = level;
921 /* polygon of building (interior) */
922 static void poly_building_interior5to6(int level12, int level34)
927 printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
930 /* allocate render item */
931 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
934 color = m68k_read_memory_8(REG_A[0]) << 8;
935 color |= m68k_read_memory_8(REG_A[0] + 1);
936 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
938 /* two vertices, two levels */
939 render_item->u.interior56.vertex14 = REG_A[2];
940 render_item->u.interior56.vertex23 = REG_A[3];
941 render_item->u.interior56.level12 = level12;
942 render_item->u.interior56.level34 = level34;
945 /* wall part of a building */
946 static void wall_building(void)
949 printf("add wall:\n");
952 /* allocate render item */
953 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
956 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
958 /* two vertices, two levels */
959 render_item->u.interior56.vertex14 = REG_A[1];
960 render_item->u.interior56.vertex23 = REG_A[2];
961 /* get top level according to bit 12 in D3 */
962 render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
963 render_item->u.interior56.level34 = 1;
966 /* coordinates ready for comet tail */
967 static void coord_comet(void)
971 x = (int32_t)REG_D[3];
972 y = (int32_t)REG_D[4];
973 z = (int32_t)REG_D[5];
974 store_planets_coord("comet tail", REG_A[0], x, y, z);
977 /* polygon of comet tail */
978 static void poly_comet(void)
981 uint32_t vertex_address = REG_A[0];
986 printf("add comet's polygon:\n");
989 /* allocate render item */
990 render_item_add(RENDER_ITEM_COMET_POLYGON);
993 color = m68k_read_memory_8(vertex_address++) << 8;
994 color |= m68k_read_memory_8(vertex_address++);
995 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
997 /* the vertex list is zero-terminated */
998 for (i = 0; i < MAX_POLYGON; i++) {
999 vertex = m68k_read_memory_8(vertex_address++);
1000 if (vertex == 0 && i)
1002 render_item->u.polygon.vertex[i] = vertex;
1004 render_item->u.polygon.vertices = i;
1007 /* coordinates ready for lines of a road / ground surface */
1008 static void coord_line_road(void)
1013 y = -motion_new.position_height;
1015 store_coord("road", REG_A[0], x, y, z, 1.0);
1019 static void line_road(void)
1024 printf("add road's line:\n");
1027 /* allocate render item */
1028 render_item_add(RENDER_ITEM_ROAD_LINE);
1031 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
1035 render_item->u.line.vertex[0] = vertex;
1037 render_item->u.line.vertex[1] = vertex;
1040 /* coordinates ready for polygons of a road / ground surface */
1041 static void coord_poly_road(void)
1045 x = m68k_read_memory_32(320 + REG_A[0]);
1047 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
1048 y = -motion_new.position_height;
1049 z = m68k_read_memory_32(576 + REG_A[0]);
1051 store_coord("road/place", REG_A[0], x, y, z, 1.0);
1054 /* polygon of road */
1055 static void poly_road()
1058 uint32_t vertex_address = REG_A[0];
1063 printf("add road/place's polygon:\n");
1066 /* allocate render item */
1067 render_item_add(RENDER_ITEM_ROAD_POLYGON);
1070 color = m68k_read_memory_8(vertex_address++) << 8;
1071 color |= m68k_read_memory_8(vertex_address++);
1072 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1074 /* the vertex list is zero-terminated */
1075 for (i = 0; i < MAX_POLYGON; i++) {
1076 vertex = m68k_read_memory_8(vertex_address++);
1077 if (vertex == 0 && i)
1079 render_item->u.polygon.vertex[i] = vertex;
1081 render_item->u.polygon.vertices = i;
1084 /* coordinates ready for tags */
1085 static void coord_tags(void)
1089 x = (int16_t)REG_D[3];
1090 x += (int32_t)REG_A[1];
1091 y = (int16_t)REG_D[4];
1092 y += (int32_t)REG_A[2];
1093 z = (int16_t)REG_D[5];
1094 z += (int32_t)REG_A[3];
1095 store_coord("tags", REG_A[0], x, y, z, 1.0);
1098 /* coordinates ready for large tags */
1099 static void coord_tags2(void)
1103 x = (int16_t)REG_D[3];
1104 x += 2 * (int32_t)REG_A[1];
1105 y = (int16_t)REG_D[4];
1106 y += 2 * (int32_t)REG_A[2];
1107 z = (int16_t)REG_D[5];
1108 z += 2 * (int32_t)REG_A[3];
1109 /* note that large tags have double distance, so the resolution is vitrually doubled.
1110 * since we use interpolation and VR, we need to scale the vertex back to normal distance.
1112 store_coord("large tags", REG_A[0], x, y, z, 0.5);
1116 static void line_tags(int last_color)
1118 uint32_t vertex_address = REG_A[0];
1122 printf("add tag's line:\n");
1125 /* allocate render item */
1126 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
1130 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
1132 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
1135 vertex = m68k_read_memory_8(vertex_address++);
1136 render_item->u.line.vertex[0] = vertex | 0x200;
1137 vertex = m68k_read_memory_8(vertex_address++);
1138 render_item->u.line.vertex[1] = vertex | 0x200;
1141 /* polygon of tags */
1142 static void poly_tags(int last_color)
1144 uint32_t vertex_address = REG_A[0];
1149 printf("add tag's polygon:\n");
1152 /* allocate render item */
1153 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1157 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1159 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
1160 /* the vertex list is zero-terminated */
1161 for (i = 0; i < MAX_POLYGON; i++) {
1162 vertex = m68k_read_memory_8(vertex_address++);
1163 if (vertex == 0 && i)
1165 render_item->u.polygon.vertex[i] = vertex | 0x200;
1167 render_item->u.polygon.vertices = i;
1170 /* coordinates ready for planet */
1171 static void coord_planet(void)
1175 x = (int32_t)REG_D[3];
1176 y = (int32_t)REG_D[4];
1177 z = (int32_t)REG_D[5];
1178 store_planets_coord("planet", REG_A[0], x, y, z);
1182 static void draw_planet(int comet)
1185 uint32_t scale_index;
1186 double scale1, scale2;
1190 /* fixing (not noticable) bug in game: don't render comet twice */
1191 if (!comet && vertex == 116)
1195 printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1198 /* allocate render item */
1199 render_item_add(RENDER_ITEM_PLANET);
1203 /* make comet black on front side and bright on back */
1204 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
1205 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
1208 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
1209 /* use background color for dark side */
1210 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
1214 render_item->u.planet.vertex = vertex;
1216 /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
1217 * the long word 21584(A0) contains two scales
1218 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1219 * the upper word defines how much this scale is shifted to the left.
1221 scale_index = mercenary_planet_scale_index();
1222 scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 4096.0;
1223 scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
1224 render_item->u.planet.size = scale1 * scale2 / 256.0;
1228 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1231 printf("add stars\n");
1234 /* allocate render item */
1235 render_item_add(RENDER_ITEM_STARS);
1237 /* vertical offset */
1238 render_item->u.stars.v_offset = v_offset;
1240 /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
1241 render_item->u.stars.tilt = tilt;
1243 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1245 /* stars above zenith */
1246 render_item->u.stars.above_zenith = above_zenith;
1249 /* stars of interstellar flight */
1250 static void draw_stars_interstellar(void)
1256 printf("add interstellar stars\n");
1259 /* allocate render item */
1260 render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1263 count = REG_D[5] + 1;
1264 if (count > MAX_INTERSTARS) {
1265 print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
1268 for (i = 0; i < count; i++) {
1271 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1273 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1275 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1278 render_item->u.interstars.count = count;
1281 /* sun of interstellar flight (center dot) */
1282 static void draw_sun_interstellar(void)
1285 printf("add interstellar sun\n");
1288 /* allocate render item */
1289 render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1292 /* coordinates ready for polygons of islands */
1293 static void coord_islands(void)
1297 x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1298 x += (int32_t)REG_A[1];
1299 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1300 y = -motion_new.position_height;
1301 z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1302 z += (int32_t)REG_A[3];
1303 store_coord("island", REG_A[0], x, y, z, 1.0);
1306 /* polygon of island */
1307 static void poly_island()
1310 uint32_t vertex_address = REG_A[0];
1315 printf("add island:\n");
1318 /* allocate render item */
1319 render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1322 color = m68k_read_memory_8(vertex_address++) << 8;
1323 color |= m68k_read_memory_8(vertex_address++);
1324 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1326 /* the vertex list is zero-terminated */
1328 while (i < MAX_POLYGON) {
1329 vertex = m68k_read_memory_8(vertex_address++);
1330 if (vertex == 0 && i)
1332 /* skip mysterious points when rendering island */
1335 render_item->u.polygon.vertex[i] = vertex;
1338 render_item->u.polygon.vertices = i;
1342 static void draw_sights(void)
1345 printf("add sights:\n");
1348 /* allocate render item */
1349 render_item_add(RENDER_ITEM_SIGHTS);
1352 static int32_t coord_explosion_x, coord_explosion_y, coord_explosion_z;
1354 static void coord_explosion(void)
1356 coord_explosion_x = REG_D[3];
1357 coord_explosion_y = REG_D[4];
1358 coord_explosion_z = REG_D[5];
1361 static void draw_explosion(void)
1364 double scale1, scale2;
1367 printf("add explosion:\n");
1370 /* allocate render item */
1371 if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
1372 render_item_add(RENDER_ITEM_EXPLOSION);
1373 /* get color from render palette */
1374 color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
1375 gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
1376 render_item->u.explosion.count = 0;
1378 if (render_item->u.explosion.count == MAX_EXPLOSION)
1381 /* the D1 register contains two scales
1382 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1383 * the upper word defines how much this scale is shifted to the left.
1385 if ((int16_t)(REG_D[1] >> 16) < 0) {
1386 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1387 scale2 = (double)(256 >> -(int16_t)(REG_D[1] >> 16)) / 256.0;
1389 if ((int16_t)(REG_D[1] >> 16) <= 10) {
1390 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1391 scale2 = (double)(1 << (int16_t)(REG_D[1] >> 16));
1396 render_item->u.explosion.size[render_item->u.explosion.count] = scale1 * scale2;
1397 render_item->u.explosion.x[render_item->u.explosion.count] = coord_explosion_x;
1398 render_item->u.explosion.y[render_item->u.explosion.count] = coord_explosion_y;
1399 render_item->u.explosion.z[render_item->u.explosion.count] = coord_explosion_z;
1400 render_item->u.explosion.count++;
1403 /* get building data out of game data, so we use it to render shadow */
1404 static void draw_shadow_building(void)
1406 int32_t scale_x, scale_y, scale_z;
1408 uint16_t anim_flag, anim_x, anim_y, anim_z, anim_phase;
1409 uint32_t a0, a0s, a5, a6, a4;
1412 int32_t d3x, d4x, d5x;
1414 int line_from, line_to, point;
1416 struct render_item_vertices vertex;
1418 mercenary_get_building_exterior_info(&x, &z, &scale_x, &scale_y, &scale_z, &anim_flag, &anim_x, &anim_y, &anim_z, &anim_phase, &a4, &a0, &a5);
1419 x -= motion_new.position_east;
1420 y = -motion_new.position_height;
1421 z -= motion_new.position_north;
1423 /* list of all vetices */
1424 for (i = 1; i < 64; i++) {
1425 d3 = m68k_read_memory_16(a4);
1427 if (d3 <= (int16_t)0x8001)
1429 d4 = m68k_read_memory_16(a4);
1431 d5 = m68k_read_memory_16(a4);
1440 double angle = (double)anim_phase / 65536.0 * 2.0 * M_PI;
1441 /* animate around what axis ? */
1442 if ((int16_t)anim_flag > 0) {
1443 /* rotate around z */
1444 d3 = (d3x & 0xffff) - anim_x;
1445 d4 = (d4x & 0xffff) - anim_y;
1447 double cosd4 = (double) d4 * cos(angle);
1448 double sind3 = (double) d3 * sin(angle);
1449 double cosd3 = (double) d3 * cos(angle);
1450 double sind4 = (double) d4 * sin(angle);
1457 if ((int16_t)anim_flag == 0) {
1458 /* rotate around y */
1459 d3 = (d3x & 0xffff) - anim_x;
1460 d5 = (d5x & 0xffff) - anim_z;
1462 double cosd3 = (double) d3 * cos(angle);
1463 double sind5 = (double) d5 * sin(angle);
1464 double cosd5 = (double) d5 * cos(angle);
1465 double sind3 = (double) d3 * sin(angle);
1472 if ((int16_t)anim_flag < 0) {
1473 /* rotate around x */
1474 d4 = (d4x & 0xffff) - anim_y;
1475 d5 = (d5x & 0xffff) - anim_z;
1477 double cosd5 = (double) d5 * cos(angle);
1478 double sind4 = (double) d4 * sin(angle);
1479 double cosd4 = (double) d4 * cos(angle);
1480 double sind5 = (double) d5 * sin(angle);
1498 /* get all data sets */
1500 s = m68k_read_memory_16(a0);
1503 /* skip over distance cube */
1506 /* get address pointer to data set */
1507 a0s = m68k_read_memory_32(a0);
1510 /* walk through primitives (polygons and lines) */
1511 while ((d1index = m68k_read_memory_8(a0s++))) {
1512 /* pointer to primitive */
1513 a6 = m68k_read_memory_32(a5 + d1index*4);
1514 if ((m68k_read_memory_8(a6) & 0x40) == 0) {
1518 printf("add object's shadow polygon:\n");
1520 /* allocate render item */
1521 render_item_add(RENDER_ITEM_SHADOW_BUILDING_POLYGON);
1522 render_item->u.shadow_polygon.x_pos = x;
1523 render_item->u.shadow_polygon.y_pos = y;
1524 render_item->u.shadow_polygon.z_pos = z;
1526 while ((point = m68k_read_memory_8(a6++) >> 2)) {
1527 render_item->u.shadow_polygon.x[i] = vertex.x[point];
1528 render_item->u.shadow_polygon.y[i] = vertex.y[point];
1529 render_item->u.shadow_polygon.z[i] = vertex.z[point];
1532 render_item->u.shadow_polygon.vertices = i;
1533 } else if ((m68k_read_memory_16(a6) & 0x2000) == 0) {
1535 line_from = m68k_read_memory_8(a6 + 2) >> 2;
1536 line_to = m68k_read_memory_8(a6 + 3) >> 2;
1537 /* allocate render item */
1538 render_item_add(RENDER_ITEM_SHADOW_BUILDING_LINE);
1539 render_item->u.shadow_line.x_pos = x;
1540 render_item->u.shadow_line.y_pos = y;
1541 render_item->u.shadow_line.z_pos = z;
1542 render_item->u.shadow_line.x[0] = vertex.x[line_from];
1543 render_item->u.shadow_line.y[0] = vertex.y[line_from];
1544 render_item->u.shadow_line.z[0] = vertex.z[line_from];
1545 render_item->u.shadow_line.x[1] = vertex.x[line_to];
1546 render_item->u.shadow_line.y[1] = vertex.y[line_to];
1547 render_item->u.shadow_line.z[1] = vertex.z[line_to];
1553 /* stop event from CPU received */
1554 void render_capture_event(int event)
1557 case STOP_AT_CLEAR_SCREEN1:
1558 clear_screen(16); /* color 16 is raster split */
1559 /* in case of screen clearing on the ground, there is no roll */
1560 motion_new.orientation_roll = 0;
1562 case STOP_AT_CLEAR_SCREEN2:
1565 case STOP_AT_CLEAR_SCREEN3:
1566 clear_screen(-1); /* no ground (in universe) */
1568 case STOP_AT_DRAW_GROUND:
1571 case STOP_AT_INFO_OBJECT_MOVING:
1574 case STOP_AT_INFO_OBJECT_FIX:
1577 case STOP_AT_TAG_IS_OBJECT_1:
1580 case STOP_AT_TAG_IS_OBJECT_0:
1583 case STOP_AT_COORD_OBJECT:
1586 case STOP_AT_POLY_OBJECT_M3:
1589 case STOP_AT_POLY_OBJECT_M2:
1592 case STOP_AT_LINE_OBJECT:
1595 case STOP_AT_COORD_BEACON:
1598 case STOP_AT_POINT_BEACON:
1600 /* note: we may not call the point-renderer, because projected coordinates are invalid */
1601 mercenary_patch_render(draw_shadows);
1603 case STOP_AT_COORD_BUILDING_EXTERIOR:
1604 coord_building_exterior();
1606 case STOP_AT_POLY_BUILDING_EXTERIOR:
1607 poly_building_exterior();
1609 case STOP_AT_LINE_BUILDING_EXTERIOR:
1610 line_building_exterior();
1612 case STOP_AT_COORD_BUILDING_INTERIOR:
1613 coord_building_interior();
1615 case STOP_AT_POLY_BUILDING_INTERIOR1:
1617 interior_level12 = 1;
1618 interior_level34 = 1;
1620 case STOP_AT_POLY_BUILDING_INTERIOR2:
1622 interior_level12 = 2;
1623 interior_level34 = 2;
1625 case STOP_AT_POLY_BUILDING_INTERIOR3:
1626 /* door/window top */
1627 interior_level12 = 3;
1628 interior_level34 = 3;
1630 case STOP_AT_POLY_BUILDING_INTERIOR4:
1632 interior_level12 = 4;
1633 interior_level34 = 4;
1635 case STOP_AT_POLY_BUILDING_INTERIOR5:
1636 /* door/window top */
1637 interior_level12 = 2;
1638 interior_level34 = 3;
1640 case STOP_AT_POLY_BUILDING_INTERIOR6:
1642 interior_level12 = 1;
1643 interior_level34 = 4;
1645 case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1646 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1647 if (interior_level12 == 0) {
1648 print_info("Interior level is not set, please fix!\n");
1651 poly_building_interior1to4(interior_level12);
1652 interior_level12 = 0;
1654 case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1655 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1656 if (interior_level12 == 0) {
1657 print_info("Interior level is not set, please fix!\n");
1660 poly_building_interior5to6(interior_level12, interior_level34);
1661 interior_level12 = 0;
1663 case STOP_AT_WALL_BUILDING:
1666 case STOP_AT_COORD_COMET:
1669 case STOP_AT_MATRIX_COMET:
1670 case STOP_AT_MATRIX_PLANET:
1671 /* track the rotation matrix
1672 * if we have 0x42c44 matrix, we must add extra rotation to planet.
1673 * the rotation will change the view from the planet's surface */
1674 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1675 motion_new.planet_rotation = 1;
1677 motion_new.planet_rotation = 0;
1679 case STOP_AT_POLY_COMET:
1682 case STOP_AT_COORD_LINE_ROADS:
1685 case STOP_AT_LINE_ROADS:
1688 case STOP_AT_COORD_POLY_ROADS:
1691 case STOP_AT_LINE_ROADS_CENTER:
1692 /* we don't need to render center lines of roads, because there are polygons already
1693 * it does not make sense, since OpenGL has much higher resolution.
1696 case STOP_AT_POLY_ROADS:
1699 case STOP_AT_COORD_TAGS:
1702 case STOP_AT_COORD_TAGS2:
1705 case STOP_AT_LINE_TAGS1:
1708 case STOP_AT_LINE_TAGS2:
1711 case STOP_AT_POLY_TAGS1:
1714 case STOP_AT_POLY_TAGS2:
1717 case STOP_AT_COORD_PLANET:
1720 case STOP_AT_DRAW_PLANET:
1723 case STOP_AT_DRAW_COMET:
1726 case STOP_AT_DRAW_STARS_SPACE:
1727 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1728 draw_stars(0x1c0, 0, 0);
1730 case STOP_AT_DRAW_STARS_GROUND:
1731 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1732 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1734 case STOP_AT_DRAW_STARS_FLYING:
1735 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1736 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1738 case STOP_AT_DRAW_STARS_FLYING2:
1739 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1740 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1742 case STOP_AT_DRAW_STARS_INTERSTELLAR:
1743 draw_stars_interstellar();
1745 case STOP_AT_DRAW_SUN_INTERSTELLAR:
1746 draw_sun_interstellar();
1748 case STOP_AT_COORD_ISLANDS:
1751 case STOP_AT_POLY_ISLANDS:
1754 case STOP_AT_LINE_ISLANDS:
1755 /* this is not used, as i had noticed so far */
1756 puts("line island");
1757 #warning FIXME: this is used on LACHESIS to improve visibility of stripes on the ground. implement this and compate a version with lines to the version without lines
1759 case STOP_AT_DRAW_SIGHTS:
1762 case STOP_AT_POLY_UKN2:
1765 case STOP_AT_COORD_EXPLOSION:
1768 case STOP_AT_DRAW_EXPLOSION:
1771 case STOP_AT_PATCH_RENDER:
1772 mercenary_patch_render(draw_shadows);
1774 case STOP_AT_SHADOW_BUILDING:
1775 draw_shadow_building();
1784 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int no_inter)
1786 render_item_t *ri = NULL;
1789 print_info("Vertex %d is not a multiple of four!\n", vertex);
1792 if (vertex < 0x100) {
1793 if (!render_item_vertices_0) {
1794 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1797 ri = render_item_vertices_0;
1799 if (vertex < 0x200) {
1800 if (!render_item_vertices_1) {
1801 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1804 ri = render_item_vertices_1;
1807 if (vertex < 0x300) {
1808 if (!render_item_vertices_2) {
1809 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1812 ri = render_item_vertices_2;
1815 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1819 /* translate to original position */
1820 *x = ri->u.vertices.x[vertex] - motion_new.position_east;
1821 *y = ri->u.vertices.y[vertex] - motion_new.position_height;
1822 *z = ri->u.vertices.z[vertex] - motion_new.position_north;
1824 /* translate to floating (interpolated) position offset */
1825 *x -= interpolation.offset_east;
1826 *y -= interpolation.offset_height;
1827 *z -= interpolation.offset_north;
1830 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1836 static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1838 render_item_t *ri = NULL;
1841 print_info("Vertex %d is not a multiple of four!\n", vertex);
1844 if (vertex >= MAX_VERTEX) {
1845 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1848 if (interpolation.planets)
1849 ri = interpolation.planets;
1851 ri = render_item_vertices_0;
1853 print_info("Vertices item for planets verticies not yet set!\n");
1857 *x = ri->u.vertices.x[vertex];
1858 *y = ri->u.vertices.y[vertex];
1859 *z = ri->u.vertices.z[vertex];
1861 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1867 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1870 print_info("Vertex is not a multiple of four!\n");
1873 if (vertex >= MAX_INTERIOR_VERTEX) {
1874 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1877 if (level < 1 || level > 4) {
1878 print_info("Level %d is out of range (1..4)!\n", level);
1881 if (!render_item_vertices_interior) {
1882 print_info("Vertices item for interior verticies not yet set!\n");
1886 *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1887 *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1888 *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1889 /* translate to position back to original */
1890 *x -= motion_new.position_east;
1891 *y -= motion_new.position_height;
1892 *z -= motion_new.position_north;
1893 /* translate to floating (interpolated) position offset */
1894 *x -= interpolation.offset_east;
1895 *y -= interpolation.offset_height;
1896 *z -= interpolation.offset_north;
1899 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1905 /* this will calculate lighting parameters for sky and shadows */
1906 static void calculate_lighting(double sun_x, double sun_y, double sun_z, double *day, double *stars, double *shadow)
1910 // azimuth = atan2(sun_z, sun_x);
1912 /* how high is the sun (1.0 is zenith, < 0 is below horizon) */
1913 elevation = atan2(sun_y, sqrt(sun_x * sun_x + sun_z * sun_z)) / (M_PI / 2);
1915 printf("Elevation of SUN: %.3f\n", elevation);
1918 /* 'day' is how much day color is used for sky (1.0) or night color (0.0) */
1919 *day = (elevation - ELEVATION_SKY_NIGHT) / (ELEVATION_SKY_DAY - ELEVATION_SKY_NIGHT);
1925 printf("How much day: %.3f\n", *day);
1928 /* 'stars' is how much we see the stars (1.0) fully bright, (0.0) no stars */
1929 *stars = (elevation - ELEVATION_STARS_DAY) / (ELEVATION_STARS_NIGHT - ELEVATION_STARS_DAY);
1935 printf("How much stars: %.3f\n", *stars);
1938 /* 'shadow' is how much color (darkness) the shadow has (1.0) totally black, (0.0) not visible */
1939 *shadow = (elevation - ELEVATION_SHADOW_MIN) / (ELEVATION_SHADOW_MAX - ELEVATION_SHADOW_MIN);
1944 *shadow *= SHADOW_LEVEL;
1946 printf("How much shadow: %.3f\n", *shadow);
1951 /* renders one item from render list */
1952 void render_one_item(render_item_t *render_item, int vr, enum render_shadow shadow)
1954 switch (render_item->type) {
1955 case RENDER_ITEM_OBJECT_INFO:
1958 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1960 render_item_object_info = render_item;
1963 case RENDER_ITEM_VERTICES_0:
1966 printf("RENDER_ITEM_VERTICES_0\n");
1968 render_item_vertices_0 = render_item;
1971 case RENDER_ITEM_VERTICES_1:
1974 printf("RENDER_ITEM_VERTICES_1\n");
1976 render_item_vertices_1 = render_item;
1979 case RENDER_ITEM_VERTICES_2:
1982 printf("RENDER_ITEM_VERTICES_2\n");
1984 render_item_vertices_2 = render_item;
1987 case RENDER_ITEM_VERTICES_INTERIOR:
1990 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1992 if (interpolation.interior)
1993 render_item_vertices_interior = interpolation.interior;
1995 render_item_vertices_interior = render_item;
1998 case RENDER_ITEM_SKY:
2000 double x[4], y[4], z[4];
2002 if (shadow != RENDER_BEFORE_SHADOW)
2006 printf("RENDER_ITEM_SKY\n");
2009 if (draw_shadows && ground_index >= 0) {
2010 uint16_t day, night;
2011 double day_red, day_green, day_blue;
2012 double night_red, night_green, night_blue;
2015 calculate_lighting(sun_pos_x, sun_pos_y, sun_pos_z, &day_factor, &stars_bright, &shadow_level);
2018 mercenary_get_sky_colors(&day, &night);
2019 /* shift them to the original format (atari style) */
2020 gamecolor2gl(&day_red, &day_green, &day_blue, day >> 1);
2021 gamecolor2gl(&night_red, &night_green, &night_blue, night >> 1);
2022 sky_color_red = day_red * day_factor + night_red * (1.0 - day_factor);
2023 sky_color_green = day_green * day_factor + night_green * (1.0 - day_factor);
2024 sky_color_blue = day_blue * day_factor + night_blue * (1.0 - day_factor);
2025 opengl_render_color(sky_color_red, sky_color_green, sky_color_blue, 1.0);
2028 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
2029 /* create box to fill view */
2030 x[0] = x[1] = y[1] = y[2] = -1000;
2031 x[2] = x[3] = y[0] = y[3] = 1000;
2032 z[0] = z[1] = z[2] = z[3] = 1000;
2033 opengl_render_polygon_and_line(x, y, z, 4);
2034 z[0] = z[1] = z[2] = z[3] = -1000;
2035 opengl_render_polygon_and_line(x, y, z, 4);
2036 x[0] = x[1] = z[1] = z[2] = -1000;
2037 x[2] = x[3] = z[0] = z[3] = 1000;
2038 y[0] = y[1] = y[2] = y[3] = 1000;
2039 opengl_render_polygon_and_line(x, y, z, 4);
2040 y[0] = y[1] = y[2] = y[3] = -1000;
2041 opengl_render_polygon_and_line(x, y, z, 4);
2042 y[0] = y[1] = z[1] = z[2] = -1000;
2043 y[2] = y[3] = z[0] = z[3] = 1000;
2044 x[0] = x[1] = x[2] = x[3] = 1000;
2045 opengl_render_polygon_and_line(x, y, z, 4);
2046 x[0] = x[1] = x[2] = x[3] = -1000;
2047 opengl_render_polygon_and_line(x, y, z, 4);
2050 case RENDER_ITEM_GROUND:
2053 double x[4], y[4], z[4];
2056 if (shadow != RENDER_BEFORE_SHADOW)
2060 printf("RENDER_ITEM_GROUND\n");
2063 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
2064 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
2065 /* create huge square */
2066 x[0] = x[1] = z[1] = z[2] = -10000000;
2067 x[2] = x[3] = z[0] = z[3] = 10000000;
2068 y[0] = y[1] = y[2] = y[3] = -1000;
2070 for (i = 0; i < 4; i++)
2071 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2073 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
2076 case RENDER_ITEM_OBJECT_POLYGON:
2077 case RENDER_ITEM_TAG_POLYGON_OBJECT:
2078 case RENDER_ITEM_TAG_POLYGON_OTHER:
2079 case RENDER_ITEM_ISLAND_POLYGON:
2083 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2087 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON) {
2088 if (shadow != RENDER_BEFORE_SHADOW)
2091 if (shadow != RENDER_AFTER_SHADOW)
2096 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
2097 printf("RENDER_ITEM_OBJECT_POLYGON\n");
2098 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
2099 printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
2100 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
2101 printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
2102 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
2103 printf("RENDER_ITEM_ISLAND_POLYGON\n");
2106 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
2107 if ((render_item->type == RENDER_ITEM_OBJECT_POLYGON || render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT) && render_item_object_info && !render_item_object_info->u.info.moving) {
2108 // GET_ORIENTATION_FIX;
2113 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2114 /* get and rotate vertex */
2115 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2117 rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
2120 /* fixed objects are pre-scaled by 16, so we correct this */
2122 x[i] /= FIX_OBJECT_SCALE;
2123 y[i] /= FIX_OBJECT_SCALE;
2124 z[i] /= FIX_OBJECT_SCALE;
2126 /* interpolate motion, if object is moving */
2127 if ((render_item->type == RENDER_ITEM_OBJECT_POLYGON || render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT) && render_item_object_info && render_item_object_info->u.info.moving) {
2128 for (o = 0; o < interpolation.object_count; o++) {
2129 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
2132 if (o < interpolation.object_count) {
2133 x[i] += interpolation.object_offset_east[o];
2134 y[i] += interpolation.object_offset_height[o];
2135 z[i] += interpolation.object_offset_north[o];
2139 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2142 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
2145 case RENDER_ITEM_OBJECT_LINE:
2146 case RENDER_ITEM_TAG_LINE_OBJECT:
2147 case RENDER_ITEM_TAG_LINE_OTHER:
2151 double x[2], y[2], z[2];
2155 if (shadow != RENDER_AFTER_SHADOW)
2159 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
2160 printf("RENDER_ITEM_OBJECT_LINE\n");
2161 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
2162 printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
2163 if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
2164 printf("RENDER_ITEM_TAG_LINE_OTHER\n");
2167 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
2168 if ((render_item->type == RENDER_ITEM_OBJECT_LINE || render_item->type == RENDER_ITEM_TAG_LINE_OBJECT) && render_item_object_info && !render_item_object_info->u.info.moving) {
2169 // GET_ORIENTATION_FIX;
2174 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2175 /* get and rotate vertex */
2176 for (i = 0; i < 2; i++) {
2178 rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
2181 /* fixed objects are pre-scaled by 16, so we correct this */
2183 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT) {
2184 x[i] /= FIX_OBJECT_SCALE_TAG;
2185 y[i] /= FIX_OBJECT_SCALE_TAG;
2186 z[i] /= FIX_OBJECT_SCALE_TAG;
2188 x[i] /= FIX_OBJECT_SCALE;
2189 y[i] /= FIX_OBJECT_SCALE;
2190 z[i] /= FIX_OBJECT_SCALE;
2193 /* interpolate motion, if object is moving */
2194 if ((render_item->type == RENDER_ITEM_OBJECT_LINE || render_item->type == RENDER_ITEM_TAG_LINE_OBJECT) && render_item_object_info && render_item_object_info->u.info.moving) {
2195 for (o = 0; o < interpolation.object_count; o++) {
2196 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
2199 if (o < interpolation.object_count) {
2200 x[i] += interpolation.object_offset_east[o];
2201 y[i] += interpolation.object_offset_height[o];
2202 z[i] += interpolation.object_offset_north[o];
2206 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2209 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2212 case RENDER_ITEM_BEACON_POINT:
2218 if (shadow != RENDER_AFTER_SHADOW)
2222 printf("RENDER_ITEM_BEACON_POINT\n");
2225 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
2227 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
2231 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
2233 opengl_render_point(x, y, z, 0.0);
2236 case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
2239 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2244 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
2247 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2248 /* get and rotate vertex */
2249 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2251 rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
2255 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2258 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
2261 case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
2264 double x[2], y[2], z[2];
2268 if (shadow != RENDER_AFTER_SHADOW)
2272 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
2275 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2276 /* get and rotate vertex */
2277 for (i = 0; i < 2; i++) {
2279 rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2283 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2286 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2289 case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
2292 double x[4], y[4], z[4];
2296 if (shadow != RENDER_AFTER_SHADOW)
2300 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
2303 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
2304 /* get and rotate vertex */
2305 for (i = 0; i < 4; i++) {
2307 rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
2311 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2314 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
2317 case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
2320 double x[4], y[4], z[4];
2325 if (shadow != RENDER_AFTER_SHADOW)
2329 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
2332 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
2333 /* get and rotate vertex */
2334 for (i = 0; i < 4; i++) {
2336 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
2337 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2338 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2342 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2345 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
2348 case RENDER_ITEM_BUILDING_INTERIOR_WALL:
2351 double x[4], y[4], z[4];
2356 if (shadow != RENDER_AFTER_SHADOW)
2360 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
2363 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
2364 /* chedck if wall is a rectangle or a line */
2365 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
2366 /* get and rotate vertex */
2367 for (i = 0; i < 4; i++) {
2369 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
2370 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2371 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2375 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2378 opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
2380 /* get and rotate vertex */
2381 for (i = 0; i < 2; i++) {
2383 vertex = render_item->u.interior56.vertex14;
2384 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2385 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2389 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2392 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2396 case RENDER_ITEM_COMET_POLYGON:
2399 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2400 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2403 double rotate_sky = 0.0;
2405 if (shadow != RENDER_BEFORE_SHADOW)
2409 printf("RENDER_ITEM_COMET_POLYGON\n");
2412 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2413 /* get and rotate vertex */
2414 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2416 rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
2420 if (motion_new.planet_rotation) {
2421 if (fix_sky_rotation)
2423 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
2425 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x[i], &y[i], &z[i]);
2428 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
2431 case RENDER_ITEM_ROAD_LINE:
2434 double x[2], y[2], z[2];
2438 if (shadow != RENDER_BEFORE_SHADOW)
2442 printf("RENDER_ITEM_ROAD_LINE\n");
2445 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2446 /* get and rotate vertex */
2447 for (i = 0; i < 2; i++) {
2449 rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2453 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2456 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2459 case RENDER_ITEM_ROAD_POLYGON:
2462 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2464 uint32_t vertex, vertex_prev, vertex_next;
2465 double x_current, y_current, z_current;
2466 double x_prev, y_prev, z_prev;
2467 double x_next, y_next, z_next;
2471 if (shadow != RENDER_BEFORE_SHADOW)
2475 printf("RENDER_ITEM_ROAD_POLYGON\n");
2478 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2479 /* get and rotate vertex */
2481 vertices_num = render_item->u.polygon.vertices;
2482 for (v = 0; v < vertices_num; v++) {
2484 vertex = render_item->u.polygon.vertex[v];
2485 rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
2488 /* check for road extension, so we extend the road to the given end point */
2489 if (extend_roads && vertex >= 0xf0) {
2490 /* previous vertex */
2491 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
2492 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
2496 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
2497 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
2500 /* extend vertices to end point position
2501 * change x or z coordinate, whatever is greater
2503 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
2504 x_prev = x_next = x_current;
2506 z_prev = z_next = z_current;
2507 /* store vertices */
2512 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2513 if (i++ == MAX_POLYGON)
2519 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2520 if (i++ == MAX_POLYGON)
2524 /* no extension, just keep the current point as is */
2529 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2530 if (i++ == MAX_POLYGON)
2535 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2538 case RENDER_ITEM_PLANET:
2541 double front_red, front_green, front_blue, back_red, back_green, back_blue;
2542 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2543 double sun_x, sun_y, sun_z, angle_sun_h;
2544 double loc_x, loc_y, loc_z, angle_loc_h, angle_loc_v;
2545 double circle_x[PLANET_VERTICES], circle_y[PLANET_VERTICES], circle_z[PLANET_VERTICES];
2546 double crescent_x[PLANET_VERTICES], crescent_y[PLANET_VERTICES], crescent_z[PLANET_VERTICES];
2547 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
2548 double dist, size, angle, fabs_angle, crescent;
2552 double rotate_sky = 0.0;
2554 if (shadow != RENDER_BEFORE_SHADOW)
2558 printf("RENDER_ITEM_PLANET\n");
2561 /* color of planets */
2562 front_red = render_item->u.planet.front_red;
2563 front_green = render_item->u.planet.front_green;
2564 front_blue = render_item->u.planet.front_blue;
2565 back_red = render_item->u.planet.back_red;
2566 back_green = render_item->u.planet.back_green;
2567 back_blue = render_item->u.planet.back_blue;
2568 if (draw_shadows && ground_index >= 0) {
2569 /* front color is blended by sky */
2570 front_red = front_red * (1.0 - sky_color_red) + sky_color_red;
2571 front_green = front_green * (1.0 - sky_color_green) + sky_color_green;
2572 front_blue = front_blue * (1.0 - sky_color_blue) + sky_color_blue;
2573 back_red = sky_color_red * (1.0 - stars_bright);
2574 back_green = sky_color_green * (1.0 - stars_bright);
2575 back_blue = sky_color_blue * (1.0 - stars_bright);
2579 rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
2582 rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
2586 size = render_item->u.planet.size;
2588 if (motion_new.planet_rotation) {
2589 if (fix_sky_rotation)
2591 rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
2592 rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
2594 /* store sun location */
2600 rotate_coordinate(roll, pitch, yaw + rotate_sky, &sun_x, &sun_y, &sun_z);
2601 rotate_coordinate(roll, pitch, yaw + rotate_sky, &loc_x, &loc_y, &loc_z);
2603 /* distance to planet */
2604 dist = sqrt(loc_x * loc_x + loc_y * loc_y + loc_z * loc_z);
2606 /* calculate direction of the sun */
2607 angle_sun_h = atan2(sun_x, sun_z);
2608 angle_loc_h = atan2(loc_x, loc_z);
2609 angle_loc_v = atan2(loc_y, sqrt(loc_x * loc_x + loc_z * loc_z));
2610 /* angle between planets */
2611 angle = angle_sun_h - angle_loc_h;
2613 angle -= 2.0 * M_PI;
2615 angle += 2.0 * M_PI;
2616 /* absolute angle to be used as crescent */
2617 fabs_angle = fabs(angle);
2618 if (fabs_angle > M_PI / 2.0)
2619 fabs_angle = M_PI - fabs_angle;
2621 /* on which side are we (sun is always bright, vertex == 0) */
2622 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
2623 /* get front side color */
2624 opengl_render_color(front_red, front_green, front_blue, debug_opacity);
2626 /* get back side color */
2627 opengl_render_color(back_red, back_green, back_blue, debug_opacity);
2630 /* create and render cicle */
2631 crescent = sin((1.0 - fabs_angle / (M_PI / 2)) * (M_PI / 2.0));
2633 for (i = 0; i < PLANET_VERTICES; i++) {
2634 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2635 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2636 circle_x[i] = _sin * planet_aspect;
2639 crescent_x[i] = circle_x[i] * crescent;
2640 crescent_y[i] = circle_y[i];
2641 crescent_z[i] = circle_z[i];
2642 /* rotate circle and cresent towards observer (billboarding) */
2643 rotate_coordinate(0.0, -angle_loc_v, 0.0, &circle_x[i], &circle_y[i], &circle_z[i]);
2644 rotate_coordinate(0.0, 0.0, angle_loc_h, &circle_x[i], &circle_y[i], &circle_z[i]);
2645 rotate_coordinate(0.0, -angle_loc_v, 0.0, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2646 rotate_coordinate(0.0, 0.0, angle_loc_h, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2649 for (i = 0; i < PLANET_VERTICES; i++) {
2650 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2651 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2652 circle_x[i] = _sin * planet_aspect;
2655 crescent_x[i] = circle_x[i] * crescent;
2656 crescent_y[i] = circle_y[i];
2657 crescent_z[i] = circle_z[i];
2660 for (i = 0; i < PLANET_VERTICES; i++) {
2661 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2662 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2663 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2665 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2667 if (render_item->u.planet.vertex == 0) {
2668 /* sun has no crescent */
2672 /* on which side are we */
2673 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
2674 /* get back side color */
2675 opengl_render_color(back_red, back_green, back_blue, debug_opacity);
2677 /* get front side color */
2678 opengl_render_color(front_red, front_green, front_blue, debug_opacity);
2681 /* create and render crescent */
2682 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2684 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2685 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2686 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2687 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2689 _sin = sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2690 for (; i < PLANET_VERTICES; i++) {
2691 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2692 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2693 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2697 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2698 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2699 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2700 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2702 for (; i < PLANET_VERTICES; i++) {
2703 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2704 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2705 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2708 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2709 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
2712 case RENDER_ITEM_STARS:
2714 double tilt_offset = 0;
2715 double x_offset = 0;
2717 double view_width, yaw = interpolation.orientation_raw_yaw;
2718 double pitch = interpolation.orientation_raw_pitch;
2719 uint32_t table, table_start;
2722 double red, green, blue;
2723 double rotate_sky = 0.0;
2725 if (shadow != RENDER_BEFORE_SHADOW)
2729 printf("RENDER_ITEM_STARS\n");
2732 /* no stars at day */
2733 if (stars_bright == 0.0)
2736 /* use default fov of 64 to calculate z distance */
2737 z = 160.0 / frustum_slope_64;
2739 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2742 for (i = 0; i < 16; i++)
2743 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2745 if (!vr && !improve_stars) {
2746 /* render legacy stars (as with the original game) */
2748 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
2749 * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
2750 * then we half it, so we get to the center via 91
2753 if (render_item->u.stars.above_zenith)
2755 yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2757 table = mercenary_star_table();
2758 table_start = table + m68k_read_memory_16(table);
2759 table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
2760 yaw = yaw / (double)0x800 * 1800.0;
2762 if (render_item->u.stars.above_zenith)
2763 pitch = 0x200 - pitch;
2764 pitch = fmod(pitch + 65536.0, 0x400);
2765 pitch -= render_item->u.stars.v_offset;
2767 pitch = pitch * (double)0x6ccc / 65536.0;
2770 x = m68k_read_memory_16(table);
2773 table = table_start;
2775 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2779 /* special case where we tilt the view when flying on the planet */
2780 if (render_item->u.stars.tilt) {
2781 /* use offset as given by game: 160 is half of the screen width
2782 * we extend the width to the actual FOV, so it fits
2784 tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2786 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2788 if (render_item->u.stars.above_zenith) {
2789 x = (double)(view_width - 1) - x;
2793 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2794 opengl_render_color(red, green, blue, debug_opacity * stars_bright);
2796 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2799 /* render ovr stars, render star table as a sphere */
2803 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2805 if (render_item->u.stars.above_zenith)
2808 table = mercenary_star_table();
2809 table += m68k_read_memory_16(table);
2812 x = m68k_read_memory_16(table);
2816 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - 108.796875;
2819 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2820 opengl_render_color(red, green, blue, debug_opacity * stars_bright);
2822 h = (900.0 - x + 160) / 900.0 * M_PI;
2823 v1 = (68.0 - y) / 900.0 * M_PI;
2824 /* wrap star field (is actually 86.2 degrees high) */
2826 v2 = v1 + (86.2 / 180.0 * M_PI);
2828 v2 = v1 - (86.2 / 180.0 * M_PI);
2829 if (v1 < 0.934 && v1 > -0.934) {
2830 /* be sure that v1 will not exceed PI/2 */
2831 v1 = v1 / cos(v1); /* FIXME: there should be a better way to distribute stars equally */
2832 x = -sin(h) * cos(v1);
2834 z = cos(h) * cos(v1);
2835 if (motion_new.planet_rotation) {
2836 if (fix_sky_rotation)
2838 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2840 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2841 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2843 if (v2 < 0.934 && v2 > -0.934) {
2844 /* be sure that v2 will not exceed PI/2 */
2845 v2 = v2 / cos(v2) /* FIXME: there should be a better way to distribute stars equally */;
2846 x = -sin(h) * cos(v2);
2848 z = cos(h) * cos(v2);
2849 if (motion_new.planet_rotation) {
2850 if (fix_sky_rotation)
2852 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2854 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2855 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2861 case RENDER_ITEM_INTERSTELLAR_STARS:
2866 double red, green, blue;
2868 if (shadow != RENDER_BEFORE_SHADOW)
2872 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2874 /* use default fov of 64 to calculate z distance */
2875 z = 160.0 / frustum_slope_64;
2878 for (i = 0; i < 16; i++)
2879 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2881 for (i = 0; i < render_item->u.interstars.count; i++) {
2882 gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
2883 opengl_render_color(red, green, blue, debug_opacity);
2885 opengl_render_point((160.0 - (double)render_item->u.interstars.x[i]) * 100, (68.0 - (double)render_item->u.interstars.y[i]) * 100, z * 100, 0.0);
2889 case RENDER_ITEM_INTERSTELLAR_SUN:
2891 double red, green, blue;
2893 if (shadow != RENDER_BEFORE_SHADOW)
2897 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2900 gamecolor2gl(&red, &green, &blue, 0x777);
2901 opengl_render_color(red, green, blue, debug_opacity);
2903 opengl_render_point(0.0, 0.0, 1000000.0, 0.0);
2906 case RENDER_ITEM_SIGHTS:
2908 double x[4], y[4], z[4];
2909 double red, green, blue;
2911 if (shadow != RENDER_AFTER_SHADOW)
2915 printf("RENDER_ITEM_SIGHTS\n");
2917 /* use default fov of 64 to calculate z distance */
2918 z[0] = z[1] = z[2] = z[3] = SIGHT_DIST;
2921 gamecolor2gl(&red, &green, &blue, 0x777);
2922 opengl_render_color(red, green, blue, debug_opacity);
2924 y[0] = y[3] = -1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2925 y[1] = y[2] = 1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2926 x[0] = x[1] = -16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2927 x[2] = x[3] = -8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2928 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2929 x[0] = x[1] = 8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2930 x[2] = x[3] = 16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2931 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2934 case RENDER_ITEM_EXPLOSION:
2937 double loc_x, loc_y, loc_z, size;
2938 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2941 if (shadow != RENDER_AFTER_SHADOW)
2945 printf("RENDER_ITEM_EXPLOSION\n");
2947 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2949 for (e = 0; e < render_item->u.explosion.count; e++) {
2950 loc_x = render_item->u.explosion.x[e];
2951 loc_y = render_item->u.explosion.y[e];
2952 loc_z = render_item->u.explosion.z[e];
2954 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2955 /* calculate size from projected size and z (256 is the distance of the game's projection plane) */
2956 size = render_item->u.explosion.size[e] * (fabs(loc_z) / 256.0);
2957 /* create and render cicle */
2958 for (i = 0; i < EXPLOSION_VERTICES; i++) {
2959 x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * explosion_aspect;
2960 y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
2963 opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
2964 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point */
2968 case RENDER_ITEM_SHADOW_BUILDING_POLYGON:
2969 case RENDER_ITEM_SHADOW_BUILDING_LINE:
2970 case RENDER_ITEM_SHADOW_OBJECT_POLYGON:
2971 case RENDER_ITEM_SHADOW_OBJECT_LINE:
2974 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2975 double shadow_x, shadow_z;
2979 if (shadow != RENDER_AT_SHADOW)
2983 if (render_item->type == RENDER_ITEM_SHADOW_POLYGON)
2984 printf("RENDER_ITEM_SHADOW_POLYGON\n");
2985 if (render_item->type == RENDER_ITEM_SHADOW_LINE)
2986 printf("RENDER_ITEM_SHADOW_LINE\n");
2989 if (!sun_valid || sun_pos_y < 1.0)
2992 if (shadow_level == 0.0)
2995 /* calculate shadow */
2996 shadow_x = -sun_pos_x / sun_pos_y;
2997 shadow_z = -sun_pos_z / sun_pos_y;
2999 opengl_render_color_alpha(0, 0, 0, shadow_level);
3001 if (render_item->type == RENDER_ITEM_SHADOW_BUILDING_POLYGON
3002 || render_item->type == RENDER_ITEM_SHADOW_OBJECT_POLYGON) {
3003 /* get and rotate vertex */
3004 for (i = 0; i < render_item->u.shadow_polygon.vertices; i++) {
3005 x[i] = render_item->u.shadow_polygon.x[i];
3006 y[i] = render_item->u.shadow_polygon.y[i];
3007 z[i] = render_item->u.shadow_polygon.z[i];
3008 /* interpolate motion, if object is moving */
3009 if (render_item->type == RENDER_ITEM_SHADOW_OBJECT_POLYGON && render_item_object_info && render_item_object_info->u.info.moving) {
3010 for (o = 0; o < interpolation.object_count; o++) {
3011 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
3014 if (o < interpolation.object_count) {
3015 x[i] += interpolation.object_offset_east[o];
3016 y[i] += interpolation.object_offset_height[o];
3017 z[i] += interpolation.object_offset_north[o];
3020 /* flatten polygon into shadow */
3021 x[i] += y[i] * shadow_x;
3022 z[i] += y[i] * shadow_z;
3024 /* apply interpolation */
3025 x[i] -= interpolation.offset_east;
3026 y[i] -= interpolation.offset_height;
3027 z[i] -= interpolation.offset_north;
3028 /* apply position */
3029 x[i] += render_item->u.shadow_polygon.x_pos;
3030 y[i] += render_item->u.shadow_polygon.y_pos;
3031 z[i] += render_item->u.shadow_polygon.z_pos;
3033 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
3036 opengl_render_polygon(x, y, z, render_item->u.shadow_polygon.vertices, 0); /* no back face culling */
3038 if (render_item->type == RENDER_ITEM_SHADOW_BUILDING_LINE
3039 || render_item->type == RENDER_ITEM_SHADOW_OBJECT_LINE) {
3040 /* get and rotate vertex */
3041 for (i = 0; i < 2; i++) {
3042 x[i] = render_item->u.shadow_line.x[i];
3043 y[i] = render_item->u.shadow_line.y[i];
3044 z[i] = render_item->u.shadow_line.z[i];
3045 /* interpolate motion, if object is moving */
3046 if (render_item->type == RENDER_ITEM_SHADOW_OBJECT_LINE && render_item_object_info && render_item_object_info->u.info.moving) {
3047 for (o = 0; o < interpolation.object_count; o++) {
3048 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
3051 if (o < interpolation.object_count) {
3052 x[i] += interpolation.object_offset_east[o];
3053 y[i] += interpolation.object_offset_height[o];
3054 z[i] += interpolation.object_offset_north[o];
3057 /* flatten polygon into shadow */
3058 x[i] += y[i] * shadow_x;
3059 z[i] += y[i] * shadow_z;
3061 /* apply interpolation */
3062 x[i] -= interpolation.offset_east;
3063 y[i] -= interpolation.offset_height;
3064 z[i] -= interpolation.offset_north;
3065 /* apply position */
3066 x[i] += render_item->u.shadow_line.x_pos;
3067 y[i] += render_item->u.shadow_line.y_pos;
3068 z[i] += render_item->u.shadow_line.z_pos;
3070 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
3073 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
3078 print_info("Unknown render item type, please fix!\n");
3086 static double interpolate_orientation(double old, double new, double inter)
3088 double turn = new - old;
3095 /* don't interpolate, if our rotation was too fast.
3096 * e.g: taxi drive around corder, load/quit game, ...
3098 if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
3101 new = old + turn * inter;
3111 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
3113 int16_t turn = (new - old) & 0x3ff;
3118 /* don't interpolate, if our rotation was too fast.
3119 * e.g: taxi drive around corder, load/quit game, ...
3121 if (turn > 0x200 / 8 || turn < -0x200 / 8)
3124 /* don't do modulo 0x400, since the user of this data does it */
3125 return (double)old + (double)turn * inter;
3128 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
3132 /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
3133 if (ground_index >= 0)
3134 offset = wrap_int28(old - new);
3136 offset = (int32_t)(old - new);
3138 if (limit > 0 && (offset > limit || offset < -limit))
3141 return offset * (1.0 - inter);
3144 static render_item_t *interpolate_door(double inter)
3146 static render_item_t interpolated;
3147 render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
3150 /* find old and new vertices */
3151 while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
3152 old_vertices = old_vertices->next;
3153 while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
3154 new_vertices = new_vertices->next;
3156 /* building does not exist in old or new render */
3157 if (!old_vertices || !new_vertices)
3160 memcpy(&interpolated, new_vertices, sizeof(interpolated));
3161 ii = MAX_INTERIOR_VERTEX >> 2;
3162 for (i = 0; i < ii; i++) {
3163 /* vertex must exist in both frames */
3164 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
3166 /* all verices must not have be too far away */
3167 if (fabs(old_vertices->u.vertices_interior.x[i] - new_vertices->u.vertices_interior.x[i]) > 100.0)
3169 if (fabs(old_vertices->u.vertices_interior.z[i] - new_vertices->u.vertices_interior.z[i]) > 100.0)
3172 interpolated.u.vertices_interior.x[i] =
3173 (double)old_vertices->u.vertices_interior.x[i] * (1.0 - inter) +
3174 (double)new_vertices->u.vertices_interior.x[i] * inter;
3175 interpolated.u.vertices_interior.z[i] =
3176 (double)old_vertices->u.vertices_interior.z[i] * (1.0 - inter) +
3177 (double)new_vertices->u.vertices_interior.z[i] * inter;
3179 for (i = 0; i < 4; i++) {
3180 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
3184 return &interpolated;
3187 /* make a list of objects that moved and store their displacement */
3188 static void interpolate_objects(double inter)
3190 render_item_t *old_info, *new_info;
3193 /* hunt for objects that exist in both (old and new) lists and moved */
3195 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
3197 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
3200 if (!new_info->u.info.moving)
3202 /* interiors don't move */
3203 if (new_info->u.info.id < 0)
3205 /* check matching object with same ID */
3206 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
3208 if (old_info->type != RENDER_ITEM_OBJECT_INFO)
3211 if (!old_info->u.info.moving)
3214 if (old_info->u.info.id == new_info->u.info.id)
3217 /* no matching object found */
3221 if (old_info->u.info.east == new_info->u.info.east
3222 && old_info->u.info.height == new_info->u.info.height
3223 && old_info->u.info.north == new_info->u.info.north)
3225 /* interpolate and store */
3226 interpolation.object_id[count] = new_info->u.info.id;
3227 interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
3228 interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
3229 interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
3230 if (count++ == MAX_MOVING_OBJECTS)
3233 interpolation.object_count = count;
3236 /* make a vertex list of interpolated planets */
3237 static render_item_t *interpolate_planets(double inter)
3239 static render_item_t interpolated;
3240 render_item_t *old_info, *new_info;
3241 render_item_t *old_vertices = NULL, *new_vertices = NULL;
3244 /* get vertices for planets/comet */
3245 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
3246 if (old_info->type == RENDER_ITEM_VERTICES_0)
3247 old_vertices = old_info;
3248 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
3249 if (old_info->type == RENDER_ITEM_COMET_POLYGON)
3252 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
3253 if (new_info->type == RENDER_ITEM_VERTICES_0)
3254 new_vertices = new_info;
3255 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
3256 if (new_info->type == RENDER_ITEM_COMET_POLYGON)
3260 /* check for existing planet's vertices and if planets are rendered in both lists (old and new) */
3261 if (old_info == NULL || new_info == NULL || old_vertices == NULL || new_vertices == NULL)
3264 /* interpolate vertices */
3265 for (i = 0; i < (MAX_VERTEX >> 2); i++) {
3266 interpolated.u.vertices.x[i] = old_vertices->u.vertices.x[i] * (1.0 - inter) + new_vertices->u.vertices.x[i] * inter;
3267 interpolated.u.vertices.y[i] = old_vertices->u.vertices.y[i] * (1.0 - inter) + new_vertices->u.vertices.y[i] * inter;
3268 interpolated.u.vertices.z[i] = old_vertices->u.vertices.z[i] * (1.0 - inter) + new_vertices->u.vertices.z[i] * inter;
3271 return &interpolated;
3274 /* always renders NEW! items
3275 * use inter == 1.0 to render motion to vertices of NEW items
3276 * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
3277 * return 0, if the scene was rendered, returns < 0, if there is no scene
3279 int render_all_items(double inter, int vr)
3281 render_item_object_info = NULL;
3282 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
3283 render_item_vertices_interior = NULL;
3284 render_item_vertices_planets = NULL;
3286 /* no interpolation when leaving or entering planet to/from space */
3287 if ((last_ground_index < 0 && ground_index >= 0)
3288 || (last_ground_index >= 0 && ground_index < 0)) {
3292 /* reset interpolation */
3293 memset(&interpolation, 0, sizeof(interpolation));
3294 interpolation.orientation_roll = motion_new.orientation_roll;
3295 interpolation.orientation_pitch = motion_new.orientation_pitch;
3296 interpolation.orientation_yaw = motion_new.orientation_yaw;
3297 interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
3298 interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
3299 interpolation.planet_inclination = motion_new.planet_inclination;
3300 interpolation.planet_azimuth = motion_new.planet_azimuth;
3301 //printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
3303 /* do interpolation */
3304 if (inter != 1.0 && render_list_old) {
3305 /* interpolate orientation */
3306 interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
3307 interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
3308 interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
3309 interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
3310 interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
3311 interpolation.planet_inclination = interpolate_orientation(motion_old.planet_inclination, motion_new.planet_inclination, inter);
3312 interpolation.planet_azimuth = interpolate_orientation(motion_old.planet_azimuth, motion_new.planet_azimuth, inter);
3314 /* interpolate position */
3315 interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
3316 interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
3317 interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
3318 /* prevent glitch when using elevators: a sudden vertical move is ignored
3319 * this is not the best solution, because fast vertical flying (from 0) will also be detected */
3320 if (old_height_offset == 0
3321 && (new_height_offset >= 150 || new_height_offset <= -150)) {
3322 interpolation.offset_east = 0.0;
3323 interpolation.offset_height = 0.0;
3324 interpolation.offset_north = 0.0;
3327 /* interpolate doors of building (if any) */
3328 interpolation.interior = interpolate_door(inter);
3330 /* interpolate objects */
3331 interpolate_objects(inter);
3333 /* interpolate planets */
3334 interpolation.planets = interpolate_planets(inter);
3337 /* return failure, if nothing can be rendered */
3338 if (!render_list_new)
3344 for (render_item = render_list_new; render_item; render_item = render_item->next) {
3345 render_one_item(render_item, vr, RENDER_BEFORE_SHADOW);
3347 if (draw_shadows && ground_index >= 0) {
3348 begin_shadow_render();
3349 for (render_item = render_list_new; render_item; render_item = render_item->next) {
3350 render_one_item(render_item, vr, RENDER_AT_SHADOW);
3352 end_shadow_render();
3354 for (render_item = render_list_new; render_item; render_item = render_item->next) {
3355 render_one_item(render_item, vr, RENDER_AFTER_SHADOW);
3361 int render_all_white(int vr)
3363 render_item_t sky_item;
3365 memset(&sky_item, 0, sizeof(sky_item));
3366 sky_item.type = RENDER_ITEM_SKY;
3369 sky_item.u.ground.red = 1.0;
3370 sky_item.u.ground.green = 1.0;
3371 sky_item.u.ground.blue = 1.0;
3373 render_one_item(&sky_item, vr, RENDER_BEFORE_SHADOW);
3378 void render_capture_reset(void)
3380 /* flush old list, if exists */
3382 /* flush new list, if exists */
3383 render_list_old = render_list_new;
3385 /* reset list pointers */
3386 render_list_old = NULL;
3387 render_list_new = NULL;
3388 render_list_end = &render_list_new;
3392 int render_capture_is_interstellar(void)
3394 if (!render_list_new)
3396 for (render_item = render_list_new; render_item; render_item = render_item->next) {
3397 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)