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