26977ba25bb57c0fb9dae544a0e8a7c01272f9ee
[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  *    - The recent capture (NEW) is rendered
33  *    - Interpolation result is taken into account
34  */
35
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <stdlib.h>
39 #include <string.h>
40 #include <math.h>
41 #include "../libsdl/print.h"
42 #include "../libcpu/m68k.h"
43 #include "../libcpu/m68kcpu.h"
44 #include "../libcpu/execute.h"
45 #include "../libopengl/opengl.h"
46 #include "mercenary.h"
47
48 #define GL3_PROTOTYPES 1
49 #include <GL/glew.h>
50
51 //#define DEBUG_COLOR
52 //#define DEBUG_VERTEX
53 //#define DEBUG_ITEMS
54
55 #define MAX_POLYGON             16      /* number of polygon complexity (vertices) */
56 #define MAX_VERTEX              0x100   /* this is the value range, these are 64 vertices */
57 #define MAX_INTERIOR_VERTEX     0x400   /* do we need that much? */
58 #define MAX_INTERSTARS          80      /* always 80 stars */
59 #define MAX_MOVING_OBJECTS      16      /* maximum number of moving objects (used for interpolation) */
60 #define MAX_EXPLOSION           256     /* how many explosion particles can be stored in one object */
61 #define PLANET_VERTICES         128
62 #define PLANET_STRETCH          1.19    /* stretch horizontally (this compensates NTSC/PAL line ratio of 625/525)*/
63 #define EXPLOSION_VERTICES      16
64 #define EXPLOSION_STRETCH       1.19    /* as above */
65 #define SIGHT_DIST              78.74   /* distanc of sights in inch */
66 #define FIX_OBJECT_SCALE        16      /* intercity... */
67 #define FIX_OBJECT_SCALE_TAG    2       /* line in faces of persons */
68
69 /*
70  *  render item definition and structures
71  */
72
73 /* render items */
74 enum render_item_type {
75         RENDER_ITEM_OBJECT_INFO,
76         RENDER_ITEM_VERTICES_0,
77         RENDER_ITEM_VERTICES_1,
78         RENDER_ITEM_VERTICES_2,
79         RENDER_ITEM_VERTICES_INTERIOR,
80         RENDER_ITEM_SKY,
81         RENDER_ITEM_GROUND,
82         RENDER_ITEM_OBJECT_POLYGON,
83         RENDER_ITEM_OBJECT_LINE,
84         RENDER_ITEM_BEACON_POINT,
85         RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
86         RENDER_ITEM_BUILDING_EXTERIOR_LINE,
87         RENDER_ITEM_BUILDING_INTERIOR_1TO4,
88         RENDER_ITEM_BUILDING_INTERIOR_5TO6,
89         RENDER_ITEM_BUILDING_INTERIOR_WALL,
90         RENDER_ITEM_COMET_POLYGON,
91         RENDER_ITEM_ROAD_LINE,
92         RENDER_ITEM_ROAD_POLYGON,
93         RENDER_ITEM_TAG_LINE_OBJECT,
94         RENDER_ITEM_TAG_LINE_OTHER,
95         RENDER_ITEM_TAG_POLYGON_OBJECT,
96         RENDER_ITEM_TAG_POLYGON_OTHER,
97         RENDER_ITEM_PLANET,
98         RENDER_ITEM_STARS,
99         RENDER_ITEM_INTERSTELLAR_STARS,
100         RENDER_ITEM_INTERSTELLAR_SUN,
101         RENDER_ITEM_ISLAND_POLYGON,
102         RENDER_ITEM_SIGHTS,
103         RENDER_ITEM_EXPLOSION,
104 };
105
106 struct render_item_info {
107         int moving;
108         int id;
109         int32_t east, height, north;
110 };
111
112 struct render_item_vertices {
113         double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
114 };
115
116 struct render_item_vertices_interior {
117         uint8_t set[MAX_INTERIOR_VERTEX >> 2];
118         double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
119 };
120
121 struct render_item_sky {
122         double red, green, blue;
123 };
124
125 struct render_item_ground {
126         double red, green, blue;
127 };
128
129 struct render_item_polygon {
130         double red, green, blue;
131         int vertices;
132         int vertex[MAX_POLYGON];
133 };
134
135 struct render_item_interior14 {
136         double red, green, blue;
137         int level;
138         int vertex[4];
139 };
140
141 struct render_item_interior56 {
142         double red, green, blue;
143         int level12;
144         int level34;
145         int vertex14;
146         int vertex23;
147 };
148
149 struct render_item_line {
150         double red, green, blue;
151         int vertex[2];
152 };
153
154 struct render_item_point {
155         double red, green, blue;
156         int vertex;
157 };
158
159 struct render_item_planet {
160         double front_red, front_green, front_blue;
161         double back_red, back_green, back_blue;
162         int vertex;
163         double size;
164 };
165
166 struct render_item_stars {
167         int16_t v_offset;
168         int tilt;
169         int32_t tilt_value;
170         int above_zenith;
171 };
172
173 struct render_item_interstars {
174         uint8_t color[MAX_INTERSTARS];
175         int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
176         int     count;
177 };
178
179 struct render_item_explosion {
180         double red, green, blue;
181         int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
182         double size[MAX_EXPLOSION];
183         int count;
184 };
185
186 typedef struct render_item {
187         struct render_item *next;
188         enum render_item_type type;
189         union {
190                 struct render_item_info                 info;
191                 struct render_item_vertices             vertices;
192                 struct render_item_vertices_interior    vertices_interior;
193                 struct render_item_sky                  sky;
194                 struct render_item_ground               ground;
195                 struct render_item_polygon              polygon;
196                 struct render_item_line                 line;
197                 struct render_item_point                point;
198                 struct render_item_interior14           interior14;
199                 struct render_item_interior56           interior56;
200                 struct render_item_planet               planet;
201                 struct render_item_stars                stars;
202                 struct render_item_interstars           interstars;
203                 struct render_item_explosion            explosion;
204         } u;
205 } render_item_t;
206
207 /* information about motion in each game rendering */
208 typedef struct motion {
209         int32_t position_east, position_height, position_north;
210         double orientation_roll, orientation_pitch, orientation_yaw;
211         uint16_t orientation_raw_yaw;
212         int16_t orientation_raw_pitch;
213         int planet_rotation;
214         double planet_inclination, planet_azimuth;
215 } motion_t;
216
217 /* information about interpolation between two game renedrings */
218 typedef struct interpolation {
219         double offset_east, offset_height, offset_north;
220         double orientation_roll, orientation_pitch, orientation_yaw;
221         double orientation_raw_yaw, orientation_raw_pitch;
222         double planet_inclination, planet_azimuth;
223         int object_id[MAX_MOVING_OBJECTS];
224         double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
225         int object_count;
226         render_item_t *interior;
227         render_item_t *planets;
228 } interpolation_t;
229
230 #define GET_ORIENTATION \
231         double roll = interpolation.orientation_roll; \
232         double pitch = interpolation.orientation_pitch; \
233         double yaw = interpolation.orientation_yaw
234
235 #define GET_ORIENTATION_FIX \
236         roll = motion_new.orientation_roll; \
237         pitch = motion_new.orientation_pitch; \
238         yaw = motion_new.orientation_yaw
239
240 /* rendering options */
241 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
242 static int improve_stars; /* stars are rendered spherical */
243 static int fix_sky_rotation; /* sky will rotate correctly by rotating planets/comet by 180 degrees */
244 static double planet_aspect, explosion_aspect; /* aspect ratio */
245 static double fov;
246 static double debug_opacity;
247 static double frustum_slope_64, frustum_slope_fov;
248
249 /* states while collecting render items */
250 static motion_t motion_old, motion_new;
251 static int32_t old_height_offset = 0, new_height_offset = 0;
252 static interpolation_t interpolation;
253 static int ground_index, last_ground_index = -1;
254 static int interior_level12 = 0;
255 static int interior_level34 = 0;
256 static int tag_is_object;
257 /* current render item list */
258 static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
259 /* previous render item list */
260 static render_item_t *render_list_old = NULL;
261 /* current item to be processed */
262 static render_item_t *render_item;
263 /* current object info */
264 static render_item_t *render_item_object_info;
265 /* current vertices */
266 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
267 static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
268
269 /*
270  * capturing
271  */
272
273 static void render_item_add(enum render_item_type type)
274 {
275         render_item = calloc(1, sizeof(render_item_t));
276         if (!render_item) {
277                 print_error("No memory, must abort!\n");
278                 abort();
279         }
280         render_item->type = type;
281         *render_list_end = render_item;
282         render_list_end = &render_item->next;
283 }
284
285 static void flush_old_items(void)
286 {
287         /* flush old render list */
288         while (render_list_old) {
289                 render_item = render_list_old;
290                 render_list_old = render_list_old->next;
291                 free(render_item);
292         }
293 }
294
295 /* rendering starts, initialize variables */
296 void render_capture_start(double _fov, int _extend_roads, int _smooth_planets, int _improve_stars, int _fix_sky_rotation, int _round_planets, int debug)
297 {
298 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
299         printf("start rendering a new frame...\n");
300 #endif
301
302         flush_old_items();
303         render_item = NULL;
304         /* move new render list to old render list */
305         render_list_old = render_list_new;
306         /* setup new render list */
307         render_list_new = NULL;
308         render_list_end = &render_list_new;
309
310         /* move new motion to old motion */
311         memcpy(&motion_old, &motion_new, sizeof(motion_old));
312
313         /* set rendering options */
314         fov = _fov;
315         extend_roads = _extend_roads;
316         fix_sky_rotation = _fix_sky_rotation;
317         improve_stars = _improve_stars;
318         planet_aspect = (_round_planets) ? 1.0 : PLANET_STRETCH;
319         explosion_aspect = (_round_planets) ? 1.0 : EXPLOSION_STRETCH;
320         /* set some transpareny, if debugging is enabled */
321         debug_opacity = (debug) ? 0.5 : 1.0;
322
323         /* calculate slope of 64 degree frustum and current FOV's frustum */    
324         frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
325         frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
326
327         /* init motion */
328         mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
329         /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
330         mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
331         mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
332         motion_new.planet_rotation = motion_old.planet_rotation;
333         mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth, _smooth_planets);
334
335         render_item_object_info = NULL;
336         render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
337         render_item_vertices_planets = NULL;
338         render_item_vertices_interior = NULL;
339
340         /* detect elevator movement */
341         old_height_offset = new_height_offset;
342         if (render_list_old)
343                 new_height_offset = motion_new.position_height - motion_old.position_height;
344
345         /* detect switching between space (-1) and over ground (>=0) */
346         last_ground_index = ground_index;
347
348         /* init tag type */
349         tag_is_object = 0;
350 }
351
352 void render_capture_stop(void)
353 {
354         /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
355         if (!render_list_new) {
356                 render_list_new = render_list_old;
357                 render_list_end = &render_list_new;
358                 render_list_old = NULL;
359         }
360
361 }
362
363 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
364 {
365         uint32_t palette;
366         uint16_t color;
367
368         /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
369         index <<= 1;
370         palette = mercenary_palette_render();
371         color = m68k_read_memory_16(palette + index);
372 #ifdef DEBUG_COLOR
373         printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
374 #endif
375         if (color >= 0x8000) {
376 #ifdef DEBUG_COLOR
377                 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
378 #endif
379         }
380         *red = (double)((color >> 8) & 0xf) / 15.0;
381         *green = (double)((color >> 4) & 0xf) / 15.0;
382         *blue = (double)(color & 0xf) / 15.0;
383 }
384
385 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
386 {
387         uint16_t index;
388         uint32_t palette;
389         int nesting = 0;
390
391 #ifdef DEBUG_COLOR
392         printf("color is given as 0x%04x\n", color);
393 #endif
394 again:
395         /* color conversion: see for example M3: 0x4f830 */
396         if (color < 0x8000) {
397                 /* use given color but shift it left by 1 */
398                 color = color << 1;
399 #ifdef DEBUG_COLOR
400                 printf("using given color, color is now 0x%04x\n", color);
401 #endif
402         } else if ((color & 0xff) < 0x80) {
403                 gamecolor2gl_index(red, green, blue, color & 0xf);
404                 return;
405         } else {
406                 /* use given index from pre-defined palette */
407                 index = color & 0x7e;
408                 palette = mercenary_palette_predefined();
409                 color = m68k_read_memory_16(palette + index);
410 #ifdef DEBUG_COLOR
411                 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
412 #endif
413                 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
414                 if (nesting++ == 8) {
415                         print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
416                         return;
417                 }
418                 goto again;
419         }
420         *red = (double)((color >> 8) & 0xf) / 15.0;
421         *green = (double)((color >> 4) & 0xf) / 15.0;
422         *blue = (double)(color & 0xf) / 15.0;
423 }
424
425 static int32_t wrap_int28(int32_t value)
426 {
427         value <<= 4;
428         value >>= 4;
429         return value;
430 }
431
432 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z, double scale)
433 {
434         if ((vertex & 3)) {
435                 print_info("Vertex %d is not a multiple of four!\n", vertex);
436                 return;
437         }
438         /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
439         if (vertex < 0x100) {
440                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
441                         render_item_add(RENDER_ITEM_VERTICES_0);
442                         /* copy vertices that have been captured already */
443                         if (render_item_vertices_0)
444                                 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
445                         render_item_vertices_0 = render_item;
446                 }
447         } else
448         if (vertex < 0x200) {
449                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
450                         render_item_add(RENDER_ITEM_VERTICES_1);
451                         /* copy vertices that have been captured already */
452                         if (render_item_vertices_1)
453                                 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
454                         render_item_vertices_1 = render_item;
455                 }
456                 vertex -= 0x100;
457         } else
458         if (vertex < 0x300) {
459                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
460                         render_item_add(RENDER_ITEM_VERTICES_2);
461                         /* copy vertices that have been captured already */
462                         if (render_item_vertices_2)
463                                 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
464                         render_item_vertices_2 = render_item;
465                 }
466                 vertex -= 0x200;
467         } else {
468                 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
469                 return;
470         }
471         vertex >>= 2;
472 #ifdef DEBUG_VERTEX
473         printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
474 #endif
475         /* use absolute position */
476         render_item->u.vertices.x[vertex] = (double)x * scale + motion_new.position_east;
477         render_item->u.vertices.y[vertex] = (double)y * scale + motion_new.position_height;
478         render_item->u.vertices.z[vertex] = (double)z * scale + motion_new.position_north;
479 }
480
481 static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
482 {
483         if ((vertex & 3)) {
484                 print_info("Vertex %d is not a multiple of four!\n", vertex);
485                 return;
486         }
487         /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
488         if (vertex >= MAX_VERTEX) {
489                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
490                 return;
491         }
492         if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
493                 render_item_add(RENDER_ITEM_VERTICES_0);
494                 /* copy vertices that have been captured already */
495                 if (render_item_vertices_0)
496                         memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
497                 render_item_vertices_0 = render_item;
498         }
499         vertex >>= 2;
500 #ifdef DEBUG_VERTEX
501         printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
502 #endif
503         render_item->u.vertices.x[vertex] = x;
504         render_item->u.vertices.y[vertex] = y;
505         render_item->u.vertices.z[vertex] = z;
506 }
507
508 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)
509 {
510         if ((vertex & 3)) {
511                 print_info("Vertex is not a multiple of four!\n");
512                 return;
513         }
514         if (vertex >= MAX_INTERIOR_VERTEX) {
515                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
516                 return;
517         }
518         if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
519                 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
520         vertex >>= 2;
521 #ifdef DEBUG_VERTEX
522         printf("storing %s coordinates: vertex=%d, x=%d, y=%d;%d;%d;%d, z=%d\n", what, vertex, x, y1, y2, y3, y4, z);
523 #endif
524         /* use absolute position */
525         x += motion_new.position_east;
526         y1 += motion_new.position_height;
527         y2 += motion_new.position_height;
528         y3 += motion_new.position_height;
529         y4 += motion_new.position_height;
530         z += motion_new.position_north;
531         render_item->u.vertices_interior.x[vertex] = (double)x;
532         render_item->u.vertices_interior.y[0] = (double)y1;
533         render_item->u.vertices_interior.y[1] = (double)y2;
534         render_item->u.vertices_interior.y[2] = (double)y3;
535         render_item->u.vertices_interior.y[3] = (double)y4;
536         render_item->u.vertices_interior.z[vertex] = (double)z;
537         render_item->u.vertices_interior.set[vertex] = 1;
538 }
539
540 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
541 {
542         double out_x, out_y, out_z;
543
544         /* rotate yaw (German: Gier, turn view to the right) */
545         if (yaw) {
546                 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
547                 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
548                 *z = out_z;
549                 *x = out_x;
550         }
551         /* rotate pitch (German: Nick, turn head down) */
552         if (pitch) {
553                 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
554                 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
555                 *y = out_y;
556                 *z = out_z;
557         }
558         /* rotate roll (tilt head to the right) */
559         if (roll) {
560                 out_x = (*x) * cos(roll) - (*y) * sin(roll);
561                 out_y = (*x) * sin(roll) + (*y) * cos(roll);
562                 *x = out_x;
563                 *y = out_y;
564         }
565 }
566
567 /* clear screen color (sky / universe) */
568 static void clear_screen(int index)
569 {
570 #ifdef DEBUG_VERTEX
571         printf("clear screen:\n");
572 #endif
573
574         /* allocate render item */
575         render_item_add(RENDER_ITEM_SKY);
576
577         /* set color */
578         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
579
580         /* store for later use after planets have been rendered */
581         ground_index = index;
582 }
583
584 /* ground color */
585 static void draw_ground(void)
586 {
587         /* no ground in space :) */
588         if (ground_index < 0)
589                 return;
590
591 #ifdef DEBUG_VERTEX
592         printf("add ground plane:\n");
593 #endif
594
595         /* allocate render item */
596         render_item_add(RENDER_ITEM_GROUND);
597
598         /* set color */
599         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
600 }
601
602 /* object info */
603 static void info_object(int moving)
604 {
605 #ifdef DEBUG_VERTEX
606         printf("add object's info:\n");
607 #endif
608
609         /* allocate render item */
610         render_item_add(RENDER_ITEM_OBJECT_INFO);
611
612         /* add info */
613         render_item->u.info.moving = moving;
614         if (moving)
615                 mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
616 }
617
618 /* coordinates ready for an object */
619 static void coord_object(void)
620 {
621         int32_t x, y, z;
622
623         x = (int16_t)REG_D[3];
624         x += (int32_t)REG_A[1];
625         y = (int16_t)REG_D[4];
626         y += (int32_t)REG_A[2];
627         z = (int16_t)REG_D[5];
628         z += (int32_t)REG_A[3];
629         store_coord("object", REG_A[0], x, y, z, 1.0);
630 }
631
632 /* polygon of object */
633 static void poly_object(int mercenary)
634 {
635         uint32_t vertex_address = REG_A[0];
636         uint32_t vertex;
637         int i;
638
639 #ifdef DEBUG_VERTEX
640         printf("add object's polygon:\n");
641 #endif
642
643         /* allocate render item */
644         render_item_add(RENDER_ITEM_OBJECT_POLYGON);
645
646         /* set color */
647         if (mercenary == 3)
648                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
649         else {
650                 uint16_t color;
651                 color = m68k_read_memory_8(vertex_address++) << 8;
652                 color |= m68k_read_memory_8(vertex_address++);
653                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
654         }
655
656         /* the vertex list is zero-terminated */
657         for (i = 0; i < MAX_POLYGON; i++) {
658                 vertex = m68k_read_memory_8(vertex_address++);
659                 if (vertex == 0 && i)
660                         break;
661                 render_item->u.polygon.vertex[i] = vertex;
662         }
663         render_item->u.polygon.vertices = i;
664 }
665
666 /* line of object */
667 static void line_object(void)
668 {
669         uint32_t vertex_address = REG_A[0];
670         uint32_t vertex;
671
672 #ifdef DEBUG_VERTEX
673         printf("add object's line:\n");
674 #endif
675
676         /* allocate render item */
677         render_item_add(RENDER_ITEM_OBJECT_LINE);
678
679         /* set color */
680         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
681
682         /* two vertices */
683         vertex = m68k_read_memory_8(vertex_address++);
684         render_item->u.line.vertex[0] = vertex;
685         vertex = m68k_read_memory_8(vertex_address++);
686         render_item->u.line.vertex[1] = vertex;
687 }
688
689 /* coordinates ready for a beacon */
690 static void coord_beacon(void)
691 {
692         int32_t x, y, z;
693
694         /* only 28 bits seem to be a correct signed int value */
695         x = (int32_t)(REG_D[3] << 4) / 16;
696         y = (int32_t)(REG_D[4] << 4) / 16;
697         z = (int32_t)(REG_D[5] << 4) / 16;
698         store_coord("beacon", 0, x, y, z, 1.0);
699 }
700
701 /* point of beacon */
702 static void point_beacon(void)
703 {
704 #ifdef DEBUG_VERTEX
705         printf("add beacon's point:\n");
706 #endif
707
708         /* allocate render item */
709         render_item_add(RENDER_ITEM_BEACON_POINT);
710
711         /* set color */
712         gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
713
714         /* one vertex */
715         render_item->u.point.vertex = 0;
716 }
717
718 /* coordinates ready for a building (exterior) */
719 static void coord_building_exterior(void)
720 {
721         int32_t x, y, z;
722
723         x = (int32_t)REG_D[3];
724         y = (int32_t)REG_D[4];
725         z = (int32_t)REG_D[5];
726         store_coord("building exterior", REG_A[0], x, y, z, 1.0);
727 }
728
729 /* polygon of building (exterior) */
730 static void poly_building_exterior(void)
731 {
732         uint16_t color;
733         uint32_t vertex_address = REG_A[0];
734         uint32_t vertex;
735         int i;
736
737 #ifdef DEBUG_VERTEX
738         printf("add building's polygon:\n");
739 #endif
740
741         /* allocate render item */
742         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
743
744         /* set color */
745         color = m68k_read_memory_8(vertex_address++) << 8;
746         color |= m68k_read_memory_8(vertex_address++);
747         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
748
749         /* the vertex list is zero-terminated */
750         for (i = 0; i < MAX_POLYGON; i++) {
751                 vertex = m68k_read_memory_8(vertex_address++);
752                 if (vertex == 0 && i)
753                         break;
754                 render_item->u.polygon.vertex[i] = vertex | 0x100;
755         }
756         render_item->u.polygon.vertices = i;
757 }
758
759 /* line of building (exterior) */
760 static void line_building_exterior(void)
761 {
762         uint32_t vertex_address = REG_A[0];
763         uint32_t vertex;
764
765 #ifdef DEBUG_VERTEX
766         printf("add building's line:\n");
767 #endif
768
769         /* allocate render item */
770         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
771
772         /* set color */
773         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
774
775         /* two vertices */
776         vertex = m68k_read_memory_8(vertex_address++);
777         render_item->u.line.vertex[0] = vertex | 0x100;
778         vertex = m68k_read_memory_8(vertex_address++);
779         render_item->u.line.vertex[1] = vertex | 0x100;
780 }
781
782 /* coordinates ready for a building (interior) */
783 static void coord_building_interior(void)
784 {
785         int16_t east, north;
786         int32_t height1, height2, height3, height4;
787
788         mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
789         store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
790 }
791
792 /* polygon of building (interior) */
793 static void poly_building_interior1to4(int level)
794 {
795         uint16_t color;
796         uint32_t vertex;
797         int i;
798
799 #ifdef DEBUG_VERTEX
800         printf("add roof/floor's polygon at level %d:\n", level);
801 #endif
802
803         /* allocate render item */
804         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
805
806         /* set color */
807         color = m68k_read_memory_8(REG_A[0]) << 8;
808         color |= m68k_read_memory_8(REG_A[0] + 1);
809         gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
810
811         /* four vertices, one level */
812         for (i = 0; i < 4; i++) {
813                 vertex = REG_A[(2 + i)];
814                 render_item->u.interior14.vertex[i] = vertex;
815         }
816         render_item->u.interior14.level = level;
817 }
818
819 /* polygon of building (interior) */
820 static void poly_building_interior5to6(int level12, int level34)
821 {
822         uint16_t color;
823
824 #ifdef DEBUG_VERTEX
825         printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
826 #endif
827
828         /* allocate render item */
829         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
830
831         /* set color */
832         color = m68k_read_memory_8(REG_A[0]) << 8;
833         color |= m68k_read_memory_8(REG_A[0] + 1);
834         gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
835
836         /* two vertices, two levels */
837         render_item->u.interior56.vertex14 = REG_A[2];
838         render_item->u.interior56.vertex23 = REG_A[3];
839         render_item->u.interior56.level12 = level12;
840         render_item->u.interior56.level34 = level34;
841 }
842
843 /* wall part of a building */
844 static void wall_building(void)
845 {
846 #ifdef DEBUG_VERTEX
847         printf("add wall:\n");
848 #endif
849
850         /* allocate render item */
851         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
852
853         /* set color */
854         gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
855
856         /* two vertices, two levels */
857         render_item->u.interior56.vertex14 = REG_A[1];
858         render_item->u.interior56.vertex23 = REG_A[2];
859         /* get top level according to bit 12 in D3 */
860         render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
861         render_item->u.interior56.level34 = 1;
862 }
863
864 /* coordinates ready for comet tail */
865 static void coord_comet(void)
866 {
867         int32_t x, y, z;
868
869         x = (int32_t)REG_D[3];
870         y = (int32_t)REG_D[4];
871         z = (int32_t)REG_D[5];
872         store_planets_coord("comet tail", REG_A[0], x, y, z);
873 }
874
875 /* polygon of comet tail */
876 static void poly_comet(void)
877 {
878         uint16_t color;
879         uint32_t vertex_address = REG_A[0];
880         uint32_t vertex;
881         int i;
882
883 #ifdef DEBUG_VERTEX
884         printf("add comet's polygon:\n");
885 #endif
886
887         /* allocate render item */
888         render_item_add(RENDER_ITEM_COMET_POLYGON);
889
890         /* set color */
891         color = m68k_read_memory_8(vertex_address++) << 8;
892         color |= m68k_read_memory_8(vertex_address++);
893         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
894
895         /* the vertex list is zero-terminated */
896         for (i = 0; i < MAX_POLYGON; i++) {
897                 vertex = m68k_read_memory_8(vertex_address++);
898                 if (vertex == 0 && i)
899                         break;
900                 render_item->u.polygon.vertex[i] = vertex;
901         }
902         render_item->u.polygon.vertices = i;
903 }
904
905 /* coordinates ready for lines of a road / ground surface */
906 static void coord_line_road(void)
907 {
908         int32_t x, y, z;
909
910         x = REG_D[3];
911         y = -motion_new.position_height;
912         z = REG_D[5];
913         store_coord("road", REG_A[0], x, y, z, 1.0);
914 }
915
916 /* line of road */
917 static void line_road(void)
918 {
919         uint32_t vertex;
920
921 #ifdef DEBUG_VERTEX
922         printf("add road's line:\n");
923 #endif
924
925         /* allocate render item */
926         render_item_add(RENDER_ITEM_ROAD_LINE);
927
928         /* set color */
929         gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
930
931         /* two vertices */
932         vertex = REG_A[1];
933         render_item->u.line.vertex[0] = vertex;
934         vertex = REG_A[2];
935         render_item->u.line.vertex[1] = vertex;
936 }
937
938 /* coordinates ready for polygons of a road / ground surface */
939 static void coord_poly_road(void)
940 {
941         int32_t x, y, z;
942
943         x = m68k_read_memory_32(320 + REG_A[0]);
944         x -= REG_A[1];
945         /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
946         y = -motion_new.position_height;
947         z = m68k_read_memory_32(576 + REG_A[0]);
948         z -= REG_A[3];
949         store_coord("road/place", REG_A[0], x, y, z, 1.0);
950 }
951
952 /* polygon of road */
953 static void poly_road()
954 {
955         uint16_t color;
956         uint32_t vertex_address = REG_A[0];
957         uint32_t vertex;
958         int i;
959
960 #ifdef DEBUG_VERTEX
961         printf("add road/place's polygon:\n");
962 #endif
963
964         /* allocate render item */
965         render_item_add(RENDER_ITEM_ROAD_POLYGON);
966
967         /* set color */
968         color = m68k_read_memory_8(vertex_address++) << 8;
969         color |= m68k_read_memory_8(vertex_address++);
970         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
971
972         /* the vertex list is zero-terminated */
973         for (i = 0; i < MAX_POLYGON; i++) {
974                 vertex = m68k_read_memory_8(vertex_address++);
975                 if (vertex == 0 && i)
976                         break;
977                 render_item->u.polygon.vertex[i] = vertex;
978         }
979         render_item->u.polygon.vertices = i;
980 }
981
982 /* coordinates ready for tags */
983 static void coord_tags(void)
984 {
985         int32_t x, y, z;
986
987         x = (int16_t)REG_D[3];
988         x += (int32_t)REG_A[1];
989         y = (int16_t)REG_D[4];
990         y += (int32_t)REG_A[2];
991         z = (int16_t)REG_D[5];
992         z += (int32_t)REG_A[3];
993         store_coord("tags", REG_A[0], x, y, z, 1.0);
994 }
995
996 /* coordinates ready for large tags */
997 static void coord_tags2(void)
998 {
999         int32_t x, y, z;
1000
1001         x = (int16_t)REG_D[3];
1002         x += 2 * (int32_t)REG_A[1];
1003         y = (int16_t)REG_D[4];
1004         y += 2 * (int32_t)REG_A[2];
1005         z = (int16_t)REG_D[5];
1006         z += 2 * (int32_t)REG_A[3];
1007         /* note that large tags have double distance, so the resolution is vitrually doubled.
1008          * since we use interpolation and VR, we need to scale the vertex back to normal distance.
1009          */
1010         store_coord("large tags", REG_A[0], x, y, z, 0.5);
1011 }
1012
1013 /* line of tag */
1014 static void line_tags(int last_color)
1015 {
1016         uint32_t vertex_address = REG_A[0];
1017         uint32_t vertex;
1018
1019 #ifdef DEBUG_VERTEX
1020         printf("add tag's line:\n");
1021 #endif
1022
1023         /* allocate render item */
1024         render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
1025
1026         /* set color */
1027         if (!last_color)
1028                 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
1029         else
1030                 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
1031
1032         /* two vertices */
1033         vertex = m68k_read_memory_8(vertex_address++);
1034         render_item->u.line.vertex[0] = vertex | 0x200;
1035         vertex = m68k_read_memory_8(vertex_address++);
1036         render_item->u.line.vertex[1] = vertex | 0x200;
1037 }
1038
1039 /* polygon of tags */
1040 static void poly_tags(int last_color)
1041 {
1042         uint32_t vertex_address = REG_A[0];
1043         uint32_t vertex;
1044         int i;
1045
1046 #ifdef DEBUG_VERTEX
1047         printf("add tag's polygon:\n");
1048 #endif
1049
1050         /* allocate render item */
1051         render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1052
1053         /* set color */
1054         if (!last_color)
1055                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1056         else
1057                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
1058         /* the vertex list is zero-terminated */
1059         for (i = 0; i < MAX_POLYGON; i++) {
1060                 vertex = m68k_read_memory_8(vertex_address++);
1061                 if (vertex == 0 && i)
1062                         break;
1063                 render_item->u.polygon.vertex[i] = vertex | 0x200;
1064         }
1065         render_item->u.polygon.vertices = i;
1066 }
1067
1068 /* coordinates ready for planet */
1069 static void coord_planet(void)
1070 {
1071         int32_t x, y, z;
1072
1073         x = (int32_t)REG_D[3];
1074         y = (int32_t)REG_D[4];
1075         z = (int32_t)REG_D[5];
1076         store_planets_coord("planet", REG_A[0], x, y, z);
1077 }
1078
1079 /* planet */
1080 static void draw_planet(int comet)
1081 {
1082         uint32_t vertex;
1083         uint32_t scale_index;
1084         double scale1, scale2;
1085
1086         vertex = REG_A[0];
1087
1088         /* fixing (not noticable) bug in game: don't render comet twice */
1089         if (!comet && vertex == 116)
1090                 return;
1091
1092 #ifdef DEBUG_VERTEX
1093         printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1094 #endif
1095
1096         /* allocate render item */
1097         render_item_add(RENDER_ITEM_PLANET);
1098
1099         /* set color */
1100         if (comet) {
1101                 /* make comet black on front side and bright on back */
1102                 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
1103                 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
1104
1105         } else {
1106                 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
1107                 /* use background color for dark side */
1108                 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
1109         }
1110
1111         /* set vertex */
1112         render_item->u.planet.vertex = vertex;
1113
1114         /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
1115          * the long word 21584(A0) contains two scales
1116          * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1117          * the upper word defines how much this scale is shifted to the left.
1118          */
1119         scale_index = mercenary_planet_scale_index();
1120         scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 4096.0;
1121         scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
1122         render_item->u.planet.size = scale1 * scale2 / 256.0;
1123 }
1124
1125 /* stars */
1126 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1127 {
1128 #ifdef DEBUG_VERTEX
1129         printf("add stars\n");
1130 #endif
1131
1132         /* allocate render item */
1133         render_item_add(RENDER_ITEM_STARS);
1134
1135         /* vertical offset */
1136         render_item->u.stars.v_offset = v_offset;
1137
1138         /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
1139         render_item->u.stars.tilt = tilt;
1140         if (tilt)
1141                 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1142
1143         /* stars above zenith */
1144         render_item->u.stars.above_zenith = above_zenith;
1145 }
1146
1147 /* stars of interstellar flight */
1148 static void draw_stars_interstellar(void)
1149 {
1150         int i, count;
1151         uint32_t table;
1152
1153 #ifdef DEBUG_VERTEX
1154         printf("add interstellar stars\n");
1155 #endif
1156
1157         /* allocate render item */
1158         render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1159
1160         table = REG_A[0];
1161         count = REG_D[5] + 1;
1162         if (count > MAX_INTERSTARS) {
1163                 print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
1164                 return;
1165         }
1166         for (i = 0; i < count; i++) {
1167                 table += 12;
1168                 /* get color */
1169                 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1170                 table += 2;
1171                 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1172                 table += 2;
1173                 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1174                 table += 2;
1175         }
1176         render_item->u.interstars.count = count;
1177 }
1178
1179 /* sun of interstellar flight (center dot) */
1180 static void draw_sun_interstellar(void)
1181 {
1182 #ifdef DEBUG_VERTEX
1183         printf("add interstellar sun\n");
1184 #endif
1185
1186         /* allocate render item */
1187         render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1188 }
1189
1190 /* coordinates ready for polygons of islands */
1191 static void coord_islands(void)
1192 {
1193         int32_t x, y, z;
1194
1195         x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1196         x += (int32_t)REG_A[1];
1197         /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1198         y = -motion_new.position_height;
1199         z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1200         z += (int32_t)REG_A[3];
1201         store_coord("island", REG_A[0], x, y, z, 1.0);
1202 }
1203
1204 /* polygon of island */
1205 static void poly_island()
1206 {
1207         uint16_t color;
1208         uint32_t vertex_address = REG_A[0];
1209         uint32_t vertex;
1210         int i;
1211
1212 #ifdef DEBUG_VERTEX
1213         printf("add island:\n");
1214 #endif
1215
1216         /* allocate render item */
1217         render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1218
1219         /* set color */
1220         color = m68k_read_memory_8(vertex_address++) << 8;
1221         color |= m68k_read_memory_8(vertex_address++);
1222         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1223
1224         /* the vertex list is zero-terminated */
1225         i = 0;
1226         while (i < MAX_POLYGON) {
1227                 vertex = m68k_read_memory_8(vertex_address++);
1228                 if (vertex == 0 && i)
1229                         break;
1230                 /* skip mysterious points when rendering island */
1231                 if (vertex >= 0xf0)
1232                         continue;
1233                 render_item->u.polygon.vertex[i] = vertex;
1234                 i++;
1235         }
1236         render_item->u.polygon.vertices = i;
1237 }
1238
1239 /* sights */
1240 static void draw_sights(void)
1241 {
1242 #ifdef DEBUG_VERTEX
1243         printf("add sights:\n");
1244 #endif
1245
1246         /* allocate render item */
1247         render_item_add(RENDER_ITEM_SIGHTS);
1248 }
1249
1250 static int32_t coord_explosion_x, coord_explosion_y, coord_explosion_z;
1251
1252 static void coord_explosion(void)
1253 {
1254         coord_explosion_x = REG_D[3];
1255         coord_explosion_y = REG_D[4];
1256         coord_explosion_z = REG_D[5];
1257 }
1258
1259 static void draw_explosion(void)
1260 {
1261         uint16_t color;
1262         double scale1, scale2;
1263
1264 #ifdef DEBUG_VERTEX
1265         printf("add explosion:\n");
1266 #endif
1267
1268         /* allocate render item */
1269         if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
1270                 render_item_add(RENDER_ITEM_EXPLOSION);
1271                 /* get color from render palette */
1272                 color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
1273                 gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
1274                 render_item->u.explosion.count = 0;
1275         }
1276         if (render_item->u.explosion.count == MAX_EXPLOSION)
1277                 return;
1278
1279         /* the D1 register contains two scales
1280          * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1281          * the upper word defines how much this scale is shifted to the left.
1282          */
1283         if ((int16_t)(REG_D[1] >> 16) < 0) {
1284                 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1285                 scale2 = (double)(256 >> -(int16_t)(REG_D[1] >> 16)) / 256.0;
1286         } else
1287         if ((int16_t)(REG_D[1] >> 16) <= 10) {
1288                 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1289                 scale2 = (double)(1 << (int16_t)(REG_D[1] >> 16));
1290         } else {
1291                 scale1 = 1.0;
1292                 scale2 = 1 << 10;
1293         }
1294         render_item->u.explosion.size[render_item->u.explosion.count] = scale1 * scale2;
1295         render_item->u.explosion.x[render_item->u.explosion.count] = coord_explosion_x;
1296         render_item->u.explosion.y[render_item->u.explosion.count] = coord_explosion_y;
1297         render_item->u.explosion.z[render_item->u.explosion.count] = coord_explosion_z;
1298         render_item->u.explosion.count++;
1299 }
1300
1301 /* stop event from CPU received */
1302 void render_capture_event(int event)
1303 {
1304         switch (event) {
1305         case STOP_AT_CLEAR_SCREEN1:
1306                 clear_screen(16); /* color 16 is raster split */
1307                 /* in case of screen clearing on the ground, there is no roll */
1308                 motion_new.orientation_roll = 0;
1309                 break;
1310         case STOP_AT_CLEAR_SCREEN2:
1311                 clear_screen(15);
1312                 break;
1313         case STOP_AT_CLEAR_SCREEN3:
1314                 clear_screen(-1); /* no ground (in universe) */
1315                 break;
1316         case STOP_AT_DRAW_GROUND:
1317                 draw_ground();
1318                 break;
1319         case STOP_AT_INFO_OBJECT_MOVING:
1320                 info_object(1);
1321                 break;
1322         case STOP_AT_INFO_OBJECT_FIX:
1323                 info_object(0);
1324                 break;
1325         case STOP_AT_TAG_IS_OBJECT_1:
1326                 tag_is_object = 1;
1327                 break;
1328         case STOP_AT_TAG_IS_OBJECT_0:
1329                 tag_is_object = 0;
1330                 break;
1331         case STOP_AT_COORD_OBJECT:
1332                 coord_object();
1333                 break;
1334         case STOP_AT_POLY_OBJECT_M3:
1335                 poly_object(3);
1336                 break;
1337         case STOP_AT_POLY_OBJECT_M2:
1338                 poly_object(2);
1339                 break;
1340         case STOP_AT_LINE_OBJECT:
1341                 line_object();
1342                 break;
1343         case STOP_AT_COORD_BEACON:
1344                 coord_beacon();
1345                 break;
1346         case STOP_AT_POINT_BEACON:
1347                 point_beacon();
1348                 /* note: we may not call the point-renderer, because projected coordinates are invalid */
1349                 mercenary_patch_render();
1350                 break;
1351         case STOP_AT_COORD_BUILDING_EXTERIOR:
1352                 coord_building_exterior();
1353                 break;
1354         case STOP_AT_POLY_BUILDING_EXTERIOR:
1355                 poly_building_exterior();
1356                 break;
1357         case STOP_AT_LINE_BUILDING_EXTERIOR:
1358                 line_building_exterior();
1359                 break;
1360         case STOP_AT_COORD_BUILDING_INTERIOR:
1361                 coord_building_interior();
1362                 break;
1363         case STOP_AT_POLY_BUILDING_INTERIOR1:
1364                 /* floor */
1365                 interior_level12 = 1;
1366                 interior_level34 = 1;
1367                 break;
1368         case STOP_AT_POLY_BUILDING_INTERIOR2:
1369                 /* ceiling */
1370                 interior_level12 = 2;
1371                 interior_level34 = 2;
1372                 break;
1373         case STOP_AT_POLY_BUILDING_INTERIOR3:
1374                 /* door/window top */
1375                 interior_level12 = 3;
1376                 interior_level34 = 3;
1377                 break;
1378         case STOP_AT_POLY_BUILDING_INTERIOR4:
1379                 /* window bottom */
1380                 interior_level12 = 4;
1381                 interior_level34 = 4;
1382                 break;
1383         case STOP_AT_POLY_BUILDING_INTERIOR5:
1384                 /* door/window top */
1385                 interior_level12 = 2;
1386                 interior_level34 = 3;
1387                 break;
1388         case STOP_AT_POLY_BUILDING_INTERIOR6:
1389                 /* window bottom */
1390                 interior_level12 = 1;
1391                 interior_level34 = 4;
1392                 break;
1393         case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1394                 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1395                 if (interior_level12 == 0) {
1396                         print_info("Interior level is not set, please fix!\n");
1397                         break;
1398                 }
1399                 poly_building_interior1to4(interior_level12);
1400                 interior_level12 = 0;
1401                 break;
1402         case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1403                 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1404                 if (interior_level12 == 0) {
1405                         print_info("Interior level is not set, please fix!\n");
1406                         break;
1407                 }
1408                 poly_building_interior5to6(interior_level12, interior_level34);
1409                 interior_level12 = 0;
1410                 break;
1411         case STOP_AT_WALL_BUILDING:
1412                 wall_building();
1413                 break;
1414         case STOP_AT_COORD_COMET:
1415                 coord_comet();
1416                 break;
1417         case STOP_AT_MATRIX_COMET:
1418         case STOP_AT_MATRIX_PLANET:
1419                 /* track the rotation matrix
1420                  * if we have 0x42c44 matrix, we must add extra rotation to planet.
1421                  * the rotation will change the view from the planet's surface */
1422                 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1423                         motion_new.planet_rotation = 1;
1424                 else
1425                         motion_new.planet_rotation = 0;
1426                 break;
1427         case STOP_AT_POLY_COMET:
1428                 poly_comet();
1429                 break;
1430         case STOP_AT_COORD_LINE_ROADS:
1431                 coord_line_road();
1432                 break;
1433         case STOP_AT_LINE_ROADS:
1434                 line_road();
1435                 break;
1436         case STOP_AT_COORD_POLY_ROADS:
1437                 coord_poly_road();
1438                 break;
1439         case STOP_AT_LINE_ROADS_CENTER:
1440                 /* we don't need to render center lines of roads, because there are polygons already
1441                  * it does not make sense, since OpenGL has much higher resolution.
1442                  */
1443                 break;
1444         case STOP_AT_POLY_ROADS:
1445                 poly_road();
1446                 break;
1447         case STOP_AT_COORD_TAGS:
1448                 coord_tags();
1449                 break;
1450         case STOP_AT_COORD_TAGS2:
1451                 coord_tags2();
1452                 break;
1453         case STOP_AT_LINE_TAGS1:
1454                 line_tags(0);
1455                 break;
1456         case STOP_AT_LINE_TAGS2:
1457                 line_tags(1);
1458                 break;
1459         case STOP_AT_POLY_TAGS1:
1460                 poly_tags(0);
1461                 break;
1462         case STOP_AT_POLY_TAGS2:
1463                 poly_tags(1);
1464                 break;
1465         case STOP_AT_COORD_PLANET:
1466                 coord_planet();
1467                 break;
1468         case STOP_AT_DRAW_PLANET:
1469                 draw_planet(0);
1470                 break;
1471         case STOP_AT_DRAW_COMET:
1472                 draw_planet(1);
1473                 break;
1474         case STOP_AT_DRAW_STARS_SPACE:
1475                 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1476                 draw_stars(0x1c0, 0, 0);
1477                 break;
1478         case STOP_AT_DRAW_STARS_GROUND:
1479                 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1480                 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1481                 break;
1482         case STOP_AT_DRAW_STARS_FLYING:
1483                 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1484                 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1485                 break;
1486         case STOP_AT_DRAW_STARS_FLYING2:
1487                 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1488                 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1489                 break;
1490         case STOP_AT_DRAW_STARS_INTERSTELLAR:
1491                 draw_stars_interstellar();
1492                 break;
1493         case STOP_AT_DRAW_SUN_INTERSTELLAR:
1494                 draw_sun_interstellar();
1495                 break;
1496         case STOP_AT_COORD_ISLANDS:
1497                 coord_islands();
1498                 break;
1499         case STOP_AT_POLY_ISLANDS:
1500                 poly_island();
1501                 break;
1502         case STOP_AT_LINE_ISLANDS:
1503                 /* this is not used, as i had noticed so far */
1504                 puts("line island");
1505                 break;
1506         case STOP_AT_DRAW_SIGHTS:
1507                 draw_sights();
1508                 break;
1509         case STOP_AT_POLY_UKN2:
1510                 puts("poly ukn2");
1511                 break;
1512         case STOP_AT_COORD_EXPLOSION:
1513                 coord_explosion();
1514                 break;
1515         case STOP_AT_DRAW_EXPLOSION:
1516                 draw_explosion();
1517                 break;
1518         case STOP_AT_PATCH_RENDER:
1519                 mercenary_patch_render();
1520                 break;
1521         }
1522 }
1523
1524 /*
1525  * rendering
1526  */
1527
1528 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix)
1529 {
1530         render_item_t *ri = NULL;
1531
1532         if ((vertex & 3)) {
1533                 print_info("Vertex %d is not a multiple of four!\n", vertex);
1534                 return -1;
1535         }
1536         if (vertex < 0x100) {
1537                 if (!render_item_vertices_0) {
1538                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1539                         return -1;
1540                 }
1541                 ri = render_item_vertices_0;
1542         } else
1543         if (vertex < 0x200) {
1544                 if (!render_item_vertices_1) {
1545                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1546                         return -1;
1547                 }
1548                 ri = render_item_vertices_1;
1549                 vertex -= 0x100;
1550         } else
1551         if (vertex < 0x300) {
1552                 if (!render_item_vertices_2) {
1553                         print_info("Vertices item for vertex %d not yet set!\n", vertex);
1554                         return -1;
1555                 }
1556                 ri = render_item_vertices_2;
1557                 vertex -= 0x200;
1558         } else {
1559                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1560                 return -1;
1561         }
1562         vertex >>= 2;
1563         /* translate to original position */
1564         *x = ri->u.vertices.x[vertex] - motion_new.position_east;
1565         *y = ri->u.vertices.y[vertex] - motion_new.position_height;
1566         *z = ri->u.vertices.z[vertex] - motion_new.position_north;
1567         if (!fix) {
1568                 /* translate to floating (interpolated) position offset */
1569                 *x -= interpolation.offset_east;
1570                 *y -= interpolation.offset_height;
1571                 *z -= interpolation.offset_north;
1572         }
1573 #ifdef DEBUG_VERTEX
1574         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1575 #endif
1576
1577         return 0;
1578 }
1579
1580 static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1581 {
1582         render_item_t *ri = NULL;
1583
1584         if ((vertex & 3)) {
1585                 print_info("Vertex %d is not a multiple of four!\n", vertex);
1586                 return -1;
1587         }
1588         if (vertex >= MAX_VERTEX) {
1589                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1590                 return -1;
1591         }
1592         if (interpolation.planets)
1593                 ri = interpolation.planets;
1594         else
1595                 ri = render_item_vertices_0;
1596         if (!ri) {
1597                 print_info("Vertices item for planets verticies not yet set!\n");
1598                 return -1;
1599         }
1600         vertex >>= 2;
1601         *x = ri->u.vertices.x[vertex];
1602         *y = ri->u.vertices.y[vertex];
1603         *z = ri->u.vertices.z[vertex];
1604 #ifdef DEBUG_VERTEX
1605         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1606 #endif
1607
1608         return 0;
1609 }
1610
1611 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1612 {
1613         if ((vertex & 3)) {
1614                 print_info("Vertex is not a multiple of four!\n");
1615                 return -1;
1616         }
1617         if (vertex >= MAX_INTERIOR_VERTEX) {
1618                 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1619                 return -1;
1620         }
1621         if (level < 1 || level > 4) {
1622                 print_info("Level %d is out of range (1..4)!\n", level);
1623                 return -1;
1624         }
1625         if (!render_item_vertices_interior) {
1626                 print_info("Vertices item for interior verticies not yet set!\n");
1627                 return -1;
1628         }
1629         vertex >>= 2;
1630         *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1631         *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1632         *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1633         /* translate to position back to original */
1634         *x -= motion_new.position_east;
1635         *y -= motion_new.position_height;
1636         *z -= motion_new.position_north;
1637         /* translate to floating (interpolated) position offset */
1638         *x -= interpolation.offset_east;
1639         *y -= interpolation.offset_height;
1640         *z -= interpolation.offset_north;
1641
1642 #ifdef DEBUG_VERTEX
1643         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1644 #endif
1645
1646         return 0;
1647 }
1648
1649 /* renders one item from render list */
1650 void render_one_item(render_item_t *render_item, int vr)
1651 {
1652         switch (render_item->type) {
1653         case RENDER_ITEM_OBJECT_INFO:
1654         {
1655 #ifdef DEBUG_ITEMS
1656                 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1657 #endif
1658                 render_item_object_info = render_item;
1659                 break;
1660         }
1661         case RENDER_ITEM_VERTICES_0:
1662         {
1663 #ifdef DEBUG_ITEMS
1664                 printf("RENDER_ITEM_VERTICES_0\n");
1665 #endif
1666                 render_item_vertices_0 = render_item;
1667                 break;
1668         }
1669         case RENDER_ITEM_VERTICES_1:
1670         {
1671 #ifdef DEBUG_ITEMS
1672                 printf("RENDER_ITEM_VERTICES_1\n");
1673 #endif
1674                 render_item_vertices_1 = render_item;
1675                 break;
1676         }
1677         case RENDER_ITEM_VERTICES_2:
1678         {
1679 #ifdef DEBUG_ITEMS
1680                 printf("RENDER_ITEM_VERTICES_2\n");
1681 #endif
1682                 render_item_vertices_2 = render_item;
1683                 break;
1684         }
1685         case RENDER_ITEM_VERTICES_INTERIOR:
1686         {
1687 #ifdef DEBUG_ITEMS
1688                 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1689 #endif
1690                 if (interpolation.interior)
1691                         render_item_vertices_interior = interpolation.interior;
1692                 else
1693                         render_item_vertices_interior = render_item;
1694                 break;
1695         }
1696         case RENDER_ITEM_SKY:
1697         {
1698                 double x[4], y[4], z[4];
1699
1700 #ifdef DEBUG_ITEMS
1701                 printf("RENDER_ITEM_SKY\n");
1702 #endif
1703                 /* get color */
1704                 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1705                 /* create box to fill view */
1706                 x[0] = x[1] = y[1] = y[2] = -1000;
1707                 x[2] = x[3] = y[0] = y[3] = 1000;
1708                 z[0] = z[1] = z[2] = z[3] = 1000;
1709                 opengl_render_polygon_and_line(x, y, z, 4);
1710                 z[0] = z[1] = z[2] = z[3] = -1000;
1711                 opengl_render_polygon_and_line(x, y, z, 4);
1712                 x[0] = x[1] = z[1] = z[2] = -1000;
1713                 x[2] = x[3] = z[0] = z[3] = 1000;
1714                 y[0] = y[1] = y[2] = y[3] = 1000;
1715                 opengl_render_polygon_and_line(x, y, z, 4);
1716                 y[0] = y[1] = y[2] = y[3] = -1000;
1717                 opengl_render_polygon_and_line(x, y, z, 4);
1718                 y[0] = y[1] = z[1] = z[2] = -1000;
1719                 y[2] = y[3] = z[0] = z[3] = 1000;
1720                 x[0] = x[1] = x[2] = x[3] = 1000;
1721                 opengl_render_polygon_and_line(x, y, z, 4);
1722                 x[0] = x[1] = x[2] = x[3] = -1000;
1723                 opengl_render_polygon_and_line(x, y, z, 4);
1724                 break;
1725         }
1726         case RENDER_ITEM_GROUND:
1727         {
1728                 GET_ORIENTATION;
1729                 double x[4], y[4], z[4];
1730                 int i;
1731
1732 #ifdef DEBUG_ITEMS
1733                 printf("RENDER_ITEM_GROUND\n");
1734 #endif
1735                 /* get color */
1736                 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1737                 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1738                 /* create huge square */
1739                 x[0] = x[1] = z[1] = z[2] = -10000000;
1740                 x[2] = x[3] = z[0] = z[3] = 10000000;
1741                 y[0] = y[1] = y[2] = y[3] = -1000;
1742                 /* rotate vertex */
1743                 for (i = 0; i < 4; i++)
1744                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1745                 /* render */
1746                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1747                 break;
1748         }
1749         case RENDER_ITEM_OBJECT_POLYGON:
1750         case RENDER_ITEM_TAG_POLYGON_OBJECT:
1751         case RENDER_ITEM_TAG_POLYGON_OTHER:
1752         case RENDER_ITEM_ISLAND_POLYGON:
1753         {
1754                 GET_ORIENTATION;
1755                 int fix = 0;
1756                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1757                 int i, o;
1758                 int rc;
1759
1760 #ifdef DEBUG_ITEMS
1761                 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1762                         printf("RENDER_ITEM_OBJECT_POLYGON\n");
1763                 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
1764                         printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
1765                 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
1766                         printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
1767                 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1768                         printf("RENDER_ITEM_ISLAND_POLYGON\n");
1769 #endif
1770
1771                 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1772                 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) {
1773 //                      GET_ORIENTATION_FIX;
1774                         fix = 1;
1775                 }
1776
1777                 /* get color */
1778                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1779                 /* get and rotate vertex */
1780                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1781                         /* get vertex */
1782                         rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
1783                         if (rc < 0)
1784                                 break;
1785                         /* fixed objects are pre-scaled by 16, so we correct this */
1786                         if (fix) {
1787                                 x[i] /= FIX_OBJECT_SCALE;
1788                                 y[i] /= FIX_OBJECT_SCALE;
1789                                 z[i] /= FIX_OBJECT_SCALE;
1790                         }
1791                         /* interpolate motion, if object is moving */
1792                         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) {
1793                                 for (o = 0; o < interpolation.object_count; o++) {
1794                                         if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1795                                                 break;
1796                                 }
1797                                 if (o < interpolation.object_count) {
1798                                         x[i] += interpolation.object_offset_east[o];
1799                                         y[i] += interpolation.object_offset_height[o];
1800                                         z[i] += interpolation.object_offset_north[o];
1801                                 }
1802                         }
1803                         /* rotate vertex */
1804                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1805                 }
1806                 /* render */
1807                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1808                 break;
1809         }
1810         case RENDER_ITEM_OBJECT_LINE:
1811         case RENDER_ITEM_TAG_LINE_OBJECT:
1812         case RENDER_ITEM_TAG_LINE_OTHER:
1813         {
1814                 GET_ORIENTATION;
1815                 int fix = 0;
1816                 double x[2], y[2], z[2];
1817                 int i, o;
1818                 int rc;
1819
1820 #ifdef DEBUG_ITEMS
1821                 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1822                         printf("RENDER_ITEM_OBJECT_LINE\n");
1823                 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
1824                         printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
1825                 if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
1826                         printf("RENDER_ITEM_TAG_LINE_OTHER\n");
1827 #endif
1828
1829                 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1830                 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) {
1831 //                      GET_ORIENTATION_FIX;
1832                         fix = 1;
1833                 }
1834
1835                 /* get color */
1836                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1837                 /* get and rotate vertex */
1838                 for (i = 0; i < 2; i++) {
1839                         /* get vertex */
1840                         rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
1841                         if (rc < 0)
1842                                 break;
1843                         /* fixed objects are pre-scaled by 16, so we correct this */
1844                         if (fix) {
1845                                 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT) {
1846                                         x[i] /= FIX_OBJECT_SCALE_TAG;
1847                                         y[i] /= FIX_OBJECT_SCALE_TAG;
1848                                         z[i] /= FIX_OBJECT_SCALE_TAG;
1849                                 } else {
1850                                         x[i] /= FIX_OBJECT_SCALE;
1851                                         y[i] /= FIX_OBJECT_SCALE;
1852                                         z[i] /= FIX_OBJECT_SCALE;
1853                                 }
1854                         }
1855                         /* interpolate motion, if object is moving */
1856                         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) {
1857                                 for (o = 0; o < interpolation.object_count; o++) {
1858                                         if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1859                                                 break;
1860                                 }
1861                                 if (o < interpolation.object_count) {
1862                                         x[i] += interpolation.object_offset_east[o];
1863                                         y[i] += interpolation.object_offset_height[o];
1864                                         z[i] += interpolation.object_offset_north[o];
1865                                 }
1866                         }
1867                         /* rotate vertex */
1868                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1869                 }
1870                 /* render */
1871                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1872                 break;
1873         }
1874         case RENDER_ITEM_BEACON_POINT:
1875         {
1876                 GET_ORIENTATION;
1877                 double x, y, z;
1878                 int rc;
1879
1880 #ifdef DEBUG_ITEMS
1881                 printf("RENDER_ITEM_BEACON_POINT\n");
1882 #endif
1883                 /* get color */
1884                 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1885                 /* get vertex */
1886                 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
1887                 if (rc < 0)
1888                         break;
1889                 /* rotate vertex */
1890                 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1891                 /* render */
1892                 opengl_render_point(x, y, z, 0.0);
1893                 break;
1894         }
1895         case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1896         {
1897                 GET_ORIENTATION;
1898                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1899                 int i;
1900                 int rc;
1901
1902 #ifdef DEBUG_ITEMS
1903                 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1904 #endif
1905                 /* get color */
1906                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1907                 /* get and rotate vertex */
1908                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1909                         /* get vertex */
1910                         rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
1911                         if (rc < 0)
1912                                 break;
1913                         /* rotate vertex */
1914                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1915                 }
1916                 /* render */
1917                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1918                 break;
1919         }
1920         case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
1921         {
1922                 GET_ORIENTATION;
1923                 double x[2], y[2], z[2];
1924                 int i;
1925                 int rc;
1926
1927 #ifdef DEBUG_ITEMS
1928                 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1929 #endif
1930                 /* get color */
1931                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1932                 /* get and rotate vertex */
1933                 for (i = 0; i < 2; i++) {
1934                         /* get vertex */
1935                         rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
1936                         if (rc < 0)
1937                                 break;
1938                         /* rotate vertex */
1939                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1940                 }
1941                 /* render */
1942                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1943                 break;
1944         }
1945         case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1946         {
1947                 GET_ORIENTATION;
1948                 double x[4], y[4], z[4];
1949                 int i;
1950                 int rc;
1951
1952 #ifdef DEBUG_ITEMS
1953                 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1954 #endif
1955                 /* get color */
1956                 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1957                 /* get and rotate vertex */
1958                 for (i = 0; i < 4; i++) {
1959                         /* get vertex */
1960                         rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1961                         if (rc < 0)
1962                                 break;
1963                         /* rotate vertex */
1964                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1965                 }
1966                 /* render */
1967                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1968                 break;
1969         }
1970         case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1971         {
1972                 GET_ORIENTATION;
1973                 double x[4], y[4], z[4];
1974                 int i;
1975                 int vertex, level;
1976                 int rc;
1977
1978 #ifdef DEBUG_ITEMS
1979                 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1980 #endif
1981                 /* get color */
1982                 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1983                 /* get and rotate vertex */
1984                 for (i = 0; i < 4; i++) {
1985                         /* get vertex */
1986                         vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1987                         level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1988                         rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1989                         if (rc < 0)
1990                                 break;
1991                         /* rotate vertex */
1992                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1993                 }
1994                 /* render */
1995                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1996                 break;
1997         }
1998         case RENDER_ITEM_BUILDING_INTERIOR_WALL:
1999         {
2000                 GET_ORIENTATION;
2001                 double x[4], y[4], z[4];
2002                 int i;
2003                 int vertex, level;
2004                 int rc;
2005
2006 #ifdef DEBUG_ITEMS
2007                 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
2008 #endif
2009                 /* get color */
2010                 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
2011                 /* chedck if wall is a rectangle or a line */
2012                 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
2013                         /* get and rotate vertex */
2014                         for (i = 0; i < 4; i++) {
2015                                 /* get vertex */
2016                                 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
2017                                 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2018                                 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2019                                 if (rc < 0)
2020                                         break;
2021                                 /* rotate vertex */
2022                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2023                         }
2024                         /* render */
2025                         opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
2026                 } else {
2027                         /* get and rotate vertex */
2028                         for (i = 0; i < 2; i++) {
2029                                 /* get vertex */
2030                                 vertex = render_item->u.interior56.vertex14;
2031                                 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2032                                 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2033                                 if (rc < 0)
2034                                         break;
2035                                 /* rotate vertex */
2036                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2037                         }
2038                         /* render */
2039                         opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2040                 }
2041                 break;
2042         }
2043         case RENDER_ITEM_COMET_POLYGON:
2044         {
2045                 GET_ORIENTATION;
2046                 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2047                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2048                 int i;
2049                 int rc;
2050                 double rotate_sky = 0.0;
2051
2052 #ifdef DEBUG_ITEMS
2053                 printf("RENDER_ITEM_COMET_POLYGON\n");
2054 #endif
2055                 /* get color */
2056                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2057                 /* get and rotate vertex */
2058                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2059                         /* get vertex */
2060                         rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
2061                         if (rc < 0)
2062                                 break;
2063                         /* rotate vertex */
2064                         if (motion_new.planet_rotation) {
2065                                 if (fix_sky_rotation)
2066                                         rotate_sky = M_PI;
2067                                 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
2068                         }
2069                         rotate_coordinate(roll, pitch, yaw + rotate_sky, &x[i], &y[i], &z[i]);
2070                 }
2071                 /* render */
2072                 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
2073                 break;
2074         }
2075         case RENDER_ITEM_ROAD_LINE:
2076         {
2077                 GET_ORIENTATION;
2078                 double x[2], y[2], z[2];
2079                 int i;
2080                 int rc;
2081
2082 #ifdef DEBUG_ITEMS
2083                 printf("RENDER_ITEM_ROAD_LINE\n");
2084 #endif
2085                 /* get color */
2086                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2087                 /* get and rotate vertex */
2088                 for (i = 0; i < 2; i++) {
2089                         /* get vertex */
2090                         rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2091                         if (rc < 0)
2092                                 break;
2093                         /* rotate vertex */
2094                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2095                 }
2096                 /* render */
2097                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2098                 break;
2099         }
2100         case RENDER_ITEM_ROAD_POLYGON:
2101         {
2102                 GET_ORIENTATION;
2103                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2104                 int i, v;
2105                 uint32_t vertex, vertex_prev, vertex_next;
2106                 double x_current, y_current, z_current;
2107                 double x_prev, y_prev, z_prev;
2108                 double x_next, y_next, z_next;
2109                 int vertices_num;
2110                 int rc;
2111
2112 #ifdef DEBUG_ITEMS
2113                 printf("RENDER_ITEM_ROAD_POLYGON\n");
2114 #endif
2115                 /* get color */
2116                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2117                 /* get and rotate vertex */
2118                 i = 0;
2119                 vertices_num = render_item->u.polygon.vertices;
2120                 for (v = 0; v < vertices_num; v++) {
2121                         /* get vertex */
2122                         vertex = render_item->u.polygon.vertex[v];
2123                         rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
2124                         if (rc < 0)
2125                                 break;
2126                         /* check for road extension, so we extend the road to the given end point */
2127                         if (extend_roads && vertex >= 0xf0) {
2128                                 /* previous vertex */
2129                                 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
2130                                 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
2131                                 if (rc < 0)
2132                                         break;
2133                                 /* next vertex */
2134                                 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
2135                                 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
2136                                 if (rc < 0)
2137                                         break;
2138                                 /* extend vertices to end point position
2139                                  * change x or z coordinate, whatever is greater
2140                                 */
2141                                 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
2142                                         x_prev = x_next = x_current;
2143                                 else
2144                                         z_prev = z_next = z_current;
2145                                 /* store vertices */
2146                                 x[i] = x_prev;
2147                                 y[i] = y_prev;
2148                                 z[i] = z_prev;
2149                                 /* rotate vertex */
2150                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2151                                 if (i++ == MAX_POLYGON)
2152                                         break;
2153                                 x[i] = x_next;
2154                                 y[i] = y_next;
2155                                 z[i] = z_next;
2156                                 /* rotate vertex */
2157                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2158                                 if (i++ == MAX_POLYGON)
2159                                         break;
2160                                 continue;
2161                         } else {
2162                                 /* no extension, just keep the current point as is */
2163                                 x[i] = x_current;
2164                                 y[i] = y_current;
2165                                 z[i] = z_current;
2166                                 /* rotate vertex */
2167                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2168                                 if (i++ == MAX_POLYGON)
2169                                         break;
2170                         }
2171                 }
2172                 /* render */
2173                 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2174                 break;
2175         }
2176         case RENDER_ITEM_PLANET:
2177         {
2178                 GET_ORIENTATION;
2179                 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2180                 double sun_x, sun_y, sun_z, angle_sun_h;
2181                 double loc_x, loc_y, loc_z, angle_loc_h, angle_loc_v;
2182                 double circle_x[PLANET_VERTICES], circle_y[PLANET_VERTICES], circle_z[PLANET_VERTICES];
2183                 double crescent_x[PLANET_VERTICES], crescent_y[PLANET_VERTICES], crescent_z[PLANET_VERTICES];
2184                 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
2185                 double dist, size, angle, fabs_angle, crescent;
2186                 double _sin, _cos;
2187                 int i;
2188                 int rc;
2189                 double rotate_sky = 0.0;
2190
2191 #ifdef DEBUG_ITEMS
2192                 printf("RENDER_ITEM_PLANET\n");
2193 #endif
2194                 /* get location */
2195                 rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
2196                 if (rc < 0)
2197                         break;
2198                 rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
2199                 if (rc < 0)
2200                         break;
2201                 /* get size */
2202                 size = render_item->u.planet.size;
2203                 /* rotate vertex */
2204                 if (motion_new.planet_rotation) {
2205                         if (fix_sky_rotation)
2206                                 rotate_sky = M_PI;
2207                         rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
2208                         rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
2209                 }
2210                 rotate_coordinate(roll, pitch, yaw + rotate_sky, &sun_x, &sun_y, &sun_z);
2211                 rotate_coordinate(roll, pitch, yaw + rotate_sky, &loc_x, &loc_y, &loc_z);
2212
2213                 /* distance to planet */
2214                 dist = sqrt(loc_x * loc_x + loc_y * loc_y + loc_z * loc_z);
2215
2216                 /* calculate direction of the sun */
2217                 angle_sun_h = atan2(sun_x, sun_z);
2218                 angle_loc_h = atan2(loc_x, loc_z);
2219                 angle_loc_v = atan2(loc_y, sqrt(loc_x * loc_x + loc_z * loc_z));
2220                 /* angle between planets */
2221                 angle = angle_sun_h - angle_loc_h;
2222                 if (angle > M_PI)
2223                         angle -= 2.0 * M_PI;
2224                 if (angle < -M_PI)
2225                         angle += 2.0 * M_PI;
2226                 /* absolute angle to be used as crescent */
2227                 fabs_angle = fabs(angle);
2228                 if (fabs_angle > M_PI / 2.0)
2229                         fabs_angle = M_PI - fabs_angle;
2230
2231                 /* on which side are we (sun is always bright, vertex == 0) */
2232                 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
2233                         /* get front side color */
2234                         opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2235                 } else {
2236                         /* get back side color */
2237                         opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2238                 }
2239
2240                 /* create and render cicle */
2241                 crescent = sin((1.0 - fabs_angle / (M_PI / 2)) * (M_PI / 2.0));
2242                 if (vr) {
2243                         for (i = 0; i < PLANET_VERTICES; i++) {
2244                                 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2245                                 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2246                                 circle_x[i] = _sin * planet_aspect;
2247                                 circle_y[i] = _cos;
2248                                 circle_z[i] = 0.0;
2249                                 crescent_x[i] = circle_x[i] * crescent;
2250                                 crescent_y[i] = circle_y[i];
2251                                 crescent_z[i] = circle_z[i];
2252                                 /* rotate circle and cresent towards observer (billboarding) */
2253                                 rotate_coordinate(0.0, -angle_loc_v, 0.0, &circle_x[i], &circle_y[i], &circle_z[i]);
2254                                 rotate_coordinate(0.0, 0.0, angle_loc_h, &circle_x[i], &circle_y[i], &circle_z[i]);
2255                                 rotate_coordinate(0.0, -angle_loc_v, 0.0, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2256                                 rotate_coordinate(0.0, 0.0, angle_loc_h, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2257                         }
2258                 } else {
2259                         for (i = 0; i < PLANET_VERTICES; i++) {
2260                                 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2261                                 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2262                                 circle_x[i] = _sin * planet_aspect;
2263                                 circle_y[i] = _cos;
2264                                 circle_z[i] = 0.0;
2265                                 crescent_x[i] = circle_x[i] * crescent;
2266                                 crescent_y[i] = circle_y[i];
2267                                 crescent_z[i] = circle_z[i];
2268                         }
2269                 }
2270                 for (i = 0; i < PLANET_VERTICES; i++) {
2271                         x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2272                         y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2273                         z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2274                 }
2275                 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2276
2277                 if (render_item->u.planet.vertex == 0) {
2278                         /* sun has no crescent */
2279                         break;
2280                 }
2281
2282                 /* on which side are we */
2283                 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
2284                         /* get back side color */
2285                         opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2286                 } else {
2287                         /* get front side color */
2288                         opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2289                 }
2290
2291                 /* create and render crescent */
2292                 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2293                         /* to the right */
2294                         for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2295                                 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2296                                 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2297                                 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2298                         }
2299                         _sin = sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2300                         for (; i < PLANET_VERTICES; i++) {
2301                                 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2302                                 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2303                                 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2304                         }
2305                 } else {
2306                         /* to the left */
2307                         for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2308                                 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2309                                 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2310                                 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2311                         }
2312                         for (; i < PLANET_VERTICES; i++) {
2313                                 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2314                                 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2315                                 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2316                         }
2317                 }
2318                 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2319                 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point  */
2320                 break;
2321         }
2322         case RENDER_ITEM_STARS:
2323         {
2324                 double tilt_offset = 0;
2325                 double x_offset = 0;
2326                 uint16_t color[16];
2327                 double view_width, yaw = interpolation.orientation_raw_yaw;
2328                 double pitch = interpolation.orientation_raw_pitch;
2329                 uint32_t table, table_start;
2330                 double x, y, z;
2331                 int i;
2332                 double red, green, blue;
2333                 double rotate_sky = 0.0;
2334
2335 #ifdef DEBUG_ITEMS
2336                 printf("RENDER_ITEM_STARS\n");
2337 #endif
2338                 /* use default fov of 64 to calculate z distance */
2339                 z = 160.0 / frustum_slope_64;
2340
2341                 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2342
2343                 /* get palette */
2344                 for (i = 0; i < 16; i++)
2345                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2346
2347                 if (!vr && !improve_stars) {
2348                         /* render legacy stars (as with the original game) */
2349
2350                         /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
2351                          * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
2352                          * then we half it, so we get to the center via 91
2353                          */
2354
2355                         if (render_item->u.stars.above_zenith)
2356                                 yaw = 0x200 + yaw;
2357                         yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2358                         yaw *= 2.0;
2359                         table = mercenary_star_table();
2360                         table_start = table + m68k_read_memory_16(table);
2361                         table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
2362                         yaw = yaw / (double)0x800 * 1800.0;
2363
2364                         if (render_item->u.stars.above_zenith)
2365                                 pitch = 0x200 - pitch;
2366                         pitch = fmod(pitch + 65536.0, 0x400);
2367                         pitch -= render_item->u.stars.v_offset;
2368                         pitch *= 4;
2369                         pitch = pitch * (double)0x6ccc / 65536.0;
2370
2371                         while (1) {
2372                                 x = m68k_read_memory_16(table);
2373                                 if (x >= 1800.0) {
2374                                         x_offset += 1800.0;
2375                                         table = table_start;
2376                                 }
2377                                 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2378                                 table += 2;
2379                                 if (x < 0.0)
2380                                         break;
2381                                 /* special case where we tilt the view when flying on the planet */
2382                                 if (render_item->u.stars.tilt) {
2383                                         /* use offset as given by game: 160 is half of the screen width
2384                                          * we extend the width to the actual FOV, so it fits
2385                                          */
2386                                         tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2387                                 }
2388                                 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2389                                 table += 2;
2390                                 if (render_item->u.stars.above_zenith) {
2391                                         x = (double)(view_width - 1) - x;
2392                                         y = -1 - y + 136;
2393                                 }
2394                                 /* get color */
2395                                 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2396                                 opengl_render_color(red, green, blue, debug_opacity);
2397                                 /* render point */
2398                                 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2399                         }
2400                 } else {
2401                         /* render ovr stars, render star table as a sphere */
2402
2403                         double h, v1, v2;
2404                         GET_ORIENTATION;
2405                         double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2406
2407                         if (render_item->u.stars.above_zenith)
2408                                 break;
2409
2410                         table = mercenary_star_table();
2411                         table += m68k_read_memory_16(table);
2412
2413                         while (1) {
2414                                 x = m68k_read_memory_16(table);
2415                                 if (x >= 1800.0)
2416                                         break;
2417                                 table += 2;
2418                                 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - 108.796875;
2419                                 table += 2;
2420                                 /* get color */
2421                                 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2422                                 opengl_render_color(red, green, blue, debug_opacity);
2423                                 /* render point */
2424                                 h = (900.0 - x + 160) / 900.0 * M_PI;
2425                                 v1 = (68.0 - y) / 900.0 * M_PI;
2426                                 /* wrap star field (is actually 86.2 degrees high) */
2427                                 if (v1 <= 0.0)
2428                                         v2 = v1 + (86.2 / 180.0 * M_PI);
2429                                 else
2430                                         v2 = v1 - (86.2 / 180.0 * M_PI);
2431                                 if (v1 < 0.934 && v1 > -0.934) {
2432                                         /* be sure that v1 will not exceed PI/2 */
2433                                         v1 = v1 / cos(v1); /* FIXME: there should be a better way to distribute stars equally */
2434                                         x = -sin(h) * cos(v1);
2435                                         y = sin(v1);
2436                                         z = cos(h) * cos(v1);
2437                                         if (motion_new.planet_rotation) {
2438                                                 if (fix_sky_rotation)
2439                                                         rotate_sky = M_PI;
2440                                                 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2441                                         }
2442                                         rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2443                                         opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2444                                 }
2445                                 if (v2 < 0.934 && v2 > -0.934) {
2446                                         /* be sure that v2 will not exceed PI/2 */
2447                                         v2 = v2 / cos(v2) /* FIXME: there should be a better way to distribute stars equally */;
2448                                         x = -sin(h) * cos(v2);
2449                                         y = sin(v2);
2450                                         z = cos(h) * cos(v2);
2451                                         if (motion_new.planet_rotation) {
2452                                                 if (fix_sky_rotation)
2453                                                         rotate_sky = M_PI;
2454                                                 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2455                                         }
2456                                         rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2457                                         opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2458                                 }
2459                         }
2460                 }
2461                 break;
2462         }
2463         case RENDER_ITEM_INTERSTELLAR_STARS:
2464         {
2465                 uint16_t color[16];
2466                 double z;
2467                 int i;
2468                 double red, green, blue;
2469
2470 #ifdef DEBUG_ITEMS
2471                 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2472 #endif
2473                 /* use default fov of 64 to calculate z distance */
2474                 z = 160.0 / frustum_slope_64;
2475
2476                 /* get palette */
2477                 for (i = 0; i < 16; i++)
2478                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2479
2480                 for (i = 0; i < render_item->u.interstars.count; i++) {
2481                         gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
2482                         opengl_render_color(red, green, blue, debug_opacity);
2483                         /* render point */
2484                         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);
2485                 }
2486                 break;
2487         }
2488         case RENDER_ITEM_INTERSTELLAR_SUN:
2489         {
2490                 double red, green, blue;
2491
2492 #ifdef DEBUG_ITEMS
2493                 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2494 #endif
2495                 /* white */
2496                 gamecolor2gl(&red, &green, &blue, 0x777);
2497                 opengl_render_color(red, green, blue, debug_opacity);
2498                 /* render point */
2499                 opengl_render_point(0.0, 0.0, 1000000.0, 0.0);
2500                 break;
2501         }
2502         case RENDER_ITEM_SIGHTS:
2503         {
2504                 double x[4], y[4], z[4];
2505                 double red, green, blue;
2506
2507 #ifdef DEBUG_ITEMS
2508                 printf("RENDER_ITEM_SIGHTS\n");
2509 #endif
2510                 /* use default fov of 64 to calculate z distance */
2511                 z[0] = z[1] = z[2] = z[3] = SIGHT_DIST;
2512
2513                 /* white */
2514                 gamecolor2gl(&red, &green, &blue, 0x777);
2515                 opengl_render_color(red, green, blue, debug_opacity);
2516
2517                 y[0] = y[3] = -1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2518                 y[1] = y[2] = 1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2519                 x[0] = x[1] = -16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2520                 x[2] = x[3] = -8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2521                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2522                 x[0] = x[1] = 8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2523                 x[2] = x[3] = 16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2524                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2525                 break;
2526         }
2527         case RENDER_ITEM_EXPLOSION:
2528         {
2529                 GET_ORIENTATION;
2530                 double loc_x, loc_y, loc_z, size;
2531                 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2532                 int i, e;
2533
2534 #ifdef DEBUG_ITEMS
2535                 printf("RENDER_ITEM_EXPLOSION\n");
2536 #endif
2537                 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2538
2539                 for (e = 0; e < render_item->u.explosion.count; e++) {
2540                         loc_x = render_item->u.explosion.x[e];
2541                         loc_y = render_item->u.explosion.y[e];
2542                         loc_z = render_item->u.explosion.z[e];
2543                         /* rotate vertex */
2544                         rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2545                         /* calculate size from projected size and z (256 is the distance of the game's projection plane) */
2546                         size = render_item->u.explosion.size[e] * (fabs(loc_z) / 256.0);
2547                         /* create and render cicle */
2548                         for (i = 0; i < EXPLOSION_VERTICES; i++) {
2549                                 x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * explosion_aspect;
2550                                 y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
2551                                 z[i] = loc_z;
2552                         }
2553                         opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
2554                         opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point  */
2555                 }
2556                 break;
2557         }
2558         default:
2559                 print_info("Unknown render item type, please fix!\n");
2560         }
2561 }
2562
2563 /*
2564  * interpolation
2565  */
2566
2567 static double interpolate_orientation(double old, double new, double inter)
2568 {
2569         double turn = new - old;
2570
2571         if (turn > M_PI)
2572                 turn -= 2.0 * M_PI;
2573         if (turn < -M_PI)
2574                 turn += 2.0 * M_PI;
2575
2576         /* don't interpolate, if our rotation was too fast.
2577          * e.g: taxi drive around corder, load/quit game, ...
2578          */ 
2579         if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
2580                 return new;
2581         
2582         new = old + turn * inter;
2583         
2584         if (new > M_PI)
2585                 new -= 2.0 * M_PI;
2586         if (new < -M_PI)
2587                 new += 2.0 * M_PI;
2588
2589         return new;
2590 }
2591
2592 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
2593 {
2594         int16_t turn = (new - old) & 0x3ff;
2595
2596         if (turn > 0x200)
2597                 turn -= 0x400;
2598
2599         /* don't interpolate, if our rotation was too fast.
2600          * e.g: taxi drive around corder, load/quit game, ...
2601          */ 
2602         if (turn > 0x200 / 8 || turn < -0x200 / 8)
2603                 return new;
2604
2605         /* don't do modulo 0x400, since the user of this data does it */        
2606         return (double)old + (double)turn * inter;
2607 }
2608
2609 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
2610 {
2611         double offset;
2612
2613         /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
2614         if (ground_index >= 0)
2615                 offset = wrap_int28(old - new);
2616         else
2617                 offset = (int32_t)(old - new);
2618
2619         if (limit > 0 && (offset > limit || offset < -limit))
2620                 return new;
2621
2622         return offset * (1.0 - inter);
2623 }
2624
2625 static render_item_t *interpolate_door(double inter)
2626 {
2627         static render_item_t interpolated;
2628         render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
2629         int i, ii;
2630
2631         /* find old and new vertices */
2632         while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2633                 old_vertices = old_vertices->next;
2634         while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2635                 new_vertices = new_vertices->next;
2636
2637         /* building does not exist in old or new render */
2638         if (!old_vertices || !new_vertices)
2639                 return NULL;
2640
2641         memcpy(&interpolated, new_vertices, sizeof(interpolated));
2642         ii = MAX_INTERIOR_VERTEX >> 2;
2643         for (i = 0; i < ii; i++) {
2644                 /* vertex must exist in both frames */
2645                 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2646                         continue;
2647                 /* all verices must not have be too far away */
2648                 if (fabs(old_vertices->u.vertices_interior.x[i] - new_vertices->u.vertices_interior.x[i]) > 100.0)
2649                         return NULL;
2650                 if (fabs(old_vertices->u.vertices_interior.z[i] - new_vertices->u.vertices_interior.z[i]) > 100.0)
2651                         return NULL;
2652                 /* interpolate */
2653                 interpolated.u.vertices_interior.x[i] =
2654                 (double)old_vertices->u.vertices_interior.x[i] * (1.0 - inter) +
2655                 (double)new_vertices->u.vertices_interior.x[i] * inter;
2656                 interpolated.u.vertices_interior.z[i] =
2657                 (double)old_vertices->u.vertices_interior.z[i] * (1.0 - inter) +
2658                 (double)new_vertices->u.vertices_interior.z[i] * inter;
2659         }
2660         for (i = 0; i < 4; i++) {
2661                 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
2662                         return NULL;
2663         }
2664
2665         return &interpolated;
2666 }
2667
2668 /* make a list of objects that moved and store their displacement */
2669 static void interpolate_objects(double inter)
2670 {
2671         render_item_t *old_info, *new_info;
2672         int count;
2673
2674         /* hunt for objects that exist in both (old and new) lists and moved */
2675         count = 0;
2676         for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2677                 /* not an object */
2678                 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
2679                         continue;
2680                 /* not moving */
2681                 if (!new_info->u.info.moving)
2682                         continue;
2683                 /* interiors don't move */
2684                 if (new_info->u.info.id < 0)
2685                         continue;
2686                 /* check matching object with same ID */
2687                 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2688                         /* not an object */
2689                         if (old_info->type != RENDER_ITEM_OBJECT_INFO)
2690                                 continue;
2691                         /* not moving */
2692                         if (!old_info->u.info.moving)
2693                                 continue;
2694                         /* same id */
2695                         if (old_info->u.info.id == new_info->u.info.id)
2696                                 break;
2697                 }
2698                 /* no matching object found */
2699                 if (!old_info)
2700                         continue;
2701                 /* not moving */
2702                 if (old_info->u.info.east == new_info->u.info.east
2703                  && old_info->u.info.height == new_info->u.info.height
2704                  && old_info->u.info.north == new_info->u.info.north)
2705                         continue;
2706                 /* interpolate and store */
2707                 interpolation.object_id[count] = new_info->u.info.id;
2708                 interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
2709                 interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
2710                 interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
2711                 if (count++ == MAX_MOVING_OBJECTS)
2712                         break;
2713         }
2714         interpolation.object_count = count;
2715 }
2716
2717 /* make a vertex list of interpolated planets */
2718 static render_item_t *interpolate_planets(double inter)
2719 {
2720         static render_item_t interpolated;
2721         render_item_t *old_info, *new_info;
2722         render_item_t *old_vertices = NULL, *new_vertices = NULL;
2723         int i;
2724
2725         /* get vertices for planets/comet */
2726         for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2727                 if (old_info->type == RENDER_ITEM_VERTICES_0)
2728                         old_vertices = old_info;
2729                 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2730                 if (old_info->type == RENDER_ITEM_COMET_POLYGON)
2731                         break;
2732         }
2733         for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2734                 if (new_info->type == RENDER_ITEM_VERTICES_0)
2735                         new_vertices = new_info;
2736                 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2737                 if (new_info->type == RENDER_ITEM_COMET_POLYGON)
2738                         break;
2739         }
2740
2741         /* check for existing planet's vertices and if planets are rendered in both lists (old and new) */
2742         if (old_info == NULL || new_info == NULL || old_vertices == NULL || new_vertices == NULL)
2743                 return NULL;
2744
2745         /* interpolate vertices */
2746         for (i = 0; i < (MAX_VERTEX >> 2); i++) {
2747                 interpolated.u.vertices.x[i] = old_vertices->u.vertices.x[i] * (1.0 - inter) + new_vertices->u.vertices.x[i] * inter;
2748                 interpolated.u.vertices.y[i] = old_vertices->u.vertices.y[i] * (1.0 - inter) + new_vertices->u.vertices.y[i] * inter;
2749                 interpolated.u.vertices.z[i] = old_vertices->u.vertices.z[i] * (1.0 - inter) + new_vertices->u.vertices.z[i] * inter;
2750         }
2751
2752         return &interpolated;
2753 }
2754
2755 /* always renders NEW! items
2756  * use inter == 1.0 to render motion to vertices of NEW items
2757  * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
2758  * return 0, if the scene was rendered, returns < 0, if there is no scene
2759  */
2760 int render_all_items(double inter, int vr)
2761 {
2762         render_item_object_info = NULL;
2763         render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2764         render_item_vertices_interior = NULL;
2765         render_item_vertices_planets = NULL;
2766
2767         /* no interpolation when leaving or entering planet to/from space */
2768         if ((last_ground_index < 0 && ground_index >= 0)
2769          || (last_ground_index >= 0 && ground_index < 0)) {
2770                 inter = 1.0;
2771         }
2772
2773         /* reset interpolation */
2774         memset(&interpolation, 0, sizeof(interpolation));
2775         interpolation.orientation_roll = motion_new.orientation_roll;
2776         interpolation.orientation_pitch = motion_new.orientation_pitch;
2777         interpolation.orientation_yaw = motion_new.orientation_yaw;
2778         interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
2779         interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
2780         interpolation.planet_inclination = motion_new.planet_inclination;
2781         interpolation.planet_azimuth = motion_new.planet_azimuth;
2782 //printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
2783
2784         /* do interpolation */
2785         if (inter != 1.0 && render_list_old) {
2786                 /* interpolate orientation */
2787                 interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
2788                 interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
2789                 interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
2790                 interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
2791                 interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
2792                 interpolation.planet_inclination = interpolate_orientation(motion_old.planet_inclination, motion_new.planet_inclination, inter);
2793                 interpolation.planet_azimuth = interpolate_orientation(motion_old.planet_azimuth, motion_new.planet_azimuth, inter);
2794
2795                 /* interpolate position */
2796                 interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
2797                 interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
2798                 interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
2799                 /* prevent glitch when using elevators: a sudden vertical move is ignored
2800                  * this is not the best solution, because fast vertical flying (from 0) will also be detected */
2801                 if (old_height_offset == 0
2802                  && (new_height_offset >= 150 || new_height_offset <= -150)) {
2803                         interpolation.offset_east = 0.0;
2804                         interpolation.offset_height = 0.0;
2805                         interpolation.offset_north = 0.0;
2806                 }
2807
2808                 /* interpolate doors of building (if any) */
2809                 interpolation.interior = interpolate_door(inter);
2810
2811                 /* interpolate objects */
2812                 interpolate_objects(inter);
2813
2814                 /* interpolate planets */
2815                 interpolation.planets = interpolate_planets(inter);
2816         }
2817
2818         /* return failure, if nothing can be rendered */
2819         if (!render_list_new)
2820                 return -1;
2821
2822         for (render_item = render_list_new; render_item; render_item = render_item->next) {
2823                 render_one_item(render_item, vr);
2824         }
2825
2826         return 0;
2827 }
2828
2829 int render_all_white(int vr)
2830 {
2831         render_item_t sky_item;
2832
2833         memset(&sky_item, 0, sizeof(sky_item));
2834         sky_item.type = RENDER_ITEM_SKY;
2835
2836         /* set color */
2837         sky_item.u.ground.red = 1.0;
2838         sky_item.u.ground.green = 1.0;
2839         sky_item.u.ground.blue = 1.0;
2840
2841         render_one_item(&sky_item, vr);
2842
2843         return 0;
2844 }
2845
2846 void render_capture_reset(void)
2847 {
2848         /* flush old list, if exists */
2849         flush_old_items();
2850         /* flush new list, if exists */
2851         render_list_old = render_list_new;
2852         flush_old_items();
2853         /* reset list pointers */
2854         render_list_old = NULL;
2855         render_list_new = NULL;
2856         render_list_end = &render_list_new;
2857         render_item = NULL;
2858 }
2859
2860 int render_capture_is_interstellar(void)
2861 {
2862         if (!render_list_new)
2863                 return 0;
2864         for (render_item = render_list_new; render_item; render_item = render_item->next) {
2865                 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)
2866                         return 1;
2867         }
2868
2869         return 0;
2870 }
2871