Add shadows and light effects
[mercenary-reloaded.git] / src / mercenary / render.c
1 /* render routines that replaces the game rendering by OpenGL rendering
2  *
3  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
4  * All Rights Reserved
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 /* How it works:
21  *
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
37  *
38  */
39
40 #include <stdio.h>
41 #include <stdint.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <math.h>
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"
51
52 #define GL3_PROTOTYPES 1
53 #include <GL/glew.h>
54
55 //#define DEBUG_COLOR
56 //#define DEBUG_VERTEX
57 //#define DEBUG_ITEMS
58 //#define DEBUG_LIGHT
59
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 */
67
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 */
81
82 enum render_shadow {
83         RENDER_BEFORE_SHADOW,
84         RENDER_AT_SHADOW,
85         RENDER_AFTER_SHADOW,
86 };
87
88 /*
89  *  render item definition and structures
90  */
91
92 /* render items */
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,
99         RENDER_ITEM_SKY,
100         RENDER_ITEM_GROUND,
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,
116         RENDER_ITEM_PLANET,
117         RENDER_ITEM_STARS,
118         RENDER_ITEM_INTERSTELLAR_STARS,
119         RENDER_ITEM_INTERSTELLAR_SUN,
120         RENDER_ITEM_ISLAND_POLYGON,
121         RENDER_ITEM_SIGHTS,
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,
127 };
128
129 struct render_item_info {
130         int moving;
131         int id;
132         int32_t east, height, north;
133 };
134
135 struct render_item_vertices {
136         double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
137 };
138
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];
142 };
143
144 struct render_item_sky {
145         double red, green, blue;
146 };
147
148 struct render_item_ground {
149         double red, green, blue;
150 };
151
152 struct render_item_polygon {
153         double red, green, blue;
154         int vertices;
155         int vertex[MAX_POLYGON];
156 };
157
158 struct render_item_interior14 {
159         double red, green, blue;
160         int level;
161         int vertex[4];
162 };
163
164 struct render_item_interior56 {
165         double red, green, blue;
166         int level12;
167         int level34;
168         int vertex14;
169         int vertex23;
170 };
171
172 struct render_item_line {
173         double red, green, blue;
174         int vertex[2];
175 };
176
177 struct render_item_point {
178         double red, green, blue;
179         int vertex;
180 };
181
182 struct render_item_planet {
183         double front_red, front_green, front_blue;
184         double back_red, back_green, back_blue;
185         int vertex;
186         double size;
187 };
188
189 struct render_item_stars {
190         int16_t v_offset;
191         int tilt;
192         int32_t tilt_value;
193         int above_zenith;
194 };
195
196 struct render_item_interstars {
197         uint8_t color[MAX_INTERSTARS];
198         int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
199         int     count;
200 };
201
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];
206         int count;
207 };
208
209 struct render_item_shadow_polygon {
210         int32_t x_pos, y_pos, z_pos;
211         int vertices;
212         int32_t x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
213 };
214
215 struct render_item_shadow_line {
216         int32_t x_pos, y_pos, z_pos;
217         int32_t x[2], y[2], z[2];
218 };
219
220 typedef struct render_item {
221         struct render_item *next;
222         enum render_item_type type;
223         union {
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;
240         } u;
241 } render_item_t;
242
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;
249         int planet_rotation;
250         double planet_inclination, planet_azimuth;
251 } motion_t;
252
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];
261         int object_count;
262         render_item_t *interior;
263         render_item_t *planets;
264 } interpolation_t;
265
266 #define GET_ORIENTATION \
267         double roll = interpolation.orientation_roll; \
268         double pitch = interpolation.orientation_pitch; \
269         double yaw = interpolation.orientation_yaw
270
271 #define GET_ORIENTATION_FIX \
272         roll = motion_new.orientation_roll; \
273         pitch = motion_new.orientation_pitch; \
274         yaw = motion_new.orientation_yaw
275
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 */
282 static double fov;
283 static double debug_opacity;
284 static double frustum_slope_64, frustum_slope_fov;
285
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;
305
306 /* states while rendering */
307 int sun_valid = 0;
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;
312
313 /*
314  * capturing
315  */
316
317 static void render_item_add(enum render_item_type type)
318 {
319         render_item = calloc(1, sizeof(render_item_t));
320         if (!render_item) {
321                 print_error("No memory, must abort!\n");
322                 abort();
323         }
324         render_item->type = type;
325         *render_list_end = render_item;
326         render_list_end = &render_item->next;
327 }
328
329 static void flush_old_items(void)
330 {
331         /* flush old render list */
332         while (render_list_old) {
333                 render_item = render_list_old;
334                 render_list_old = render_list_old->next;
335                 free(render_item);
336         }
337 }
338
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)
341 {
342 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
343         printf("start rendering a new frame...\n");
344 #endif
345
346         flush_old_items();
347         render_item = NULL;
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;
353
354         /* move new motion to old motion */
355         memcpy(&motion_old, &motion_new, sizeof(motion_old));
356
357         /* set rendering options */
358         fov = _fov;
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;
367
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);
371
372         /* init motion */
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);
379
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;
384
385         /* detect elevator movement */
386         old_height_offset = new_height_offset;
387         if (render_list_old)
388                 new_height_offset = motion_new.position_height - motion_old.position_height;
389
390         /* detect switching between space (-1) and over ground (>=0) */
391         last_ground_index = ground_index;
392
393         /* init tag type */
394         tag_is_object = 0;
395 }
396
397 void render_capture_stop(void)
398 {
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;
404         }
405
406 }
407
408 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
409 {
410         uint32_t palette;
411         uint16_t color;
412
413         /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
414         index <<= 1;
415         palette = mercenary_palette_render();
416         color = m68k_read_memory_16(palette + index);
417 #ifdef DEBUG_COLOR
418         printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
419 #endif
420         if (color >= 0x8000) {
421 #ifdef DEBUG_COLOR
422                 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
423 #endif
424         }
425         *red = (double)((color >> 8) & 0xf) / 15.0;
426         *green = (double)((color >> 4) & 0xf) / 15.0;
427         *blue = (double)(color & 0xf) / 15.0;
428 }
429
430 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
431 {
432         uint16_t index;
433         uint32_t palette;
434         int nesting = 0;
435
436 #ifdef DEBUG_COLOR
437         printf("color is given as 0x%04x\n", color);
438 #endif
439 again:
440         /* color conversion: see for example M3: 0x4f830 */
441         if (color < 0x8000) {
442                 /* use given color but shift it left by 1 */
443                 color = color << 1;
444 #ifdef DEBUG_COLOR
445                 printf("using given color, color is now 0x%04x\n", color);
446 #endif
447         } else if ((color & 0xff) < 0x80) {
448                 gamecolor2gl_index(red, green, blue, color & 0xf);
449                 return;
450         } else {
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);
455 #ifdef DEBUG_COLOR
456                 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
457 #endif
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");
461                         return;
462                 }
463                 goto again;
464         }
465         *red = (double)((color >> 8) & 0xf) / 15.0;
466         *green = (double)((color >> 4) & 0xf) / 15.0;
467         *blue = (double)(color & 0xf) / 15.0;
468 }
469
470 static int32_t wrap_int28(int32_t value)
471 {
472         value <<= 4;
473         value >>= 4;
474         return value;
475 }
476
477 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z, double scale)
478 {
479         if ((vertex & 3)) {
480                 print_info("Vertex %d is not a multiple of four!\n", vertex);
481                 return;
482         }
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;
491                 }
492         } else
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;
500                 }
501                 vertex -= 0x100;
502         } else
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;
510                 }
511                 vertex -= 0x200;
512         } else {
513                 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
514                 return;
515         }
516         vertex >>= 2;
517 #ifdef DEBUG_VERTEX
518         printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
519 #endif
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;
524 }
525
526 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix);
527
528 static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
529 {
530         if ((vertex & 3)) {
531                 print_info("Vertex %d is not a multiple of four!\n", vertex);
532                 return;
533         }
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);
537                 return;
538         }
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;
545         }
546         vertex >>= 2;
547 #ifdef DEBUG_VERTEX
548         printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
549 #endif
550         render_item->u.vertices.x[vertex] = x;
551         render_item->u.vertices.y[vertex] = y;
552         render_item->u.vertices.z[vertex] = z;
553 }
554
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)
556 {
557         if ((vertex & 3)) {
558                 print_info("Vertex is not a multiple of four!\n");
559                 return;
560         }
561         if (vertex >= MAX_INTERIOR_VERTEX) {
562                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
563                 return;
564         }
565         if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
566                 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
567         vertex >>= 2;
568 #ifdef DEBUG_VERTEX
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);
570 #endif
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;
585 }
586
587 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
588 {
589         double out_x, out_y, out_z;
590
591         /* rotate yaw (German: Gier, turn view to the right) */
592         if (yaw) {
593                 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
594                 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
595                 *z = out_z;
596                 *x = out_x;
597         }
598         /* rotate pitch (German: Nick, turn head down) */
599         if (pitch) {
600                 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
601                 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
602                 *y = out_y;
603                 *z = out_z;
604         }
605         /* rotate roll (tilt head to the right) */
606         if (roll) {
607                 out_x = (*x) * cos(roll) - (*y) * sin(roll);
608                 out_y = (*x) * sin(roll) + (*y) * cos(roll);
609                 *x = out_x;
610                 *y = out_y;
611         }
612 }
613
614 /* clear screen color (sky / universe) */
615 static void clear_screen(int index)
616 {
617 #ifdef DEBUG_VERTEX
618         printf("clear screen:\n");
619 #endif
620
621         /* allocate render item */
622         render_item_add(RENDER_ITEM_SKY);
623
624         /* set color */
625         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
626
627         /* store for later use after planets have been rendered */
628         ground_index = index;
629 }
630
631 /* ground color */
632 static void draw_ground(void)
633 {
634         /* no ground in space :) */
635         if (ground_index < 0)
636                 return;
637
638 #ifdef DEBUG_VERTEX
639         printf("add ground plane:\n");
640 #endif
641
642         /* allocate render item */
643         render_item_add(RENDER_ITEM_GROUND);
644
645         /* set color */
646         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
647 }
648
649 /* object info */
650 static void info_object(int moving)
651 {
652 #ifdef DEBUG_VERTEX
653         printf("add object's info:\n");
654 #endif
655
656         /* allocate render item */
657         render_item_add(RENDER_ITEM_OBJECT_INFO);
658
659         /* add info */
660         render_item->u.info.moving = moving;
661         if (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;
664 }
665
666 /* coordinates ready for an object */
667 static void coord_object(void)
668 {
669         int32_t x, y, z;
670
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);
678 }
679
680 /* polygon of object */
681 static void poly_object(int mercenary)
682 {
683         uint32_t vertex_address = REG_A[0], va;
684         uint32_t vertex;
685         double x, y, z;
686         int i, rc;
687
688 #ifdef DEBUG_VERTEX
689         printf("add object's polygon:\n");
690 #endif
691
692         /* allocate render item */
693         render_item_add(RENDER_ITEM_OBJECT_POLYGON);
694
695         /* set color */
696         if (mercenary == 3)
697                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
698         else {
699                 uint16_t color;
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);
703         }
704
705         /* the vertex list is zero-terminated */
706         va = vertex_address;
707         for (i = 0; i < MAX_POLYGON; i++) {
708                 vertex = m68k_read_memory_8(va++);
709                 if (vertex == 0 && i)
710                         break;
711                 render_item->u.polygon.vertex[i] = vertex;
712         }
713         render_item->u.polygon.vertices = i;
714
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;
722
723                 /* the vertex list is zero-terminated */
724                 va = vertex_address;
725                 for (i = 0; i < MAX_POLYGON; i++) {
726                         vertex = m68k_read_memory_8(va++);
727                         if (vertex == 0 && i)
728                                 break;
729                         rc = use_coord("object", vertex, &x, &y, &z, 1);
730                         if (rc < 0)
731                                 break;
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;
735                 }
736                 render_item->u.shadow_polygon.vertices = i;
737         }
738 }
739
740 /* line of object */
741 static void line_object(void)
742 {
743         uint32_t vertex_address = REG_A[0], va;
744         uint32_t vertex;
745         double x, y, z;
746         int rc;
747
748 #ifdef DEBUG_VERTEX
749         printf("add object's line:\n");
750 #endif
751
752         /* allocate render item */
753         render_item_add(RENDER_ITEM_OBJECT_LINE);
754
755         /* set color */
756         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
757
758         /* two vertices */
759         va = vertex_address;
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;
764
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;
770
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) {
773                 va = vertex_address;
774                 vertex = m68k_read_memory_8(va++);
775                 rc = use_coord("object", vertex, &x, &y, &z, 1);
776                 if (rc < 0)
777                         x=y=z=0;
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);
783                 if (rc < 0)
784                         x=y=z=0;
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;
788         }
789 }
790
791 /* coordinates ready for a beacon */
792 static void coord_beacon(void)
793 {
794         int32_t x, y, z;
795
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);
801 }
802
803 /* point of beacon */
804 static void point_beacon(void)
805 {
806 #ifdef DEBUG_VERTEX
807         printf("add beacon's point:\n");
808 #endif
809
810         /* allocate render item */
811         render_item_add(RENDER_ITEM_BEACON_POINT);
812
813         /* set color */
814         gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
815
816         /* one vertex */
817         render_item->u.point.vertex = 0;
818 }
819
820 /* coordinates ready for a building (exterior) */
821 static void coord_building_exterior(void)
822 {
823         int32_t x, y, z;
824
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);
829 }
830
831 /* polygon of building (exterior) */
832 static void poly_building_exterior(void)
833 {
834         uint16_t color;
835         uint32_t vertex_address = REG_A[0];
836         uint32_t vertex;
837         int i;
838
839 #ifdef DEBUG_VERTEX
840         printf("add building's polygon:\n");
841 #endif
842
843         /* allocate render item */
844         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
845
846         /* set color */
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);
850
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)
855                         break;
856                 render_item->u.polygon.vertex[i] = vertex | 0x100;
857         }
858         render_item->u.polygon.vertices = i;
859 }
860
861 /* line of building (exterior) */
862 static void line_building_exterior(void)
863 {
864         uint32_t vertex_address = REG_A[0];
865         uint32_t vertex;
866
867 #ifdef DEBUG_VERTEX
868         printf("add building's line:\n");
869 #endif
870
871         /* allocate render item */
872         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
873
874         /* set color */
875         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
876
877         /* two vertices */
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;
882 }
883
884 /* coordinates ready for a building (interior) */
885 static void coord_building_interior(void)
886 {
887         int16_t east, north;
888         int32_t height1, height2, height3, height4;
889
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);
892 }
893
894 /* polygon of building (interior) */
895 static void poly_building_interior1to4(int level)
896 {
897         uint16_t color;
898         uint32_t vertex;
899         int i;
900
901 #ifdef DEBUG_VERTEX
902         printf("add roof/floor's polygon at level %d:\n", level);
903 #endif
904
905         /* allocate render item */
906         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
907
908         /* set color */
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);
912
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;
917         }
918         render_item->u.interior14.level = level;
919 }
920
921 /* polygon of building (interior) */
922 static void poly_building_interior5to6(int level12, int level34)
923 {
924         uint16_t color;
925
926 #ifdef DEBUG_VERTEX
927         printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
928 #endif
929
930         /* allocate render item */
931         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
932
933         /* set color */
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);
937
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;
943 }
944
945 /* wall part of a building */
946 static void wall_building(void)
947 {
948 #ifdef DEBUG_VERTEX
949         printf("add wall:\n");
950 #endif
951
952         /* allocate render item */
953         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
954
955         /* set color */
956         gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
957
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;
964 }
965
966 /* coordinates ready for comet tail */
967 static void coord_comet(void)
968 {
969         int32_t x, y, z;
970
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);
975 }
976
977 /* polygon of comet tail */
978 static void poly_comet(void)
979 {
980         uint16_t color;
981         uint32_t vertex_address = REG_A[0];
982         uint32_t vertex;
983         int i;
984
985 #ifdef DEBUG_VERTEX
986         printf("add comet's polygon:\n");
987 #endif
988
989         /* allocate render item */
990         render_item_add(RENDER_ITEM_COMET_POLYGON);
991
992         /* set color */
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);
996
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)
1001                         break;
1002                 render_item->u.polygon.vertex[i] = vertex;
1003         }
1004         render_item->u.polygon.vertices = i;
1005 }
1006
1007 /* coordinates ready for lines of a road / ground surface */
1008 static void coord_line_road(void)
1009 {
1010         int32_t x, y, z;
1011
1012         x = REG_D[3];
1013         y = -motion_new.position_height;
1014         z = REG_D[5];
1015         store_coord("road", REG_A[0], x, y, z, 1.0);
1016 }
1017
1018 /* line of road */
1019 static void line_road(void)
1020 {
1021         uint32_t vertex;
1022
1023 #ifdef DEBUG_VERTEX
1024         printf("add road's line:\n");
1025 #endif
1026
1027         /* allocate render item */
1028         render_item_add(RENDER_ITEM_ROAD_LINE);
1029
1030         /* set color */
1031         gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
1032
1033         /* two vertices */
1034         vertex = REG_A[1];
1035         render_item->u.line.vertex[0] = vertex;
1036         vertex = REG_A[2];
1037         render_item->u.line.vertex[1] = vertex;
1038 }
1039
1040 /* coordinates ready for polygons of a road / ground surface */
1041 static void coord_poly_road(void)
1042 {
1043         int32_t x, y, z;
1044
1045         x = m68k_read_memory_32(320 + REG_A[0]);
1046         x -= REG_A[1];
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]);
1050         z -= REG_A[3];
1051         store_coord("road/place", REG_A[0], x, y, z, 1.0);
1052 }
1053
1054 /* polygon of road */
1055 static void poly_road()
1056 {
1057         uint16_t color;
1058         uint32_t vertex_address = REG_A[0];
1059         uint32_t vertex;
1060         int i;
1061
1062 #ifdef DEBUG_VERTEX
1063         printf("add road/place's polygon:\n");
1064 #endif
1065
1066         /* allocate render item */
1067         render_item_add(RENDER_ITEM_ROAD_POLYGON);
1068
1069         /* set color */
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);
1073
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)
1078                         break;
1079                 render_item->u.polygon.vertex[i] = vertex;
1080         }
1081         render_item->u.polygon.vertices = i;
1082 }
1083
1084 /* coordinates ready for tags */
1085 static void coord_tags(void)
1086 {
1087         int32_t x, y, z;
1088
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);
1096 }
1097
1098 /* coordinates ready for large tags */
1099 static void coord_tags2(void)
1100 {
1101         int32_t x, y, z;
1102
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.
1111          */
1112         store_coord("large tags", REG_A[0], x, y, z, 0.5);
1113 }
1114
1115 /* line of tag */
1116 static void line_tags(int last_color)
1117 {
1118         uint32_t vertex_address = REG_A[0];
1119         uint32_t vertex;
1120
1121 #ifdef DEBUG_VERTEX
1122         printf("add tag's line:\n");
1123 #endif
1124
1125         /* allocate render item */
1126         render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
1127
1128         /* set color */
1129         if (!last_color)
1130                 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
1131         else
1132                 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
1133
1134         /* two vertices */
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;
1139 }
1140
1141 /* polygon of tags */
1142 static void poly_tags(int last_color)
1143 {
1144         uint32_t vertex_address = REG_A[0];
1145         uint32_t vertex;
1146         int i;
1147
1148 #ifdef DEBUG_VERTEX
1149         printf("add tag's polygon:\n");
1150 #endif
1151
1152         /* allocate render item */
1153         render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1154
1155         /* set color */
1156         if (!last_color)
1157                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1158         else
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)
1164                         break;
1165                 render_item->u.polygon.vertex[i] = vertex | 0x200;
1166         }
1167         render_item->u.polygon.vertices = i;
1168 }
1169
1170 /* coordinates ready for planet */
1171 static void coord_planet(void)
1172 {
1173         int32_t x, y, z;
1174
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);
1179 }
1180
1181 /* planet */
1182 static void draw_planet(int comet)
1183 {
1184         uint32_t vertex;
1185         uint32_t scale_index;
1186         double scale1, scale2;
1187
1188         vertex = REG_A[0];
1189
1190         /* fixing (not noticable) bug in game: don't render comet twice */
1191         if (!comet && vertex == 116)
1192                 return;
1193
1194 #ifdef DEBUG_VERTEX
1195         printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1196 #endif
1197
1198         /* allocate render item */
1199         render_item_add(RENDER_ITEM_PLANET);
1200
1201         /* set color */
1202         if (comet) {
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);
1206
1207         } else {
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);
1211         }
1212
1213         /* set vertex */
1214         render_item->u.planet.vertex = vertex;
1215
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.
1220          */
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;
1225 }
1226
1227 /* stars */
1228 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1229 {
1230 #ifdef DEBUG_VERTEX
1231         printf("add stars\n");
1232 #endif
1233
1234         /* allocate render item */
1235         render_item_add(RENDER_ITEM_STARS);
1236
1237         /* vertical offset */
1238         render_item->u.stars.v_offset = v_offset;
1239
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;
1242         if (tilt)
1243                 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1244
1245         /* stars above zenith */
1246         render_item->u.stars.above_zenith = above_zenith;
1247 }
1248
1249 /* stars of interstellar flight */
1250 static void draw_stars_interstellar(void)
1251 {
1252         int i, count;
1253         uint32_t table;
1254
1255 #ifdef DEBUG_VERTEX
1256         printf("add interstellar stars\n");
1257 #endif
1258
1259         /* allocate render item */
1260         render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1261
1262         table = REG_A[0];
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);
1266                 return;
1267         }
1268         for (i = 0; i < count; i++) {
1269                 table += 12;
1270                 /* get color */
1271                 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1272                 table += 2;
1273                 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1274                 table += 2;
1275                 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1276                 table += 2;
1277         }
1278         render_item->u.interstars.count = count;
1279 }
1280
1281 /* sun of interstellar flight (center dot) */
1282 static void draw_sun_interstellar(void)
1283 {
1284 #ifdef DEBUG_VERTEX
1285         printf("add interstellar sun\n");
1286 #endif
1287
1288         /* allocate render item */
1289         render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1290 }
1291
1292 /* coordinates ready for polygons of islands */
1293 static void coord_islands(void)
1294 {
1295         int32_t x, y, z;
1296
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);
1304 }
1305
1306 /* polygon of island */
1307 static void poly_island()
1308 {
1309         uint16_t color;
1310         uint32_t vertex_address = REG_A[0];
1311         uint32_t vertex;
1312         int i;
1313
1314 #ifdef DEBUG_VERTEX
1315         printf("add island:\n");
1316 #endif
1317
1318         /* allocate render item */
1319         render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1320
1321         /* set color */
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);
1325
1326         /* the vertex list is zero-terminated */
1327         i = 0;
1328         while (i < MAX_POLYGON) {
1329                 vertex = m68k_read_memory_8(vertex_address++);
1330                 if (vertex == 0 && i)
1331                         break;
1332                 /* skip mysterious points when rendering island */
1333                 if (vertex >= 0xf0)
1334                         continue;
1335                 render_item->u.polygon.vertex[i] = vertex;
1336                 i++;
1337         }
1338         render_item->u.polygon.vertices = i;
1339 }
1340
1341 /* sights */
1342 static void draw_sights(void)
1343 {
1344 #ifdef DEBUG_VERTEX
1345         printf("add sights:\n");
1346 #endif
1347
1348         /* allocate render item */
1349         render_item_add(RENDER_ITEM_SIGHTS);
1350 }
1351
1352 static int32_t coord_explosion_x, coord_explosion_y, coord_explosion_z;
1353
1354 static void coord_explosion(void)
1355 {
1356         coord_explosion_x = REG_D[3];
1357         coord_explosion_y = REG_D[4];
1358         coord_explosion_z = REG_D[5];
1359 }
1360
1361 static void draw_explosion(void)
1362 {
1363         uint16_t color;
1364         double scale1, scale2;
1365
1366 #ifdef DEBUG_VERTEX
1367         printf("add explosion:\n");
1368 #endif
1369
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;
1377         }
1378         if (render_item->u.explosion.count == MAX_EXPLOSION)
1379                 return;
1380
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.
1384          */
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;
1388         } else
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));
1392         } else {
1393                 scale1 = 1.0;
1394                 scale2 = 1 << 10;
1395         }
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++;
1401 }
1402
1403 /* get building data out of game data, so we use it to render shadow */
1404 static void draw_shadow_building(void)
1405 {
1406         int32_t scale_x, scale_y, scale_z;
1407         int32_t x, y, z;
1408         uint16_t anim_flag, anim_x, anim_y, anim_z, anim_phase;
1409         uint32_t a0, a0s, a5, a6, a4;
1410         uint16_t s;
1411         int16_t d3, d4, d5;
1412         int32_t d3x, d4x, d5x;
1413         int d1index;
1414         int line_from, line_to, point;
1415         int i;
1416         struct render_item_vertices vertex;
1417
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;
1422
1423         /* list of all vetices */
1424         for (i = 1; i < 64; i++) {
1425                 d3 = m68k_read_memory_16(a4);
1426                 a4 += 2;
1427                 if (d3 <= (int16_t)0x8001)
1428                         break;
1429                 d4 = m68k_read_memory_16(a4);
1430                 a4 += 2;
1431                 d5 = m68k_read_memory_16(a4);
1432                 a4 += 2;
1433                 if (d4 < 0) {
1434                         d4 = ~d4;
1435                         /* scale */
1436                         d3x = d3 * scale_x;
1437                         d4x = d4 * scale_y;
1438                         d5x = d5 * scale_z;
1439                         /* angle */
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;
1446                                 if (angle) {
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);
1451                                         d3 = cosd3 - sind4;
1452                                         d4 = cosd4 + sind3;
1453                                 }
1454                                 d3x = d3 + anim_x;
1455                                 d4x = d4 + anim_y;
1456                         }
1457                         if ((int16_t)anim_flag == 0) {
1458                                 /* rotate around y */
1459                                 d3 = (d3x & 0xffff) - anim_x;
1460                                 d5 = (d5x & 0xffff) - anim_z;
1461                                 if (angle) {
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);
1466                                         d3 = cosd3 + sind5;
1467                                         d5 = cosd5 - sind3;
1468                                 }
1469                                 d3x = d3 + anim_x;
1470                                 d5x = d5 + anim_z;
1471                         }
1472                         if ((int16_t)anim_flag < 0) {
1473                                 /* rotate around x */
1474                                 d4 = (d4x & 0xffff) - anim_y;
1475                                 d5 = (d5x & 0xffff) - anim_z;
1476                                 if (angle) {
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);
1481                                         d4 = cosd4 + sind5;
1482                                         d5 = cosd5 - sind4;
1483                                 }
1484                                 d4x = d4 + anim_y;
1485                                 d5x = d5 + anim_z;
1486                         }
1487                 } else {
1488                         /* scale */
1489                         d3x = d3 * scale_x;
1490                         d4x = d4 * scale_y;
1491                         d5x = d5 * scale_z;
1492                 }
1493                 vertex.x[i] = d3x;
1494                 vertex.y[i] = d4x;
1495                 vertex.z[i] = d5x;
1496         }
1497
1498         /* get all data sets */
1499         do {
1500                 s = m68k_read_memory_16(a0);
1501                 a0 += 2;
1502                 if (s) {
1503                         /* skip over distance cube */
1504                         a0 += 4 * 6;
1505                 }
1506                 /* get address pointer to data set */
1507                 a0s = m68k_read_memory_32(a0);
1508                 a0 += 4;
1509
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) {
1515                                 /* polygon */
1516                                 a6 += 2;
1517 #ifdef DEBUG_VERTEX
1518                                 printf("add object's shadow polygon:\n");
1519 #endif
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;
1525                                 i = 0;
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];
1530                                         i++;
1531                                 }
1532                                 render_item->u.shadow_polygon.vertices = i;
1533                         } else if ((m68k_read_memory_16(a6) & 0x2000) == 0) {
1534                                 /* line */
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];
1548                         }
1549                 }
1550         } while (s);
1551 }
1552
1553 /* stop event from CPU received */
1554 void render_capture_event(int event)
1555 {
1556         switch (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;
1561                 break;
1562         case STOP_AT_CLEAR_SCREEN2:
1563                 clear_screen(15);
1564                 break;
1565         case STOP_AT_CLEAR_SCREEN3:
1566                 clear_screen(-1); /* no ground (in universe) */
1567                 break;
1568         case STOP_AT_DRAW_GROUND:
1569                 draw_ground();
1570                 break;
1571         case STOP_AT_INFO_OBJECT_MOVING:
1572                 info_object(1);
1573                 break;
1574         case STOP_AT_INFO_OBJECT_FIX:
1575                 info_object(0);
1576                 break;
1577         case STOP_AT_TAG_IS_OBJECT_1:
1578                 tag_is_object = 1;
1579                 break;
1580         case STOP_AT_TAG_IS_OBJECT_0:
1581                 tag_is_object = 0;
1582                 break;
1583         case STOP_AT_COORD_OBJECT:
1584                 coord_object();
1585                 break;
1586         case STOP_AT_POLY_OBJECT_M3:
1587                 poly_object(3);
1588                 break;
1589         case STOP_AT_POLY_OBJECT_M2:
1590                 poly_object(2);
1591                 break;
1592         case STOP_AT_LINE_OBJECT:
1593                 line_object();
1594                 break;
1595         case STOP_AT_COORD_BEACON:
1596                 coord_beacon();
1597                 break;
1598         case STOP_AT_POINT_BEACON:
1599                 point_beacon();
1600                 /* note: we may not call the point-renderer, because projected coordinates are invalid */
1601                 mercenary_patch_render(draw_shadows);
1602                 break;
1603         case STOP_AT_COORD_BUILDING_EXTERIOR:
1604                 coord_building_exterior();
1605                 break;
1606         case STOP_AT_POLY_BUILDING_EXTERIOR:
1607                 poly_building_exterior();
1608                 break;
1609         case STOP_AT_LINE_BUILDING_EXTERIOR:
1610                 line_building_exterior();
1611                 break;
1612         case STOP_AT_COORD_BUILDING_INTERIOR:
1613                 coord_building_interior();
1614                 break;
1615         case STOP_AT_POLY_BUILDING_INTERIOR1:
1616                 /* floor */
1617                 interior_level12 = 1;
1618                 interior_level34 = 1;
1619                 break;
1620         case STOP_AT_POLY_BUILDING_INTERIOR2:
1621                 /* ceiling */
1622                 interior_level12 = 2;
1623                 interior_level34 = 2;
1624                 break;
1625         case STOP_AT_POLY_BUILDING_INTERIOR3:
1626                 /* door/window top */
1627                 interior_level12 = 3;
1628                 interior_level34 = 3;
1629                 break;
1630         case STOP_AT_POLY_BUILDING_INTERIOR4:
1631                 /* window bottom */
1632                 interior_level12 = 4;
1633                 interior_level34 = 4;
1634                 break;
1635         case STOP_AT_POLY_BUILDING_INTERIOR5:
1636                 /* door/window top */
1637                 interior_level12 = 2;
1638                 interior_level34 = 3;
1639                 break;
1640         case STOP_AT_POLY_BUILDING_INTERIOR6:
1641                 /* window bottom */
1642                 interior_level12 = 1;
1643                 interior_level34 = 4;
1644                 break;
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");
1649                         break;
1650                 }
1651                 poly_building_interior1to4(interior_level12);
1652                 interior_level12 = 0;
1653                 break;
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");
1658                         break;
1659                 }
1660                 poly_building_interior5to6(interior_level12, interior_level34);
1661                 interior_level12 = 0;
1662                 break;
1663         case STOP_AT_WALL_BUILDING:
1664                 wall_building();
1665                 break;
1666         case STOP_AT_COORD_COMET:
1667                 coord_comet();
1668                 break;
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;
1676                 else
1677                         motion_new.planet_rotation = 0;
1678                 break;
1679         case STOP_AT_POLY_COMET:
1680                 poly_comet();
1681                 break;
1682         case STOP_AT_COORD_LINE_ROADS:
1683                 coord_line_road();
1684                 break;
1685         case STOP_AT_LINE_ROADS:
1686                 line_road();
1687                 break;
1688         case STOP_AT_COORD_POLY_ROADS:
1689                 coord_poly_road();
1690                 break;
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.
1694                  */
1695                 break;
1696         case STOP_AT_POLY_ROADS:
1697                 poly_road();
1698                 break;
1699         case STOP_AT_COORD_TAGS:
1700                 coord_tags();
1701                 break;
1702         case STOP_AT_COORD_TAGS2:
1703                 coord_tags2();
1704                 break;
1705         case STOP_AT_LINE_TAGS1:
1706                 line_tags(0);
1707                 break;
1708         case STOP_AT_LINE_TAGS2:
1709                 line_tags(1);
1710                 break;
1711         case STOP_AT_POLY_TAGS1:
1712                 poly_tags(0);
1713                 break;
1714         case STOP_AT_POLY_TAGS2:
1715                 poly_tags(1);
1716                 break;
1717         case STOP_AT_COORD_PLANET:
1718                 coord_planet();
1719                 break;
1720         case STOP_AT_DRAW_PLANET:
1721                 draw_planet(0);
1722                 break;
1723         case STOP_AT_DRAW_COMET:
1724                 draw_planet(1);
1725                 break;
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);
1729                 break;
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! */
1733                 break;
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! */
1737                 break;
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! */
1741                 break;
1742         case STOP_AT_DRAW_STARS_INTERSTELLAR:
1743                 draw_stars_interstellar();
1744                 break;
1745         case STOP_AT_DRAW_SUN_INTERSTELLAR:
1746                 draw_sun_interstellar();
1747                 break;
1748         case STOP_AT_COORD_ISLANDS:
1749                 coord_islands();
1750                 break;
1751         case STOP_AT_POLY_ISLANDS:
1752                 poly_island();
1753                 break;
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
1758                 break;
1759         case STOP_AT_DRAW_SIGHTS:
1760                 draw_sights();
1761                 break;
1762         case STOP_AT_POLY_UKN2:
1763                 puts("poly ukn2");
1764                 break;
1765         case STOP_AT_COORD_EXPLOSION:
1766                 coord_explosion();
1767                 break;
1768         case STOP_AT_DRAW_EXPLOSION:
1769                 draw_explosion();
1770                 break;
1771         case STOP_AT_PATCH_RENDER:
1772                 mercenary_patch_render(draw_shadows);
1773                 break;
1774         case STOP_AT_SHADOW_BUILDING:
1775                 draw_shadow_building();
1776                 break;
1777         }
1778 }
1779
1780 /*
1781  * rendering
1782  */
1783
1784 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int no_inter)
1785 {
1786         render_item_t *ri = NULL;
1787
1788         if ((vertex & 3)) {
1789                 print_info("Vertex %d is not a multiple of four!\n", vertex);
1790                 return -1;
1791         }
1792         if (vertex < 0x100) {
1793                 if (!render_item_vertices_0) {
1794                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1795                         return -1;
1796                 }
1797                 ri = render_item_vertices_0;
1798         } else
1799         if (vertex < 0x200) {
1800                 if (!render_item_vertices_1) {
1801                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1802                         return -1;
1803                 }
1804                 ri = render_item_vertices_1;
1805                 vertex -= 0x100;
1806         } else
1807         if (vertex < 0x300) {
1808                 if (!render_item_vertices_2) {
1809                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1810                         return -1;
1811                 }
1812                 ri = render_item_vertices_2;
1813                 vertex -= 0x200;
1814         } else {
1815                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1816                 return -1;
1817         }
1818         vertex >>= 2;
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;
1823         if (!no_inter) {
1824                 /* translate to floating (interpolated) position offset */
1825                 *x -= interpolation.offset_east;
1826                 *y -= interpolation.offset_height;
1827                 *z -= interpolation.offset_north;
1828         }
1829 #ifdef DEBUG_VERTEX
1830         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1831 #endif
1832
1833         return 0;
1834 }
1835
1836 static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1837 {
1838         render_item_t *ri = NULL;
1839
1840         if ((vertex & 3)) {
1841                 print_info("Vertex %d is not a multiple of four!\n", vertex);
1842                 return -1;
1843         }
1844         if (vertex >= MAX_VERTEX) {
1845                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1846                 return -1;
1847         }
1848         if (interpolation.planets)
1849                 ri = interpolation.planets;
1850         else
1851                 ri = render_item_vertices_0;
1852         if (!ri) {
1853                 print_info("Vertices item for planets verticies not yet set!\n");
1854                 return -1;
1855         }
1856         vertex >>= 2;
1857         *x = ri->u.vertices.x[vertex];
1858         *y = ri->u.vertices.y[vertex];
1859         *z = ri->u.vertices.z[vertex];
1860 #ifdef DEBUG_VERTEX
1861         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1862 #endif
1863
1864         return 0;
1865 }
1866
1867 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1868 {
1869         if ((vertex & 3)) {
1870                 print_info("Vertex is not a multiple of four!\n");
1871                 return -1;
1872         }
1873         if (vertex >= MAX_INTERIOR_VERTEX) {
1874                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1875                 return -1;
1876         }
1877         if (level < 1 || level > 4) {
1878                 print_info("Level %d is out of range (1..4)!\n", level);
1879                 return -1;
1880         }
1881         if (!render_item_vertices_interior) {
1882                 print_info("Vertices item for interior verticies not yet set!\n");
1883                 return -1;
1884         }
1885         vertex >>= 2;
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;
1897
1898 #ifdef DEBUG_VERTEX
1899         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1900 #endif
1901
1902         return 0;
1903 }
1904
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)
1907 {
1908         double elevation;
1909
1910 //      azimuth = atan2(sun_z, sun_x);
1911
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);
1914 #ifdef DEBUG_LIGHT
1915         printf("Elevation of SUN: %.3f\n", elevation);
1916 #endif
1917
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);
1920         if (*day < 0.0)
1921                 *day = 0.0;
1922         if (*day > 1.0)
1923                 *day = 1.0;
1924 #ifdef DEBUG_LIGHT
1925         printf("How much day: %.3f\n", *day);
1926 #endif
1927
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);
1930         if (*stars < 0.0)
1931                 *stars = 0.0;
1932         if (*stars > 1.0)
1933                 *stars = 1.0;
1934 #ifdef DEBUG_LIGHT
1935         printf("How much stars: %.3f\n", *stars);
1936 #endif
1937
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);
1940         if (*shadow < 0.0)
1941                 *shadow = 0.0;
1942         if (*shadow > 1.0)
1943                 *shadow = 1.0;
1944         *shadow *= SHADOW_LEVEL;
1945 #ifdef DEBUG_LIGHT
1946         printf("How much shadow: %.3f\n", *shadow);
1947 #endif
1948
1949 }
1950
1951 /* renders one item from render list */
1952 void render_one_item(render_item_t *render_item, int vr, enum render_shadow shadow)
1953 {
1954         switch (render_item->type) {
1955         case RENDER_ITEM_OBJECT_INFO:
1956         {
1957 #ifdef DEBUG_ITEMS
1958                 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1959 #endif
1960                 render_item_object_info = render_item;
1961                 break;
1962         }
1963         case RENDER_ITEM_VERTICES_0:
1964         {
1965 #ifdef DEBUG_ITEMS
1966                 printf("RENDER_ITEM_VERTICES_0\n");
1967 #endif
1968                 render_item_vertices_0 = render_item;
1969                 break;
1970         }
1971         case RENDER_ITEM_VERTICES_1:
1972         {
1973 #ifdef DEBUG_ITEMS
1974                 printf("RENDER_ITEM_VERTICES_1\n");
1975 #endif
1976                 render_item_vertices_1 = render_item;
1977                 break;
1978         }
1979         case RENDER_ITEM_VERTICES_2:
1980         {
1981 #ifdef DEBUG_ITEMS
1982                 printf("RENDER_ITEM_VERTICES_2\n");
1983 #endif
1984                 render_item_vertices_2 = render_item;
1985                 break;
1986         }
1987         case RENDER_ITEM_VERTICES_INTERIOR:
1988         {
1989 #ifdef DEBUG_ITEMS
1990                 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1991 #endif
1992                 if (interpolation.interior)
1993                         render_item_vertices_interior = interpolation.interior;
1994                 else
1995                         render_item_vertices_interior = render_item;
1996                 break;
1997         }
1998         case RENDER_ITEM_SKY:
1999         {
2000                 double x[4], y[4], z[4];
2001
2002                 if (shadow != RENDER_BEFORE_SHADOW)
2003                         break;
2004
2005 #ifdef DEBUG_ITEMS
2006                 printf("RENDER_ITEM_SKY\n");
2007 #endif
2008                 /* get color */
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;
2013                         double day_factor;
2014
2015                         calculate_lighting(sun_pos_x, sun_pos_y, sun_pos_z, &day_factor, &stars_bright, &shadow_level);
2016
2017                         /* sky color */
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);
2026
2027                 } else
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);
2048                 break;
2049         }
2050         case RENDER_ITEM_GROUND:
2051         {
2052                 GET_ORIENTATION;
2053                 double x[4], y[4], z[4];
2054                 int i;
2055
2056                 if (shadow != RENDER_BEFORE_SHADOW)
2057                         break;
2058
2059 #ifdef DEBUG_ITEMS
2060                 printf("RENDER_ITEM_GROUND\n");
2061 #endif
2062                 /* get color */
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;
2069                 /* rotate vertex */
2070                 for (i = 0; i < 4; i++)
2071                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2072                 /* render */
2073                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
2074                 break;
2075         }
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:
2080         {
2081                 GET_ORIENTATION;
2082                 int fix = 0;
2083                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2084                 int i, o;
2085                 int rc;
2086
2087                 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON) {
2088                         if (shadow != RENDER_BEFORE_SHADOW)
2089                                 break;
2090                 } else {
2091                         if (shadow != RENDER_AFTER_SHADOW)
2092                                 break;
2093                 }
2094
2095 #ifdef DEBUG_ITEMS
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");
2104 #endif
2105
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;
2109                         fix = 1;
2110                 }
2111
2112                 /* get color */
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++) {
2116                         /* get vertex */
2117                         rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
2118                         if (rc < 0)
2119                                 break;
2120                         /* fixed objects are pre-scaled by 16, so we correct this */
2121                         if (fix) {
2122                                 x[i] /= FIX_OBJECT_SCALE;
2123                                 y[i] /= FIX_OBJECT_SCALE;
2124                                 z[i] /= FIX_OBJECT_SCALE;
2125                         }
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)
2130                                                 break;
2131                                 }
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];
2136                                 }
2137                         }
2138                         /* rotate vertex */
2139                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2140                 }
2141                 /* render */
2142                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
2143                 break;
2144         }
2145         case RENDER_ITEM_OBJECT_LINE:
2146         case RENDER_ITEM_TAG_LINE_OBJECT:
2147         case RENDER_ITEM_TAG_LINE_OTHER:
2148         {
2149                 GET_ORIENTATION;
2150                 int fix = 0;
2151                 double x[2], y[2], z[2];
2152                 int i, o;
2153                 int rc;
2154
2155                 if (shadow != RENDER_AFTER_SHADOW)
2156                         break;
2157
2158 #ifdef DEBUG_ITEMS
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");
2165 #endif
2166
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;
2170                         fix = 1;
2171                 }
2172
2173                 /* get color */
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++) {
2177                         /* get vertex */
2178                         rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
2179                         if (rc < 0)
2180                                 break;
2181                         /* fixed objects are pre-scaled by 16, so we correct this */
2182                         if (fix) {
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;
2187                                 } else {
2188                                         x[i] /= FIX_OBJECT_SCALE;
2189                                         y[i] /= FIX_OBJECT_SCALE;
2190                                         z[i] /= FIX_OBJECT_SCALE;
2191                                 }
2192                         }
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)
2197                                                 break;
2198                                 }
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];
2203                                 }
2204                         }
2205                         /* rotate vertex */
2206                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2207                 }
2208                 /* render */
2209                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2210                 break;
2211         }
2212         case RENDER_ITEM_BEACON_POINT:
2213         {
2214                 GET_ORIENTATION;
2215                 double x, y, z;
2216                 int rc;
2217
2218                 if (shadow != RENDER_AFTER_SHADOW)
2219                         break;
2220
2221 #ifdef DEBUG_ITEMS
2222                 printf("RENDER_ITEM_BEACON_POINT\n");
2223 #endif
2224                 /* get color */
2225                 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
2226                 /* get vertex */
2227                 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
2228                 if (rc < 0)
2229                         break;
2230                 /* rotate vertex */
2231                 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
2232                 /* render */
2233                 opengl_render_point(x, y, z, 0.0);
2234                 break;
2235         }
2236         case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
2237         {
2238                 GET_ORIENTATION;
2239                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2240                 int i;
2241                 int rc;
2242
2243 #ifdef DEBUG_ITEMS
2244                 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
2245 #endif
2246                 /* get color */
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++) {
2250                         /* get vertex */
2251                         rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
2252                         if (rc < 0)
2253                                 break;
2254                         /* rotate vertex */
2255                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2256                 }
2257                 /* render */
2258                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
2259                 break;
2260         }
2261         case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
2262         {
2263                 GET_ORIENTATION;
2264                 double x[2], y[2], z[2];
2265                 int i;
2266                 int rc;
2267
2268                 if (shadow != RENDER_AFTER_SHADOW)
2269                         break;
2270
2271 #ifdef DEBUG_ITEMS
2272                 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
2273 #endif
2274                 /* get color */
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++) {
2278                         /* get vertex */
2279                         rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2280                         if (rc < 0)
2281                                 break;
2282                         /* rotate vertex */
2283                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2284                 }
2285                 /* render */
2286                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2287                 break;
2288         }
2289         case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
2290         {
2291                 GET_ORIENTATION;
2292                 double x[4], y[4], z[4];
2293                 int i;
2294                 int rc;
2295
2296                 if (shadow != RENDER_AFTER_SHADOW)
2297                         break;
2298
2299 #ifdef DEBUG_ITEMS
2300                 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
2301 #endif
2302                 /* get color */
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++) {
2306                         /* get vertex */
2307                         rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
2308                         if (rc < 0)
2309                                 break;
2310                         /* rotate vertex */
2311                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2312                 }
2313                 /* render */
2314                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
2315                 break;
2316         }
2317         case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
2318         {
2319                 GET_ORIENTATION;
2320                 double x[4], y[4], z[4];
2321                 int i;
2322                 int vertex, level;
2323                 int rc;
2324
2325                 if (shadow != RENDER_AFTER_SHADOW)
2326                         break;
2327
2328 #ifdef DEBUG_ITEMS
2329                 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
2330 #endif
2331                 /* get color */
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++) {
2335                         /* get vertex */
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]);
2339                         if (rc < 0)
2340                                 break;
2341                         /* rotate vertex */
2342                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2343                 }
2344                 /* render */
2345                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
2346                 break;
2347         }
2348         case RENDER_ITEM_BUILDING_INTERIOR_WALL:
2349         {
2350                 GET_ORIENTATION;
2351                 double x[4], y[4], z[4];
2352                 int i;
2353                 int vertex, level;
2354                 int rc;
2355
2356                 if (shadow != RENDER_AFTER_SHADOW)
2357                         break;
2358
2359 #ifdef DEBUG_ITEMS
2360                 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
2361 #endif
2362                 /* get color */
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++) {
2368                                 /* get vertex */
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]);
2372                                 if (rc < 0)
2373                                         break;
2374                                 /* rotate vertex */
2375                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2376                         }
2377                         /* render */
2378                         opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
2379                 } else {
2380                         /* get and rotate vertex */
2381                         for (i = 0; i < 2; i++) {
2382                                 /* get vertex */
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]);
2386                                 if (rc < 0)
2387                                         break;
2388                                 /* rotate vertex */
2389                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2390                         }
2391                         /* render */
2392                         opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2393                 }
2394                 break;
2395         }
2396         case RENDER_ITEM_COMET_POLYGON:
2397         {
2398                 GET_ORIENTATION;
2399                 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2400                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2401                 int i;
2402                 int rc;
2403                 double rotate_sky = 0.0;
2404
2405                 if (shadow != RENDER_BEFORE_SHADOW)
2406                         break;
2407
2408 #ifdef DEBUG_ITEMS
2409                 printf("RENDER_ITEM_COMET_POLYGON\n");
2410 #endif
2411                 /* get color */
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++) {
2415                         /* get vertex */
2416                         rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
2417                         if (rc < 0)
2418                                 break;
2419                         /* rotate vertex */
2420                         if (motion_new.planet_rotation) {
2421                                 if (fix_sky_rotation)
2422                                         rotate_sky = M_PI;
2423                                 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
2424                         }
2425                         rotate_coordinate(roll, pitch, yaw + rotate_sky, &x[i], &y[i], &z[i]);
2426                 }
2427                 /* render */
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! */
2429                 break;
2430         }
2431         case RENDER_ITEM_ROAD_LINE:
2432         {
2433                 GET_ORIENTATION;
2434                 double x[2], y[2], z[2];
2435                 int i;
2436                 int rc;
2437
2438                 if (shadow != RENDER_BEFORE_SHADOW)
2439                         break;
2440
2441 #ifdef DEBUG_ITEMS
2442                 printf("RENDER_ITEM_ROAD_LINE\n");
2443 #endif
2444                 /* get color */
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++) {
2448                         /* get vertex */
2449                         rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2450                         if (rc < 0)
2451                                 break;
2452                         /* rotate vertex */
2453                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2454                 }
2455                 /* render */
2456                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2457                 break;
2458         }
2459         case RENDER_ITEM_ROAD_POLYGON:
2460         {
2461                 GET_ORIENTATION;
2462                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2463                 int i, v;
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;
2468                 int vertices_num;
2469                 int rc;
2470
2471                 if (shadow != RENDER_BEFORE_SHADOW)
2472                         break;
2473
2474 #ifdef DEBUG_ITEMS
2475                 printf("RENDER_ITEM_ROAD_POLYGON\n");
2476 #endif
2477                 /* get color */
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 */
2480                 i = 0;
2481                 vertices_num = render_item->u.polygon.vertices;
2482                 for (v = 0; v < vertices_num; v++) {
2483                         /* get vertex */
2484                         vertex = render_item->u.polygon.vertex[v];
2485                         rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
2486                         if (rc < 0)
2487                                 break;
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);
2493                                 if (rc < 0)
2494                                         break;
2495                                 /* next vertex */
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);
2498                                 if (rc < 0)
2499                                         break;
2500                                 /* extend vertices to end point position
2501                                  * change x or z coordinate, whatever is greater
2502                                 */
2503                                 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
2504                                         x_prev = x_next = x_current;
2505                                 else
2506                                         z_prev = z_next = z_current;
2507                                 /* store vertices */
2508                                 x[i] = x_prev;
2509                                 y[i] = y_prev;
2510                                 z[i] = z_prev;
2511                                 /* rotate vertex */
2512                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2513                                 if (i++ == MAX_POLYGON)
2514                                         break;
2515                                 x[i] = x_next;
2516                                 y[i] = y_next;
2517                                 z[i] = z_next;
2518                                 /* rotate vertex */
2519                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2520                                 if (i++ == MAX_POLYGON)
2521                                         break;
2522                                 continue;
2523                         } else {
2524                                 /* no extension, just keep the current point as is */
2525                                 x[i] = x_current;
2526                                 y[i] = y_current;
2527                                 z[i] = z_current;
2528                                 /* rotate vertex */
2529                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2530                                 if (i++ == MAX_POLYGON)
2531                                         break;
2532                         }
2533                 }
2534                 /* render */
2535                 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2536                 break;
2537         }
2538         case RENDER_ITEM_PLANET:
2539         {
2540                 GET_ORIENTATION;
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;
2549                 double _sin, _cos;
2550                 int i;
2551                 int rc;
2552                 double rotate_sky = 0.0;
2553
2554                 if (shadow != RENDER_BEFORE_SHADOW)
2555                         break;
2556
2557 #ifdef DEBUG_ITEMS
2558                 printf("RENDER_ITEM_PLANET\n");
2559 #endif
2560
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);
2576                 }
2577
2578                 /* get location */
2579                 rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
2580                 if (rc < 0)
2581                         break;
2582                 rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
2583                 if (rc < 0)
2584                         break;
2585                 /* get size */
2586                 size = render_item->u.planet.size;
2587                 /* rotate vertex */
2588                 if (motion_new.planet_rotation) {
2589                         if (fix_sky_rotation)
2590                                 rotate_sky = M_PI;
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);
2593                 }
2594                 /* store sun location */
2595                 sun_valid = 1;
2596                 sun_pos_x = sun_x;
2597                 sun_pos_y = sun_y;
2598                 sun_pos_z = sun_z;
2599                 /* rotate sun */
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);
2602
2603                 /* distance to planet */
2604                 dist = sqrt(loc_x * loc_x + loc_y * loc_y + loc_z * loc_z);
2605
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;
2612                 if (angle > M_PI)
2613                         angle -= 2.0 * M_PI;
2614                 if (angle < -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;
2620
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);
2625                 } else {
2626                         /* get back side color */
2627                         opengl_render_color(back_red, back_green, back_blue, debug_opacity);
2628                 }
2629
2630                 /* create and render cicle */
2631                 crescent = sin((1.0 - fabs_angle / (M_PI / 2)) * (M_PI / 2.0));
2632                 if (vr) {
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;
2637                                 circle_y[i] = _cos;
2638                                 circle_z[i] = 0.0;
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]);
2647                         }
2648                 } else {
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;
2653                                 circle_y[i] = _cos;
2654                                 circle_z[i] = 0.0;
2655                                 crescent_x[i] = circle_x[i] * crescent;
2656                                 crescent_y[i] = circle_y[i];
2657                                 crescent_z[i] = circle_z[i];
2658                         }
2659                 }
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;
2664                 }
2665                 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2666
2667                 if (render_item->u.planet.vertex == 0) {
2668                         /* sun has no crescent */
2669                         break;
2670                 }
2671
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);
2676                 } else {
2677                         /* get front side color */
2678                         opengl_render_color(front_red, front_green, front_blue, debug_opacity);
2679                 }
2680
2681                 /* create and render crescent */
2682                 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2683                         /* to the right */
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;
2688                         }
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;
2694                         }
2695                 } else {
2696                         /* to the left */
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;
2701                         }
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;
2706                         }
2707                 }
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  */
2710                 break;
2711         }
2712         case RENDER_ITEM_STARS:
2713         {
2714                 double tilt_offset = 0;
2715                 double x_offset = 0;
2716                 uint16_t color[16];
2717                 double view_width, yaw = interpolation.orientation_raw_yaw;
2718                 double pitch = interpolation.orientation_raw_pitch;
2719                 uint32_t table, table_start;
2720                 double x, y, z;
2721                 int i;
2722                 double red, green, blue;
2723                 double rotate_sky = 0.0;
2724
2725                 if (shadow != RENDER_BEFORE_SHADOW)
2726                         break;
2727
2728 #ifdef DEBUG_ITEMS
2729                 printf("RENDER_ITEM_STARS\n");
2730 #endif
2731
2732                 /* no stars at day */
2733                 if (stars_bright == 0.0)
2734                         break;
2735
2736                 /* use default fov of 64 to calculate z distance */
2737                 z = 160.0 / frustum_slope_64;
2738
2739                 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2740
2741                 /* get palette */
2742                 for (i = 0; i < 16; i++)
2743                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2744
2745                 if (!vr && !improve_stars) {
2746                         /* render legacy stars (as with the original game) */
2747
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
2751                          */
2752
2753                         if (render_item->u.stars.above_zenith)
2754                                 yaw = 0x200 + yaw;
2755                         yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2756                         yaw *= 2.0;
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;
2761
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;
2766                         pitch *= 4;
2767                         pitch = pitch * (double)0x6ccc / 65536.0;
2768
2769                         while (1) {
2770                                 x = m68k_read_memory_16(table);
2771                                 if (x >= 1800.0) {
2772                                         x_offset += 1800.0;
2773                                         table = table_start;
2774                                 }
2775                                 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2776                                 table += 2;
2777                                 if (x < 0.0)
2778                                         break;
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
2783                                          */
2784                                         tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2785                                 }
2786                                 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2787                                 table += 2;
2788                                 if (render_item->u.stars.above_zenith) {
2789                                         x = (double)(view_width - 1) - x;
2790                                         y = -1 - y + 136;
2791                                 }
2792                                 /* get color */
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);
2795                                 /* render point */
2796                                 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2797                         }
2798                 } else {
2799                         /* render ovr stars, render star table as a sphere */
2800
2801                         double h, v1, v2;
2802                         GET_ORIENTATION;
2803                         double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2804
2805                         if (render_item->u.stars.above_zenith)
2806                                 break;
2807
2808                         table = mercenary_star_table();
2809                         table += m68k_read_memory_16(table);
2810
2811                         while (1) {
2812                                 x = m68k_read_memory_16(table);
2813                                 if (x >= 1800.0)
2814                                         break;
2815                                 table += 2;
2816                                 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - 108.796875;
2817                                 table += 2;
2818                                 /* get color */
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);
2821                                 /* render point */
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) */
2825                                 if (v1 <= 0.0)
2826                                         v2 = v1 + (86.2 / 180.0 * M_PI);
2827                                 else
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);
2833                                         y = sin(v1);
2834                                         z = cos(h) * cos(v1);
2835                                         if (motion_new.planet_rotation) {
2836                                                 if (fix_sky_rotation)
2837                                                         rotate_sky = M_PI;
2838                                                 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2839                                         }
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);
2842                                 }
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);
2847                                         y = sin(v2);
2848                                         z = cos(h) * cos(v2);
2849                                         if (motion_new.planet_rotation) {
2850                                                 if (fix_sky_rotation)
2851                                                         rotate_sky = M_PI;
2852                                                 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2853                                         }
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);
2856                                 }
2857                         }
2858                 }
2859                 break;
2860         }
2861         case RENDER_ITEM_INTERSTELLAR_STARS:
2862         {
2863                 uint16_t color[16];
2864                 double z;
2865                 int i;
2866                 double red, green, blue;
2867
2868                 if (shadow != RENDER_BEFORE_SHADOW)
2869                         break;
2870
2871 #ifdef DEBUG_ITEMS
2872                 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2873 #endif
2874                 /* use default fov of 64 to calculate z distance */
2875                 z = 160.0 / frustum_slope_64;
2876
2877                 /* get palette */
2878                 for (i = 0; i < 16; i++)
2879                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2880
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);
2884                         /* render point */
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);
2886                 }
2887                 break;
2888         }
2889         case RENDER_ITEM_INTERSTELLAR_SUN:
2890         {
2891                 double red, green, blue;
2892
2893                 if (shadow != RENDER_BEFORE_SHADOW)
2894                         break;
2895
2896 #ifdef DEBUG_ITEMS
2897                 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2898 #endif
2899                 /* white */
2900                 gamecolor2gl(&red, &green, &blue, 0x777);
2901                 opengl_render_color(red, green, blue, debug_opacity);
2902                 /* render point */
2903                 opengl_render_point(0.0, 0.0, 1000000.0, 0.0);
2904                 break;
2905         }
2906         case RENDER_ITEM_SIGHTS:
2907         {
2908                 double x[4], y[4], z[4];
2909                 double red, green, blue;
2910
2911                 if (shadow != RENDER_AFTER_SHADOW)
2912                         break;
2913
2914 #ifdef DEBUG_ITEMS
2915                 printf("RENDER_ITEM_SIGHTS\n");
2916 #endif
2917                 /* use default fov of 64 to calculate z distance */
2918                 z[0] = z[1] = z[2] = z[3] = SIGHT_DIST;
2919
2920                 /* white */
2921                 gamecolor2gl(&red, &green, &blue, 0x777);
2922                 opengl_render_color(red, green, blue, debug_opacity);
2923
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! */
2932                 break;
2933         }
2934         case RENDER_ITEM_EXPLOSION:
2935         {
2936                 GET_ORIENTATION;
2937                 double loc_x, loc_y, loc_z, size;
2938                 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2939                 int i, e;
2940
2941                 if (shadow != RENDER_AFTER_SHADOW)
2942                         break;
2943
2944 #ifdef DEBUG_ITEMS
2945                 printf("RENDER_ITEM_EXPLOSION\n");
2946 #endif
2947                 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2948
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];
2953                         /* rotate vertex */
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);
2961                                 z[i] = loc_z;
2962                         }
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  */
2965                 }
2966                 break;
2967         }
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:
2972         {
2973                 GET_ORIENTATION;
2974                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2975                 double shadow_x, shadow_z;
2976                 int o;
2977                 int i;
2978
2979                 if (shadow != RENDER_AT_SHADOW)
2980                         break;
2981
2982 #ifdef DEBUG_ITEMS
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");
2987 #endif
2988
2989                 if (!sun_valid || sun_pos_y < 1.0)
2990                         return;
2991
2992                 if (shadow_level == 0.0)
2993                         return;
2994
2995                 /* calculate shadow */
2996                 shadow_x = -sun_pos_x / sun_pos_y;
2997                 shadow_z = -sun_pos_z / sun_pos_y;
2998
2999                 opengl_render_color_alpha(0, 0, 0, shadow_level);
3000
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)
3012                                                         break;
3013                                         }
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];
3018                                         }
3019                                 }
3020                                 /* flatten polygon into shadow */
3021                                 x[i] += y[i] * shadow_x;
3022                                 z[i] += y[i] * shadow_z;
3023                                 y[i] = 0.0;
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;
3032                                 /* rotate vertex */
3033                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
3034                         }
3035                         /* render */
3036                         opengl_render_polygon(x, y, z, render_item->u.shadow_polygon.vertices, 0); /* no back face culling */
3037                 }
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)
3049                                                         break;
3050                                         }
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];
3055                                         }
3056                                 }
3057                                 /* flatten polygon into shadow */
3058                                 x[i] += y[i] * shadow_x;
3059                                 z[i] += y[i] * shadow_z;
3060                                 y[i] = 0.0;
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;
3069                                 /* rotate vertex */
3070                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
3071                         }
3072                         /* render */
3073                         opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
3074                 }
3075                 break;
3076         }
3077         default:
3078                 print_info("Unknown render item type, please fix!\n");
3079         }
3080 }
3081
3082 /*
3083  * interpolation
3084  */
3085
3086 static double interpolate_orientation(double old, double new, double inter)
3087 {
3088         double turn = new - old;
3089
3090         if (turn > M_PI)
3091                 turn -= 2.0 * M_PI;
3092         if (turn < -M_PI)
3093                 turn += 2.0 * M_PI;
3094
3095         /* don't interpolate, if our rotation was too fast.
3096          * e.g: taxi drive around corder, load/quit game, ...
3097          */ 
3098         if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
3099                 return new;
3100         
3101         new = old + turn * inter;
3102         
3103         if (new > M_PI)
3104                 new -= 2.0 * M_PI;
3105         if (new < -M_PI)
3106                 new += 2.0 * M_PI;
3107
3108         return new;
3109 }
3110
3111 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
3112 {
3113         int16_t turn = (new - old) & 0x3ff;
3114
3115         if (turn > 0x200)
3116                 turn -= 0x400;
3117
3118         /* don't interpolate, if our rotation was too fast.
3119          * e.g: taxi drive around corder, load/quit game, ...
3120          */ 
3121         if (turn > 0x200 / 8 || turn < -0x200 / 8)
3122                 return new;
3123
3124         /* don't do modulo 0x400, since the user of this data does it */        
3125         return (double)old + (double)turn * inter;
3126 }
3127
3128 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
3129 {
3130         double offset;
3131
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);
3135         else
3136                 offset = (int32_t)(old - new);
3137
3138         if (limit > 0 && (offset > limit || offset < -limit))
3139                 return new;
3140
3141         return offset * (1.0 - inter);
3142 }
3143
3144 static render_item_t *interpolate_door(double inter)
3145 {
3146         static render_item_t interpolated;
3147         render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
3148         int i, ii;
3149
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;
3155
3156         /* building does not exist in old or new render */
3157         if (!old_vertices || !new_vertices)
3158                 return NULL;
3159
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])
3165                         continue;
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)
3168                         return NULL;
3169                 if (fabs(old_vertices->u.vertices_interior.z[i] - new_vertices->u.vertices_interior.z[i]) > 100.0)
3170                         return NULL;
3171                 /* interpolate */
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;
3178         }
3179         for (i = 0; i < 4; i++) {
3180                 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
3181                         return NULL;
3182         }
3183
3184         return &interpolated;
3185 }
3186
3187 /* make a list of objects that moved and store their displacement */
3188 static void interpolate_objects(double inter)
3189 {
3190         render_item_t *old_info, *new_info;
3191         int count;
3192
3193         /* hunt for objects that exist in both (old and new) lists and moved */
3194         count = 0;
3195         for (new_info = render_list_new; new_info; new_info = new_info -> next) {
3196                 /* not an object */
3197                 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
3198                         continue;
3199                 /* not moving */
3200                 if (!new_info->u.info.moving)
3201                         continue;
3202                 /* interiors don't move */
3203                 if (new_info->u.info.id < 0)
3204                         continue;
3205                 /* check matching object with same ID */
3206                 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
3207                         /* not an object */
3208                         if (old_info->type != RENDER_ITEM_OBJECT_INFO)
3209                                 continue;
3210                         /* not moving */
3211                         if (!old_info->u.info.moving)
3212                                 continue;
3213                         /* same id */
3214                         if (old_info->u.info.id == new_info->u.info.id)
3215                                 break;
3216                 }
3217                 /* no matching object found */
3218                 if (!old_info)
3219                         continue;
3220                 /* not moving */
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)
3224                         continue;
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)
3231                         break;
3232         }
3233         interpolation.object_count = count;
3234 }
3235
3236 /* make a vertex list of interpolated planets */
3237 static render_item_t *interpolate_planets(double inter)
3238 {
3239         static render_item_t interpolated;
3240         render_item_t *old_info, *new_info;
3241         render_item_t *old_vertices = NULL, *new_vertices = NULL;
3242         int i;
3243
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)
3250                         break;
3251         }
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)
3257                         break;
3258         }
3259
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)
3262                 return NULL;
3263
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;
3269         }
3270
3271         return &interpolated;
3272 }
3273
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
3278  */
3279 int render_all_items(double inter, int vr)
3280 {
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;
3285
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)) {
3289                 inter = 1.0;
3290         }
3291
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);
3302
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);
3313
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;
3325                 }
3326
3327                 /* interpolate doors of building (if any) */
3328                 interpolation.interior = interpolate_door(inter);
3329
3330                 /* interpolate objects */
3331                 interpolate_objects(inter);
3332
3333                 /* interpolate planets */
3334                 interpolation.planets = interpolate_planets(inter);
3335         }
3336
3337         /* return failure, if nothing can be rendered */
3338         if (!render_list_new)
3339                 return -1;
3340
3341         sun_valid = 0;
3342         stars_bright = 1.0;
3343
3344         for (render_item = render_list_new; render_item; render_item = render_item->next) {
3345                 render_one_item(render_item, vr, RENDER_BEFORE_SHADOW);
3346         }
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);
3351                 }
3352                 end_shadow_render();
3353         }
3354         for (render_item = render_list_new; render_item; render_item = render_item->next) {
3355                 render_one_item(render_item, vr, RENDER_AFTER_SHADOW);
3356         }
3357
3358         return 0;
3359 }
3360
3361 int render_all_white(int vr)
3362 {
3363         render_item_t sky_item;
3364
3365         memset(&sky_item, 0, sizeof(sky_item));
3366         sky_item.type = RENDER_ITEM_SKY;
3367
3368         /* set color */
3369         sky_item.u.ground.red = 1.0;
3370         sky_item.u.ground.green = 1.0;
3371         sky_item.u.ground.blue = 1.0;
3372
3373         render_one_item(&sky_item, vr, RENDER_BEFORE_SHADOW);
3374
3375         return 0;
3376 }
3377
3378 void render_capture_reset(void)
3379 {
3380         /* flush old list, if exists */
3381         flush_old_items();
3382         /* flush new list, if exists */
3383         render_list_old = render_list_new;
3384         flush_old_items();
3385         /* reset list pointers */
3386         render_list_old = NULL;
3387         render_list_new = NULL;
3388         render_list_end = &render_list_new;
3389         render_item = NULL;
3390 }
3391
3392 int render_capture_is_interstellar(void)
3393 {
3394         if (!render_list_new)
3395                 return 0;
3396         for (render_item = render_list_new; render_item; render_item = render_item->next) {
3397                 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)
3398                         return 1;
3399         }
3400
3401         return 0;
3402 }
3403