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