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