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