Fix interpolation of objects
[mercenary-reloaded.git] / src / mercenary / render.c
index 2bd8f76..f672eac 100644 (file)
@@ -1,4 +1,4 @@
-/* render routines that replaces the game rendering with modern rendering
+/* render routines that replaces the game rendering by OpenGL rendering
  *
  * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
  * All Rights Reserved
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+/* How it works:
+ *
+ * 1. Each game's rendering is capured:
+ *    a: call to render_capture_start()
+ *    b: several calls to render_capture_event() to capture all data
+ *    c: call to render_capture_stop()
+ * 2. The captured motion is then interpolated to get smooth motion:
+ *    - new_motion for motion of current/recent capture
+ *    - old_motion for motion of previous capture
+ *    - interpolation for interpolated result
+ * 3. The complete scene is rendered:
+ *    - render_all_items() calls the render_item() for each item
+ *    - The recent capture (NEW) is rendered
+ *    - Interpolation result is taken into account
+ */
+
 #include <stdio.h>
 #include <stdint.h>
 #include <stdlib.h>
+#include <string.h>
 #include <math.h>
+#include <GL/glew.h>
+#include "../libsdl/print.h"
 #include "../libcpu/m68k.h"
+#include "../libcpu/m68kcpu.h"
 #include "../libcpu/execute.h"
+#include "../libsdl/opengl.h"
 #include "mercenary.h"
 
-#define OBJECT_COORD_MAX 256
-static int object_coord_valid; /* set, if the coordinates below are valid */
-static int object_coord_num;
-static int object_coord_x[OBJECT_COORD_MAX];
-static int object_coord_y[OBJECT_COORD_MAX];
-static int object_coord_z[OBJECT_COORD_MAX];
+//#define DEBUG_COLOR
+//#define DEBUG_VERTEX
+//#define DEBUG_ITEMS
+
+#define MAX_POLYGON            16      /* number of polygon complexity (vertices) */
+#define MAX_VERTEX             0x100   /* this is the value range, these are 64 vertices */
+#define MAX_INTERIOR_VERTEX    0x400   /* do we need that much? */
+#define MAX_INTERSTARS         80      /* always 80 stars */
+#define MAX_MOVING_OBJECTS     16      /* maximum number of moving objects (used for interpolation) */
+#define MAX_EXPLOSION          256     /* how many explosion particles can be stored in one object */
+#define PLANET_VERTICES                128
+#define PLANET_ELIPSE          1.17
+#define EXPLOSION_VERTICES     16
+#define EXPLOSION_ELIPSE       1.17
+
+/*
+ *  render item definition and structures
+ */
+
+/* render items */
+enum render_item_type {
+       RENDER_ITEM_OBJECT_INFO,
+       RENDER_ITEM_VERTICES_0,
+       RENDER_ITEM_VERTICES_1,
+       RENDER_ITEM_VERTICES_2,
+       RENDER_ITEM_VERTICES_INTERIOR,
+       RENDER_ITEM_SKY,
+       RENDER_ITEM_GROUND,
+       RENDER_ITEM_OBJECT_POLYGON,
+       RENDER_ITEM_OBJECT_LINE,
+       RENDER_ITEM_BEACON_POINT,
+       RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
+       RENDER_ITEM_BUILDING_EXTERIOR_LINE,
+       RENDER_ITEM_BUILDING_INTERIOR_1TO4,
+       RENDER_ITEM_BUILDING_INTERIOR_5TO6,
+       RENDER_ITEM_BUILDING_INTERIOR_WALL,
+       RENDER_ITEM_COMET_POLYGON,
+       RENDER_ITEM_ROAD_LINE,
+       RENDER_ITEM_ROAD_POLYGON,
+       RENDER_ITEM_TAG_LINE_OBJECT,
+       RENDER_ITEM_TAG_LINE_OTHER,
+       RENDER_ITEM_TAG_POLYGON_OBJECT,
+       RENDER_ITEM_TAG_POLYGON_OTHER,
+       RENDER_ITEM_PLANET,
+       RENDER_ITEM_STARS,
+       RENDER_ITEM_INTERSTELLAR_STARS,
+       RENDER_ITEM_INTERSTELLAR_SUN,
+       RENDER_ITEM_ISLAND_POLYGON,
+       RENDER_ITEM_SIGHTS,
+       RENDER_ITEM_EXPLOSION,
+};
+
+struct render_item_info {
+       int moving;
+       int id;
+       int32_t east, height, north;
+};
+
+struct render_item_vertices {
+       double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
+};
+
+struct render_item_vertices_interior {
+       uint8_t set[MAX_INTERIOR_VERTEX >> 2];
+       double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
+};
+
+struct render_item_sky {
+       double red, green, blue;
+};
+
+struct render_item_ground {
+       double red, green, blue;
+};
+
+struct render_item_polygon {
+       double red, green, blue;
+       int vertices;
+       int vertex[MAX_POLYGON];
+};
+
+struct render_item_interior14 {
+       double red, green, blue;
+       int level;
+       int vertex[4];
+};
+
+struct render_item_interior56 {
+       double red, green, blue;
+       int level12;
+       int level34;
+       int vertex14;
+       int vertex23;
+};
+
+struct render_item_line {
+       double red, green, blue;
+       int vertex[2];
+};
+
+struct render_item_point {
+       double red, green, blue;
+       int vertex;
+};
+
+struct render_item_planet {
+       double front_red, front_green, front_blue;
+       double back_red, back_green, back_blue;
+       int vertex;
+       double size;
+};
+
+struct render_item_stars {
+       int16_t v_offset;
+       int tilt;
+       int32_t tilt_value;
+       int above_zenith;
+};
+
+struct render_item_interstars {
+       uint8_t color[MAX_INTERSTARS];
+       int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
+       int     count;
+};
+
+struct render_item_explosion {
+       double red, green, blue;
+       int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
+       int count;
+};
+
+typedef struct render_item {
+       struct render_item *next;
+       enum render_item_type type;
+       union {
+               struct render_item_info                 info;
+               struct render_item_vertices             vertices;
+               struct render_item_vertices_interior    vertices_interior;
+               struct render_item_sky                  sky;
+               struct render_item_ground               ground;
+               struct render_item_polygon              polygon;
+               struct render_item_line                 line;
+               struct render_item_point                point;
+               struct render_item_interior14           interior14;
+               struct render_item_interior56           interior56;
+               struct render_item_planet               planet;
+               struct render_item_stars                stars;
+               struct render_item_interstars           interstars;
+               struct render_item_explosion            explosion;
+       } u;
+} render_item_t;
+
+/* information about motion in each game rendering */
+typedef struct motion {
+       int32_t position_east, position_height, position_north;
+       double orientation_roll, orientation_pitch, orientation_yaw;
+       uint16_t orientation_raw_yaw;
+       int16_t orientation_raw_pitch;
+       int planet_rotation;
+       double planet_inclination, planet_azimuth;
+} motion_t;
+
+/* information about interpolation between two game renedrings */
+typedef struct interpolation {
+       double offset_east, offset_height, offset_north;
+       double orientation_roll, orientation_pitch, orientation_yaw;
+       double orientation_raw_yaw, orientation_raw_pitch;
+       double planet_inclination, planet_azimuth;
+       int object_id[MAX_MOVING_OBJECTS];
+       double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
+       int object_count;
+       render_item_t *interior;
+       render_item_t *planets;
+} interpolation_t;
+
+#define GET_ORIENTATION \
+       double roll = interpolation.orientation_roll; \
+       double pitch = interpolation.orientation_pitch; \
+       double yaw = interpolation.orientation_yaw
+
+#define GET_ORIENTATION_FIX \
+       roll = motion_new.orientation_roll; \
+       pitch = motion_new.orientation_pitch; \
+       yaw = motion_new.orientation_yaw
+
+/* rendering options */
+static int extend_roads; /* extend roads in its original width, rather than just using a single point */
+static double fov;
+static double debug_opacity;
+static double frustum_slope_64, frustum_slope_fov;
+
+/* states while collecting render items */
+static motion_t motion_old, motion_new;
+static int32_t old_height_offset = 0, new_height_offset = 0;
+static interpolation_t interpolation;
+static int ground_index, last_ground_index = -1;
+static int interior_level12 = 0;
+static int interior_level34 = 0;
+static int tag_is_object;
+/* current render item list */
+static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
+/* previous render item list */
+static render_item_t *render_list_old = NULL;
+/* current item to be processed */
+static render_item_t *render_item;
+/* current object info */
+static render_item_t *render_item_object_info;
+/* current vertices */
+static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
+static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
+
+/*
+ * capturing
+ */
+
+static void render_item_add(enum render_item_type type)
+{
+       render_item = calloc(1, sizeof(render_item_t));
+       if (!render_item) {
+               print_error("No memory, must abort!\n");
+               abort();
+       }
+       render_item->type = type;
+       *render_list_end = render_item;
+       render_list_end = &render_item->next;
+}
+
+static void flush_old_items(void)
+{
+       /* flush old render list */
+       while (render_list_old) {
+               render_item = render_list_old;
+               render_list_old = render_list_old->next;
+               free(render_item);
+       }
+}
 
 /* rendering starts, initialize variables */
-void render_start(void)
+void render_capture_start(double _fov, int _extend_roads, int debug)
+{
+#if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
+       printf("start rendering a new frame...\n");
+#endif
+
+       flush_old_items();
+       render_item = NULL;
+       /* move new render list to old render list */
+       render_list_old = render_list_new;
+       /* setup new render list */
+       render_list_new = NULL;
+       render_list_end = &render_list_new;
+
+       /* move new motion to old motion */
+       memcpy(&motion_old, &motion_new, sizeof(motion_old));
+
+       /* set rendering options */
+       fov = _fov;
+       extend_roads = _extend_roads;
+       /* set some transpareny, if debugging is enabled */
+       debug_opacity = (debug) ? 0.5 : 1.0;
+
+       /* calculate slope of 64 degree frustum and current FOV's frustum */    
+       frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
+       frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
+
+       /* init motion */
+       mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
+       /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
+       mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
+       mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
+       motion_new.planet_rotation = 0;
+       mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth);
+
+       render_item_object_info = NULL;
+       render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
+       render_item_vertices_planets = NULL;
+       render_item_vertices_interior = NULL;
+
+       /* detect elevator movement */
+       old_height_offset = new_height_offset;
+       if (render_list_old)
+               new_height_offset = motion_new.position_height - motion_old.position_height;
+
+       /* detect switching between space (-1) and over ground (>=0) */
+       last_ground_index = ground_index;
+
+       /* init tag type */
+       tag_is_object = 0;
+}
+
+void render_capture_stop(void)
 {
-       object_coord_valid = 0;
+       /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
+       if (!render_list_new) {
+               render_list_new = render_list_old;
+               render_list_end = &render_list_new;
+               render_list_old = NULL;
+       }
+
 }
 
-/* parse object's coordinates, rotate them and store them */
-static void parse_object(void)
+static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
 {
-#if 0
-#warning tbd: handling in 540D2
-       int16_t r;
-       double roll, pitch, yaw;
-       uint32_t address;
-       int16_t word_x, word_y, word_z;
-       double  x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
+       uint32_t palette;
+       uint16_t color;
 
-       if (object_coord_valid) {
-               fprintf(stderr, "Coodinates are valid, because previous object did not render, please fix!\n");
-               return;
+       /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
+       index <<= 1;
+       palette = mercenary_palette_render();
+       color = m68k_read_memory_16(palette + index);
+#ifdef DEBUG_COLOR
+       printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
+#endif
+       if (color >= 0x8000) {
+#ifdef DEBUG_COLOR
+               fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
+#endif
        }
+       *red = (double)((color >> 8) & 0xf) / 15.0;
+       *green = (double)((color >> 4) & 0xf) / 15.0;
+       *blue = (double)(color & 0xf) / 15.0;
+}
 
-       /* get observer's tilt, pitch, yaw */
-       r = (int16_t)(m68k_read_memory_16(0x530c+0x1E46) & 0x1ff);
-       roll = (double)r / 512.0 * 2 * M_PI;
-       r = (int16_t)((m68k_read_memory_16(0x530c+0x1E48) + 0x200) & 0x1ff);
-       pitch = (double)r / 512.0 * 2 * M_PI;
-       r = (int16_t)((m68k_read_memory_16(0x530c+0x1E4a) + 0x200) & 0x1ff);
-       yaw = (double)r / 512.0 * 2 * M_PI;
-
-       /* get address that points to object vertices */
-       address = mercenary_object_vertex_register;
-
-       /* parse object, see M3 code at 0x540a6 */
-word_x = (int8_t)0xff;
-printf("testing %x, %d (should be extended to -1 as a word)\n", word_x, word_x);
-word_x = (int8_t)0xf1;
-printf("testing %x, %d (should be extended to -15 as a word)\n", word_x, word_x);
-word_x = (int8_t)0x80;
-printf("check value: %x (should be 0x80)\n", (uint8_t)word_x);
-exit(0);
-tbd: wie werden die koordinaten mit der objektposition translatiert?:
-       object_coord_num = 0;
-       while(42) {
-               word_x = (int8_t)m68k_read_memory_8(address);
-               address += 1;
-               /* check for 8 bit or 16 bit coordinate using this magic */
-               if ((uint8_t)word_x != 0x80) {
-                       /* we have an 8 bit coordinate */
-                       word_y = (int8_t)m68k_read_memory_8(address);
-                       address += 1;
-                       word_z = (int8_t)m68k_read_memory_8(address);
-                       address += 1;
-               } else {
-                       /* we have an 16 bit coordinate, make address word align */
-                       if ((address & 1))
-                               address++;
-                       word_x = (int16_t)m68k_read_memory_16(address);
-                       address += 2;
-                       /* done if we get this magic */
-                       if ((uint16_t)word_x == 0x8000)
-                               break;
-                       word_y = (int16_t)m68k_read_memory_16(address);
-                       address += 2;
-                       word_z = (int16_t)m68k_read_memory_16(address);
-                       address += 2;
-               }
+static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
+{
+       uint16_t index;
+       uint32_t palette;
+       int nesting = 0;
 
-               /* check if too many coordinates */
-               if (object_coord_num == OBJECT_COORD_MAX) {
-                       fprintf(stderr, "object has too many coordinates, please fix!\n");
+#ifdef DEBUG_COLOR
+       printf("color is given as 0x%04x\n", color);
+#endif
+again:
+       /* color conversion: see for example M3: 0x4f830 */
+       if (color < 0x8000) {
+               /* use given color but shift it left by 1 */
+               color = color << 1;
+#ifdef DEBUG_COLOR
+               printf("using given color, color is now 0x%04x\n", color);
+#endif
+       } else if ((color & 0xff) < 0x80) {
+               gamecolor2gl_index(red, green, blue, color & 0xf);
+               return;
+       } else {
+               /* use given index from pre-defined palette */
+               index = color & 0x7e;
+               palette = mercenary_palette_predefined();
+               color = m68k_read_memory_16(palette + index);
+#ifdef DEBUG_COLOR
+               printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
+#endif
+               /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
+               if (nesting++ == 8) {
+                       print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
                        return;
                }
+               goto again;
+       }
+       *red = (double)((color >> 8) & 0xf) / 15.0;
+       *green = (double)((color >> 4) & 0xf) / 15.0;
+       *blue = (double)(color & 0xf) / 15.0;
+}
 
-               /* convert to double */
-               x1 = (double)word_x;
-               y1 = (double)word_y;
-               z1 = (double)word_z;
-
-               /* rotate roll (tilt head to the right) */
-               x2 = x1 * cos(roll) - y1 * sin(roll);
-               y2 = x1 * sin(roll) + y1 * cos(roll);
-               z2 = z1;
+static int32_t wrap_int28(int32_t value)
+{
+       value <<= 4;
+       value >>= 4;
+       return value;
+}
 
-               /* rotate head (pitch down) */
-               y3 = y2 * cos(pitch) - z2 * sin(pitch);
-               z3 = y2 * sin(pitch) + z2 * cos(pitch);
-               x3 = x2;
+static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
+{
+       if ((vertex & 3)) {
+               print_info("Vertex %d is not a multiple of four!\n", vertex);
+               return;
+       }
+       /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
+       if (vertex < 0x100) {
+               if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
+                       render_item_add(RENDER_ITEM_VERTICES_0);
+                       /* copy vertices that have been captured already */
+                       if (render_item_vertices_0)
+                               memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
+                       render_item_vertices_0 = render_item;
+               }
+       } else
+       if (vertex < 0x200) {
+               if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
+                       render_item_add(RENDER_ITEM_VERTICES_1);
+                       /* copy vertices that have been captured already */
+                       if (render_item_vertices_1)
+                               memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
+                       render_item_vertices_1 = render_item;
+               }
+               vertex -= 0x100;
+       } else
+       if (vertex < 0x300) {
+               if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
+                       render_item_add(RENDER_ITEM_VERTICES_2);
+                       /* copy vertices that have been captured already */
+                       if (render_item_vertices_2)
+                               memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
+                       render_item_vertices_2 = render_item;
+               }
+               vertex -= 0x200;
+       } else {
+               print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
+               return;
+       }
+       vertex >>= 2;
+#ifdef DEBUG_VERTEX
+       printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
+#endif
+       /* use absolute position */
+       x += motion_new.position_east;
+       y += motion_new.position_height;
+       z += motion_new.position_north;
+       render_item->u.vertices.x[vertex] = x;
+       render_item->u.vertices.y[vertex] = y;
+       render_item->u.vertices.z[vertex] = z;
+}
 
-               /* rotate yaw (turn right) */
-               z4 = z3 * cos(yaw) - x3 * sin(yaw);
-               x4 = z3 * sin(yaw) + x3 * cos(yaw);
-               y4 = y3;
+static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
+{
+       if ((vertex & 3)) {
+               print_info("Vertex %d is not a multiple of four!\n", vertex);
+               return;
+       }
+       /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
+       if (vertex >= MAX_VERTEX) {
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
+               return;
+       }
+       if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
+               render_item_add(RENDER_ITEM_VERTICES_0);
+               /* copy vertices that have been captured already */
+               if (render_item_vertices_0)
+                       memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
+               render_item_vertices_0 = render_item;
+       }
+       vertex >>= 2;
+#ifdef DEBUG_VERTEX
+       printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
+#endif
+       render_item->u.vertices.x[vertex] = x;
+       render_item->u.vertices.y[vertex] = y;
+       render_item->u.vertices.z[vertex] = z;
+}
 
-               /* store vertices as float */
-               object_coord_x[object_coord_num] = x4;
-               object_coord_y[object_coord_num] = y4;
-               object_coord_z[object_coord_num] = z4;
+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)
+{
+       if ((vertex & 3)) {
+               print_info("Vertex is not a multiple of four!\n");
+               return;
+       }
+       if (vertex >= MAX_INTERIOR_VERTEX) {
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
+               return;
        }
+       if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
+               render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
+       vertex >>= 2;
+#ifdef DEBUG_VERTEX
+       printf("storing %s coordinates: vertex=%d, x=%d, y=%d;%d;%d;%d, z=%d\n", what, vertex, x, y1, y2, y3, y4, z);
+#endif
+       /* use absolute position */
+       x += motion_new.position_east;
+       y1 += motion_new.position_height;
+       y2 += motion_new.position_height;
+       y3 += motion_new.position_height;
+       y4 += motion_new.position_height;
+       z += motion_new.position_north;
+       render_item->u.vertices_interior.x[vertex] = (double)x;
+       render_item->u.vertices_interior.y[0] = (double)y1;
+       render_item->u.vertices_interior.y[1] = (double)y2;
+       render_item->u.vertices_interior.y[2] = (double)y3;
+       render_item->u.vertices_interior.y[3] = (double)y4;
+       render_item->u.vertices_interior.z[vertex] = (double)z;
+       render_item->u.vertices_interior.set[vertex] = 1;
+}
+
+static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
+{
+       double out_x, out_y, out_z;
 
-       /* we are done, coordinates are valid */
-       object_coord_valid = 1;
+       /* rotate yaw (German: Gier, turn view to the right) */
+       out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
+       out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
+       *z = out_z;
+       *x = out_x;
+       /* rotate pitch (German: Nick, turn head down) */
+       out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
+       out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
+       *y = out_y;
+       *z = out_z;
+       if (roll == 0.0)
+               return;
+       /* rotate roll (tilt head to the right) */
+       out_x = (*x) * cos(roll) - (*y) * sin(roll);
+       out_y = (*x) * sin(roll) + (*y) * cos(roll);
+       *x = out_x;
+       *y = out_y;
+}
+
+/* clear screen color (sky / universe) */
+static void clear_screen(int index)
+{
+#ifdef DEBUG_VERTEX
+       printf("clear screen:\n");
 #endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_SKY);
+
+       /* set color */
+       gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
+
+       /* store for later use after planets have been rendered */
+       ground_index = index;
 }
 
-void render_polygons(void)
+/* ground color */
+static void draw_ground(void)
 {
-#if 0
-#warning beim polygon auf object_coord_num checken
-       if (!object_coord_valid) {
-               print failure, if coords not valid!!
+       /* no ground in space :) */
+       if (ground_index < 0)
                return;
+
+#ifdef DEBUG_VERTEX
+       printf("add ground plane:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_GROUND);
+
+       /* set color */
+       gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
+}
+
+/* object info */
+static void info_object(int moving)
+{
+#ifdef DEBUG_VERTEX
+       printf("add object's info:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_OBJECT_INFO);
+
+       /* add info */
+       render_item->u.info.moving = moving;
+       if (moving)
+               mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
+}
+
+/* coordinates ready for an object */
+static void coord_object(void)
+{
+       int32_t x, y, z;
+
+       x = (int16_t)REG_D[3];
+       x += (int32_t)REG_A[1];
+       y = (int16_t)REG_D[4];
+       y += (int32_t)REG_A[2];
+       z = (int16_t)REG_D[5];
+       z += (int32_t)REG_A[3];
+       store_coord("object", REG_A[0], x, y, z);
+}
+
+/* polygon of object */
+static void poly_object(int mercenary)
+{
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add object's polygon:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_OBJECT_POLYGON);
+
+       /* set color */
+       if (mercenary == 3)
+               gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
+       else {
+               uint16_t color;
+               color = m68k_read_memory_8(vertex_address++) << 8;
+               color |= m68k_read_memory_8(vertex_address++);
+               gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
+       }
+
+       /* the vertex list is zero-terminated */
+       for (i = 0; i < MAX_POLYGON; i++) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               render_item->u.polygon.vertex[i] = vertex;
+       }
+       render_item->u.polygon.vertices = i;
+}
+
+/* line of object */
+static void line_object(void)
+{
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+
+#ifdef DEBUG_VERTEX
+       printf("add object's line:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_OBJECT_LINE);
+
+       /* set color */
+       gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
+
+       /* two vertices */
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[0] = vertex;
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[1] = vertex;
+}
+
+/* coordinates ready for a beacon */
+static void coord_beacon(void)
+{
+       int32_t x, y, z;
+
+       /* only 28 bits seem to be a correct signed int value */
+       x = (int32_t)(REG_D[3] << 4) / 16;
+       y = (int32_t)(REG_D[4] << 4) / 16;
+       z = (int32_t)(REG_D[5] << 4) / 16;
+       store_coord("beacon", 0, x, y, z);
+}
+
+/* point of beacon */
+static void point_beacon(void)
+{
+#ifdef DEBUG_VERTEX
+       printf("add beacon's point:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BEACON_POINT);
+
+       /* set color */
+       gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
+
+       /* one vertex */
+       render_item->u.point.vertex = 0;
+}
+
+/* coordinates ready for a building (exterior) */
+static void coord_building_exterior(void)
+{
+       int32_t x, y, z;
+
+       x = (int32_t)REG_D[3];
+       y = (int32_t)REG_D[4];
+       z = (int32_t)REG_D[5];
+       store_coord("building exterior", REG_A[0], x, y, z);
+}
+
+/* polygon of building (exterior) */
+static void poly_building_exterior(void)
+{
+       uint16_t color;
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add building's polygon:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
+
+       /* set color */
+       color = m68k_read_memory_8(vertex_address++) << 8;
+       color |= m68k_read_memory_8(vertex_address++);
+       gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
+
+       /* the vertex list is zero-terminated */
+       for (i = 0; i < MAX_POLYGON; i++) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               render_item->u.polygon.vertex[i] = vertex | 0x100;
+       }
+       render_item->u.polygon.vertices = i;
+}
+
+/* line of building (exterior) */
+static void line_building_exterior(void)
+{
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+
+#ifdef DEBUG_VERTEX
+       printf("add building's line:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
+
+       /* set color */
+       gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
+
+       /* two vertices */
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[0] = vertex | 0x100;
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[1] = vertex | 0x100;
+}
+
+/* coordinates ready for a building (interior) */
+static void coord_building_interior(void)
+{
+       int16_t east, north;
+       int32_t height1, height2, height3, height4;
+
+       mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
+       store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
+}
+
+/* polygon of building (interior) */
+static void poly_building_interior1to4(int level)
+{
+       uint16_t color;
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add roof/floor's polygon at level %d:\n", level);
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
+
+       /* set color */
+       color = m68k_read_memory_8(REG_A[0]) << 8;
+       color |= m68k_read_memory_8(REG_A[0] + 1);
+       gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
+
+       /* four vertices, one level */
+       for (i = 0; i < 4; i++) {
+               vertex = REG_A[(2 + i)];
+               render_item->u.interior14.vertex[i] = vertex;
        }
+       render_item->u.interior14.level = level;
+}
 
+/* polygon of building (interior) */
+static void poly_building_interior5to6(int level12, int level34)
+{
+       uint16_t color;
+
+#ifdef DEBUG_VERTEX
+       printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
+#endif
 
-       render..
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
 
+       /* set color */
+       color = m68k_read_memory_8(REG_A[0]) << 8;
+       color |= m68k_read_memory_8(REG_A[0] + 1);
+       gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
 
+       /* two vertices, two levels */
+       render_item->u.interior56.vertex14 = REG_A[2];
+       render_item->u.interior56.vertex23 = REG_A[3];
+       render_item->u.interior56.level12 = level12;
+       render_item->u.interior56.level34 = level34;
+}
 
-       /* done with rendering, mark coordinates as beeing invalid */
-       object_coord_valid = 0;
+/* wall part of a building */
+static void wall_building(void)
+{
+#ifdef DEBUG_VERTEX
+       printf("add wall:\n");
 #endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
+
+       /* set color */
+       gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
+
+       /* two vertices, two levels */
+       render_item->u.interior56.vertex14 = REG_A[1];
+       render_item->u.interior56.vertex23 = REG_A[2];
+       /* get top level according to bit 12 in D3 */
+       render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
+       render_item->u.interior56.level34 = 1;
 }
 
-/* stop event from CPU received */
-void render_improved_event(int event)
+/* coordinates ready for comet tail */
+static void coord_comet(void)
 {
-       switch (event) {
-       case STOP_AT_PARSE_OBJECT:
-               parse_object();
-               break;
-       case STOP_AT_RENDER_POLYGONS:
-               render_polygons();
-               break;
+       int32_t x, y, z;
+
+       x = (int32_t)REG_D[3];
+       y = (int32_t)REG_D[4];
+       z = (int32_t)REG_D[5];
+       store_planets_coord("comet tail", REG_A[0], x, y, z);
+}
+
+/* polygon of comet tail */
+static void poly_comet(void)
+{
+       uint16_t color;
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add comet's polygon:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_COMET_POLYGON);
+
+       /* set color */
+       color = m68k_read_memory_8(vertex_address++) << 8;
+       color |= m68k_read_memory_8(vertex_address++);
+       gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
+
+       /* the vertex list is zero-terminated */
+       for (i = 0; i < MAX_POLYGON; i++) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               render_item->u.polygon.vertex[i] = vertex;
+       }
+       render_item->u.polygon.vertices = i;
+}
+
+/* coordinates ready for lines of a road / ground surface */
+static void coord_line_road(void)
+{
+       int32_t x, y, z;
+
+       x = REG_D[3];
+       y = -motion_new.position_height;
+       z = REG_D[5];
+       store_coord("road", REG_A[0], x, y, z);
+}
+
+/* line of road */
+static void line_road(void)
+{
+       uint32_t vertex;
+
+#ifdef DEBUG_VERTEX
+       printf("add road's line:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_ROAD_LINE);
+
+       /* set color */
+       gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
+
+       /* two vertices */
+       vertex = REG_A[1];
+       render_item->u.line.vertex[0] = vertex;
+       vertex = REG_A[2];
+       render_item->u.line.vertex[1] = vertex;
+}
+
+/* coordinates ready for polygons of a road / ground surface */
+static void coord_poly_road(void)
+{
+       int32_t x, y, z;
+
+       x = m68k_read_memory_32(320 + REG_A[0]);
+       x -= REG_A[1];
+       /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
+       y = -motion_new.position_height;
+       z = m68k_read_memory_32(576 + REG_A[0]);
+       z -= REG_A[3];
+       store_coord("road/place", REG_A[0], x, y, z);
+}
+
+/* polygon of road */
+static void poly_road()
+{
+       uint16_t color;
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add road/place's polygon:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_ROAD_POLYGON);
+
+       /* set color */
+       color = m68k_read_memory_8(vertex_address++) << 8;
+       color |= m68k_read_memory_8(vertex_address++);
+       gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
+
+       /* the vertex list is zero-terminated */
+       for (i = 0; i < MAX_POLYGON; i++) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               render_item->u.polygon.vertex[i] = vertex;
+       }
+       render_item->u.polygon.vertices = i;
+}
+
+/* coordinates ready for tags */
+static void coord_tags(void)
+{
+       int32_t x, y, z;
+
+       x = (int16_t)REG_D[3];
+       x += (int32_t)REG_A[1];
+       y = (int16_t)REG_D[4];
+       y += (int32_t)REG_A[2];
+       z = (int16_t)REG_D[5];
+       z += (int32_t)REG_A[3];
+       store_coord("tags", REG_A[0], x, y, z);
+}
+
+/* coordinates ready for large tags */
+static void coord_tags2(void)
+{
+       int32_t x, y, z;
+
+       x = (int16_t)REG_D[3];
+       x += 2 * (int32_t)REG_A[1];
+       y = (int16_t)REG_D[4];
+       y += 2 * (int32_t)REG_A[2];
+       z = (int16_t)REG_D[5];
+       z += 2 * (int32_t)REG_A[3];
+       store_coord("large tags", REG_A[0], x, y, z);
+}
+
+/* line of tag */
+static void line_tags(int last_color)
+{
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+
+#ifdef DEBUG_VERTEX
+       printf("add tag's line:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
+
+       /* set color */
+       if (!last_color)
+               gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
+       else
+               gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
+
+       /* two vertices */
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[0] = vertex | 0x200;
+       vertex = m68k_read_memory_8(vertex_address++);
+       render_item->u.line.vertex[1] = vertex | 0x200;
+}
+
+/* polygon of tags */
+static void poly_tags(int last_color)
+{
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add tag's polygon:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
+
+       /* set color */
+       if (!last_color)
+               gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
+       else
+               gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
+       /* the vertex list is zero-terminated */
+       for (i = 0; i < MAX_POLYGON; i++) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               render_item->u.polygon.vertex[i] = vertex | 0x200;
        }
+       render_item->u.polygon.vertices = i;
+}
+
+/* coordinates ready for planet */
+static void coord_planet(void)
+{
+       int32_t x, y, z;
+
+       x = (int32_t)REG_D[3];
+       y = (int32_t)REG_D[4];
+       z = (int32_t)REG_D[5];
+       store_planets_coord("planet", REG_A[0], x, y, z);
 }
+
+/* planet */
+static void draw_planet(int comet)
+{
+       uint32_t vertex;
+       uint32_t scale_index;
+       double scale1, scale2;
+
+       vertex = REG_A[0];
+
+       /* fixing (not noticable) bug in game: don't render comet twice */
+       if (!comet && vertex == 116)
+               return;
+
+#ifdef DEBUG_VERTEX
+       printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_PLANET);
+
+       /* set color */
+       if (comet) {
+               /* make comet black on front side and bright on back */
+               gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
+               gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
+
+       } else {
+               gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
+               /* use background color for dark side */
+               gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
+       }
+
+       /* set vertex */
+       render_item->u.planet.vertex = vertex;
+
+       /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
+        * the long word 21584(A0) contains two scales
+        * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
+        * the upper word defines how much this scale is shifted to the left.
+        */
+       scale_index = mercenary_planet_scale_index();
+       scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
+       scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
+       render_item->u.planet.size = scale1 * scale2 / 128.0;
+}
+
+/* stars */
+static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
+{
+#ifdef DEBUG_VERTEX
+       printf("add stars\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_STARS);
+
+       /* vertical offset */
+       render_item->u.stars.v_offset = v_offset;
+
+       /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
+       render_item->u.stars.tilt = tilt;
+       if (tilt)
+               render_item->u.stars.tilt_value = (int32_t)REG_A[4];
+
+       /* stars above zenith */
+       render_item->u.stars.above_zenith = above_zenith;
+}
+
+/* stars of interstellar flight */
+static void draw_stars_interstellar(void)
+{
+       int i, count;
+       uint32_t table;
+
+#ifdef DEBUG_VERTEX
+       printf("add interstellar stars\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
+
+       table = REG_A[0];
+       count = REG_D[5] + 1;
+       if (count > MAX_INTERSTARS) {
+               print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
+               return;
+       }
+       for (i = 0; i < count; i++) {
+               table += 12;
+               /* get color */
+               render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
+               table += 2;
+               render_item->u.interstars.x[i] = m68k_read_memory_16(table);
+               table += 2;
+               render_item->u.interstars.y[i] = m68k_read_memory_16(table);
+               table += 2;
+       }
+       render_item->u.interstars.count = count;
+}
+
+/* sun of interstellar flight (center dot) */
+static void draw_sun_interstellar(void)
+{
+#ifdef DEBUG_VERTEX
+       printf("add interstellar sun\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
+}
+
+/* coordinates ready for polygons of islands */
+static void coord_islands(void)
+{
+       int32_t x, y, z;
+
+       x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
+       x += (int32_t)REG_A[1];
+       /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
+       y = -motion_new.position_height;
+       z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
+       z += (int32_t)REG_A[3];
+       store_coord("island", REG_A[0], x, y, z);
+}
+
+/* polygon of island */
+static void poly_island()
+{
+       uint16_t color;
+       uint32_t vertex_address = REG_A[0];
+       uint32_t vertex;
+       int i;
+
+#ifdef DEBUG_VERTEX
+       printf("add island:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_ISLAND_POLYGON);
+
+       /* set color */
+       color = m68k_read_memory_8(vertex_address++) << 8;
+       color |= m68k_read_memory_8(vertex_address++);
+       gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
+
+       /* the vertex list is zero-terminated */
+       i = 0;
+       while (i < MAX_POLYGON) {
+               vertex = m68k_read_memory_8(vertex_address++);
+               if (vertex == 0 && i)
+                       break;
+               /* skip mysterious points when rendering island */
+               if (vertex >= 0xf0)
+                       continue;
+               render_item->u.polygon.vertex[i] = vertex;
+               i++;
+       }
+       render_item->u.polygon.vertices = i;
+}
+
+/* sights */
+static void draw_sights(void)
+{
+#ifdef DEBUG_VERTEX
+       printf("add sights:\n");
+#endif
+
+       /* allocate render item */
+       render_item_add(RENDER_ITEM_SIGHTS);
+}
+
+static void draw_explosion(void)
+{
+       uint16_t color;
+
+#ifdef DEBUG_VERTEX
+       printf("add explosion:\n");
+#endif
+
+       /* allocate render item */
+       if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
+               render_item_add(RENDER_ITEM_EXPLOSION);
+               /* get color from render palette */
+               color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
+               gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
+               render_item->u.explosion.count = 0;
+       }
+       if (render_item->u.explosion.count == MAX_EXPLOSION)
+               return;
+       render_item->u.explosion.x[render_item->u.explosion.count] = REG_D[3];
+       render_item->u.explosion.y[render_item->u.explosion.count] = REG_D[4];
+       render_item->u.explosion.z[render_item->u.explosion.count] = REG_D[5];
+       render_item->u.explosion.count++;
+}
+
+/* stop event from CPU received */
+void render_capture_event(int event)
+{
+       switch (event) {
+       case STOP_AT_CLEAR_SCREEN1:
+               clear_screen(16); /* color 16 is raster split */
+               /* in case of screen clearing on the ground, there is no roll */
+               motion_new.orientation_roll = 0;
+               break;
+       case STOP_AT_CLEAR_SCREEN2:
+               clear_screen(15);
+               break;
+       case STOP_AT_CLEAR_SCREEN3:
+               clear_screen(-1); /* no ground (in universe) */
+               break;
+       case STOP_AT_DRAW_GROUND:
+               draw_ground();
+               break;
+       case STOP_AT_INFO_OBJECT_MOVING:
+               info_object(1);
+               break;
+       case STOP_AT_INFO_OBJECT_FIX:
+               info_object(0);
+               break;
+       case STOP_AT_TAG_IS_OBJECT_1:
+               tag_is_object = 1;
+               break;
+       case STOP_AT_TAG_IS_OBJECT_0:
+               tag_is_object = 0;
+               break;
+       case STOP_AT_COORD_OBJECT:
+               coord_object();
+               break;
+       case STOP_AT_POLY_OBJECT_M3:
+               poly_object(3);
+               break;
+       case STOP_AT_POLY_OBJECT_M2:
+               poly_object(2);
+               break;
+       case STOP_AT_LINE_OBJECT:
+               line_object();
+               break;
+       case STOP_AT_COORD_BEACON:
+               coord_beacon();
+               break;
+       case STOP_AT_POINT_BEACON:
+               point_beacon();
+               break;
+       case STOP_AT_COORD_BUILDING_EXTERIOR:
+               coord_building_exterior();
+               break;
+       case STOP_AT_POLY_BUILDING_EXTERIOR:
+               poly_building_exterior();
+               break;
+       case STOP_AT_LINE_BUILDING_EXTERIOR:
+               line_building_exterior();
+               break;
+       case STOP_AT_COORD_BUILDING_INTERIOR:
+               coord_building_interior();
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR1:
+               /* floor */
+               interior_level12 = 1;
+               interior_level34 = 1;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR2:
+               /* ceiling */
+               interior_level12 = 2;
+               interior_level34 = 2;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR3:
+               /* door/window top */
+               interior_level12 = 3;
+               interior_level34 = 3;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR4:
+               /* window bottom */
+               interior_level12 = 4;
+               interior_level34 = 4;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR5:
+               /* door/window top */
+               interior_level12 = 2;
+               interior_level34 = 3;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR6:
+               /* window bottom */
+               interior_level12 = 1;
+               interior_level34 = 4;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR1to4:
+               /* before we come here, we must already passed the break points above, so we know the level to be rendered */
+               if (interior_level12 == 0) {
+                       print_info("Interior level is not set, please fix!\n");
+                       break;
+               }
+               poly_building_interior1to4(interior_level12);
+               interior_level12 = 0;
+               break;
+       case STOP_AT_POLY_BUILDING_INTERIOR5to6:
+               /* before we come here, we must already passed the break points above, so we know the level to be rendered */
+               if (interior_level12 == 0) {
+                       print_info("Interior level is not set, please fix!\n");
+                       break;
+               }
+               poly_building_interior5to6(interior_level12, interior_level34);
+               interior_level12 = 0;
+               break;
+       case STOP_AT_WALL_BUILDING:
+               wall_building();
+               break;
+       case STOP_AT_COORD_COMET:
+               coord_comet();
+               break;
+       case STOP_AT_MATRIX_COMET:
+       case STOP_AT_MATRIX_PLANET:
+               /* track the rotation matrix
+                * if we have 0x42c44 matrix, we must add extra rotation to planet.
+                * the rotation will change the view from the planet's surface */
+               if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
+                       motion_new.planet_rotation = 1;
+               else
+                       motion_new.planet_rotation = 0;
+               break;
+       case STOP_AT_POLY_COMET:
+               poly_comet();
+               break;
+       case STOP_AT_COORD_LINE_ROADS:
+               coord_line_road();
+               break;
+       case STOP_AT_LINE_ROADS:
+               line_road();
+               break;
+       case STOP_AT_COORD_POLY_ROADS:
+               coord_poly_road();
+               break;
+       case STOP_AT_LINE_ROADS_CENTER:
+               /* we don't need to render center lines of roads, because there are polygons already
+                * it does not make sense, since OpenGL has much higher resolution.
+                */
+               break;
+       case STOP_AT_POLY_ROADS:
+               poly_road();
+               break;
+       case STOP_AT_COORD_TAGS:
+               coord_tags();
+               break;
+       case STOP_AT_COORD_TAGS2:
+               coord_tags2();
+               break;
+       case STOP_AT_LINE_TAGS1:
+               line_tags(0);
+               break;
+       case STOP_AT_LINE_TAGS2:
+               line_tags(1);
+               break;
+       case STOP_AT_POLY_TAGS1:
+               poly_tags(0);
+               break;
+       case STOP_AT_POLY_TAGS2:
+               poly_tags(1);
+               break;
+       case STOP_AT_COORD_PLANET:
+               coord_planet();
+               break;
+       case STOP_AT_DRAW_PLANET:
+               draw_planet(0);
+               break;
+       case STOP_AT_DRAW_COMET:
+               draw_planet(1);
+               break;
+       case STOP_AT_DRAW_STARS_SPACE:
+               /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
+               draw_stars(0x1c0, 0, 0);
+               break;
+       case STOP_AT_DRAW_STARS_GROUND:
+               /* render stars with vertical offset 0x128, no tilt, not above zenith */
+               draw_stars(0x128, 0, 0); /* yet it's hex 128! */
+               break;
+       case STOP_AT_DRAW_STARS_FLYING:
+               /* render stars with vertical offset 0x128, with tilt, not above zenith */
+               draw_stars(0x128, 1, 0); /* yet it's hex 128! */
+               break;
+       case STOP_AT_DRAW_STARS_FLYING2:
+               /* render stars with vertical offset 0x128, with tilt, and above zenith */
+               draw_stars(0x128, 1, 1); /* yet it's hex 128! */
+               break;
+       case STOP_AT_DRAW_STARS_INTERSTELLAR:
+               draw_stars_interstellar();
+               break;
+       case STOP_AT_DRAW_SUN_INTERSTELLAR:
+               draw_sun_interstellar();
+               break;
+       case STOP_AT_COORD_ISLANDS:
+               coord_islands();
+               break;
+       case STOP_AT_POLY_ISLANDS:
+               poly_island();
+               break;
+       case STOP_AT_LINE_ISLANDS:
+               /* this is not used, as i had noticed so far */
+               puts("line island");
+               break;
+       case STOP_AT_DRAW_SIGHTS:
+               draw_sights();
+               break;
+       case STOP_AT_POLY_UKN2:
+               puts("poly ukn2");
+               break;
+       case STOP_AT_EXPLOSION:
+               draw_explosion();
+               break;
+       }
+}
+
+/*
+ * rendering
+ */
+
+static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix)
+{
+       render_item_t *ri = NULL;
+
+       if ((vertex & 3)) {
+               print_info("Vertex %d is not a multiple of four!\n", vertex);
+               return -1;
+       }
+       if (vertex < 0x100) {
+               if (!render_item_vertices_0) {
+                       print_info("Vertices item for vertex %d not yet set!\n", vertex);
+                       return -1;
+               }
+               ri = render_item_vertices_0;
+       } else
+       if (vertex < 0x200) {
+               if (!render_item_vertices_1) {
+                       print_info("Vertices item for vertex %d not yet set!\n", vertex);
+                       return -1;
+               }
+               ri = render_item_vertices_1;
+               vertex -= 0x100;
+       } else
+       if (vertex < 0x300) {
+               if (!render_item_vertices_2) {
+                       print_info("Vertices item for vertex %d not yet set!\n", vertex);
+                       return -1;
+               }
+               ri = render_item_vertices_2;
+               vertex -= 0x200;
+       } else {
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+               return -1;
+       }
+       vertex >>= 2;
+       /* translate to original position */
+       *x = ri->u.vertices.x[vertex] - motion_new.position_east;
+       *y = ri->u.vertices.y[vertex] - motion_new.position_height;
+       *z = ri->u.vertices.z[vertex] - motion_new.position_north;
+       if (!fix) {
+               /* translate to floating (interpolated) position offset */
+               *x -= interpolation.offset_east;
+               *y -= interpolation.offset_height;
+               *z -= interpolation.offset_north;
+       }
+#ifdef DEBUG_VERTEX
+       printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
+#endif
+
+       return 0;
+}
+
+static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
+{
+       render_item_t *ri = NULL;
+
+       if ((vertex & 3)) {
+               print_info("Vertex %d is not a multiple of four!\n", vertex);
+               return -1;
+       }
+       if (vertex >= MAX_VERTEX) {
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+               return -1;
+       }
+       if (interpolation.planets)
+               ri = interpolation.planets;
+       else
+               ri = render_item_vertices_0;
+       if (!ri) {
+               print_info("Vertices item for planets verticies not yet set!\n");
+               return -1;
+       }
+       vertex >>= 2;
+       *x = ri->u.vertices.x[vertex];
+       *y = ri->u.vertices.y[vertex];
+       *z = ri->u.vertices.z[vertex];
+#ifdef DEBUG_VERTEX
+       printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
+#endif
+
+       return 0;
+}
+
+static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
+{
+       if ((vertex & 3)) {
+               print_info("Vertex is not a multiple of four!\n");
+               return -1;
+       }
+       if (vertex >= MAX_INTERIOR_VERTEX) {
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+               return -1;
+       }
+       if (level < 1 || level > 4) {
+               print_info("Level %d is out of range (1..4)!\n", level);
+               return -1;
+       }
+       if (!render_item_vertices_interior) {
+               print_info("Vertices item for interior verticies not yet set!\n");
+               return -1;
+       }
+       vertex >>= 2;
+       *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
+       *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
+       *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
+       /* translate to position back to original */
+       *x -= motion_new.position_east;
+       *y -= motion_new.position_height;
+       *z -= motion_new.position_north;
+       /* translate to floating (interpolated) position offset */
+       *x -= interpolation.offset_east;
+       *y -= interpolation.offset_height;
+       *z -= interpolation.offset_north;
+
+#ifdef DEBUG_VERTEX
+       printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
+#endif
+
+       return 0;
+}
+
+/* renders one item from render list */
+void render_one_item(render_item_t *render_item)
+{
+       switch (render_item->type) {
+       case RENDER_ITEM_OBJECT_INFO:
+       {
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
+#endif
+               render_item_object_info = render_item;
+               break;
+       }
+       case RENDER_ITEM_VERTICES_0:
+       {
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_VERTICES_0\n");
+#endif
+               render_item_vertices_0 = render_item;
+               break;
+       }
+       case RENDER_ITEM_VERTICES_1:
+       {
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_VERTICES_1\n");
+#endif
+               render_item_vertices_1 = render_item;
+               break;
+       }
+       case RENDER_ITEM_VERTICES_2:
+       {
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_VERTICES_2\n");
+#endif
+               render_item_vertices_2 = render_item;
+               break;
+       }
+       case RENDER_ITEM_VERTICES_INTERIOR:
+       {
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_VERTICES_INTERIOR\n");
+#endif
+               if (interpolation.interior)
+                       render_item_vertices_interior = interpolation.interior;
+               else
+                       render_item_vertices_interior = render_item;
+               break;
+       }
+       case RENDER_ITEM_SKY:
+       {
+               double x[4], y[4], z[4];
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_SKY\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
+               /* create plane to fill view */
+               x[0] = x[1] = y[1] = y[2] = -1000000;
+               x[2] = x[3] = y[0] = y[3] = 1000000;
+               z[0] = z[1] = z[2] = z[3] = 10;
+               /* render */
+               opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sky (background) is always visible! */
+               break;
+       }
+       case RENDER_ITEM_GROUND:
+       {
+               GET_ORIENTATION;
+               double x[4], y[4], z[4];
+               int i;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_GROUND\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
+               yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
+               /* create huge square */
+               x[0] = x[1] = z[1] = z[2] = -1000000;
+               x[2] = x[3] = z[0] = z[3] = 1000000;
+               y[0] = y[1] = y[2] = y[3] = -10;
+               /* rotate vertex */
+               for (i = 0; i < 4; i++)
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               /* render */
+               opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
+               break;
+       }
+       case RENDER_ITEM_OBJECT_POLYGON:
+       case RENDER_ITEM_TAG_POLYGON_OBJECT:
+       case RENDER_ITEM_TAG_POLYGON_OTHER:
+       case RENDER_ITEM_ISLAND_POLYGON:
+       {
+               GET_ORIENTATION;
+               int fix = 0;
+               double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
+               int i, o;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
+                       printf("RENDER_ITEM_OBJECT_POLYGON\n");
+               if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
+                       printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
+               if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
+                       printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
+               if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
+                       printf("RENDER_ITEM_ISLAND_POLYGON\n");
+#endif
+
+               /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
+               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) {
+//                     GET_ORIENTATION_FIX;
+                       fix = 1;
+               }
+
+               /* get color */
+               opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < render_item->u.polygon.vertices; i++) {
+                       /* get vertex */
+                       rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
+                       if (rc < 0)
+                               break;
+                       /* interpolate motion, if object is moving */
+                       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) {
+                               for (o = 0; o < interpolation.object_count; o++) {
+                                       if (interpolation.object_id[o] == render_item_object_info->u.info.id)
+                                               break;
+                               }
+                               if (o < interpolation.object_count) {
+                                       x[i] += interpolation.object_offset_east[o];
+                                       y[i] += interpolation.object_offset_height[o];
+                                       z[i] += interpolation.object_offset_north[o];
+                               }
+                       }
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
+               break;
+       }
+       case RENDER_ITEM_OBJECT_LINE:
+       case RENDER_ITEM_TAG_LINE_OBJECT:
+       case RENDER_ITEM_TAG_LINE_OTHER:
+       {
+               GET_ORIENTATION;
+               int fix = 0;
+               double x[2], y[2], z[2];
+               int i, o;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               if (render_item->type == RENDER_ITEM_OBJECT_LINE)
+                       printf("RENDER_ITEM_OBJECT_LINE\n");
+               if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
+                       printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
+               if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
+                       printf("RENDER_ITEM_TAG_LINE_OTHER\n");
+#endif
+
+               /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
+               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) {
+//                     GET_ORIENTATION_FIX;
+                       fix = 1;
+               }
+
+               /* get color */
+               opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < 2; i++) {
+                       /* get vertex */
+                       rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
+                       if (rc < 0)
+                               break;
+                       /* interpolate motion, if object is moving */
+                       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) {
+                               for (o = 0; o < interpolation.object_count; o++) {
+                                       if (interpolation.object_id[o] == render_item_object_info->u.info.id)
+                                               break;
+                               }
+                               if (o < interpolation.object_count) {
+                                       x[i] += interpolation.object_offset_east[o];
+                                       y[i] += interpolation.object_offset_height[o];
+                                       z[i] += interpolation.object_offset_north[o];
+                               }
+                       }
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
+               break;
+       }
+       case RENDER_ITEM_BEACON_POINT:
+       {
+               GET_ORIENTATION;
+               double x, y, z;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BEACON_POINT\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
+               /* get vertex */
+               rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
+               if (rc < 0)
+                       break;
+               /* rotate vertex */
+               rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
+               /* render */
+               opengl_render_point(x, y, z, 0.0);
+               break;
+       }
+       case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
+       {
+               GET_ORIENTATION;
+               double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < render_item->u.polygon.vertices; i++) {
+                       /* get vertex */
+                       rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
+               break;
+       }
+       case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
+       {
+               GET_ORIENTATION;
+               double x[2], y[2], z[2];
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < 2; i++) {
+                       /* get vertex */
+                       rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
+               break;
+       }
+       case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
+       {
+               GET_ORIENTATION;
+               double x[4], y[4], z[4];
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < 4; i++) {
+                       /* get vertex */
+                       rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
+               break;
+       }
+       case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
+       {
+               GET_ORIENTATION;
+               double x[4], y[4], z[4];
+               int i;
+               int vertex, level;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < 4; i++) {
+                       /* get vertex */
+                       vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
+                       level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
+                       rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
+               break;
+       }
+       case RENDER_ITEM_BUILDING_INTERIOR_WALL:
+       {
+               GET_ORIENTATION;
+               double x[4], y[4], z[4];
+               int i;
+               int vertex, level;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
+               /* chedck if wall is a rectangle or a line */
+               if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
+                       /* get and rotate vertex */
+                       for (i = 0; i < 4; i++) {
+                               /* get vertex */
+                               vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
+                               level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
+                               rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
+                               if (rc < 0)
+                                       break;
+                               /* rotate vertex */
+                               rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+                       }
+                       /* render */
+                       opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
+               } else {
+                       /* get and rotate vertex */
+                       for (i = 0; i < 2; i++) {
+                               /* get vertex */
+                               vertex = render_item->u.interior56.vertex14;
+                               level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
+                               rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
+                               if (rc < 0)
+                                       break;
+                               /* rotate vertex */
+                               rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+                       }
+                       /* render */
+                       opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
+               }
+               break;
+       }
+       case RENDER_ITEM_COMET_POLYGON:
+       {
+               GET_ORIENTATION;
+               double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
+               double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_COMET_POLYGON\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < render_item->u.polygon.vertices; i++) {
+                       /* get vertex */
+                       rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       if (motion_new.planet_rotation)
+                               rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
+               break;
+       }
+       case RENDER_ITEM_ROAD_LINE:
+       {
+               GET_ORIENTATION;
+               double x[2], y[2], z[2];
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_ROAD_LINE\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
+               /* get and rotate vertex */
+               for (i = 0; i < 2; i++) {
+                       /* get vertex */
+                       rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
+                       if (rc < 0)
+                               break;
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+               }
+               /* render */
+               opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
+               break;
+       }
+       case RENDER_ITEM_ROAD_POLYGON:
+       {
+               GET_ORIENTATION;
+               double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
+               int i, v;
+               uint32_t vertex, vertex_prev, vertex_next;
+               double x_current, y_current, z_current;
+               double x_prev, y_prev, z_prev;
+               double x_next, y_next, z_next;
+               int vertices_num;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_ROAD_POLYGON\n");
+#endif
+               /* get color */
+               opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
+               /* get and rotate vertex */
+               i = 0;
+               vertices_num = render_item->u.polygon.vertices;
+               for (v = 0; v < vertices_num; v++) {
+                       /* get vertex */
+                       vertex = render_item->u.polygon.vertex[v];
+                       rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
+                       if (rc < 0)
+                               break;
+                       /* check for road extension, so we extend the road to the given end point */
+                       if (extend_roads && vertex >= 0xf0) {
+                               /* previous vertex */
+                               vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
+                               rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
+                               if (rc < 0)
+                                       break;
+                               /* next vertex */
+                               vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
+                               rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
+                               if (rc < 0)
+                                       break;
+                               /* extend vertices to end point position
+                                * change x or z coordinate, whatever is greater
+                               */
+                               if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
+                                       x_prev = x_next = x_current;
+                               else
+                                       z_prev = z_next = z_current;
+                               /* store vertices */
+                               x[i] = x_prev;
+                               y[i] = y_prev;
+                               z[i] = z_prev;
+                               /* rotate vertex */
+                               rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+                               if (i++ == MAX_POLYGON)
+                                       break;
+                               x[i] = x_next;
+                               y[i] = y_next;
+                               z[i] = z_next;
+                               /* rotate vertex */
+                               rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+                               if (i++ == MAX_POLYGON)
+                                       break;
+                               continue;
+                       } else {
+                               /* no extension, just keep the current point as is */
+                               x[i] = x_current;
+                               y[i] = y_current;
+                               z[i] = z_current;
+                               /* rotate vertex */
+                               rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+                               if (i++ == MAX_POLYGON)
+                                       break;
+                       }
+               }
+               /* render */
+               opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
+               break;
+       }
+       case RENDER_ITEM_PLANET:
+       {
+               GET_ORIENTATION;
+               double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
+               double sun_x, sun_y, sun_z, angle_sun;
+               double loc_x, loc_y, loc_z, angle_loc;
+               double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
+               double size, angle;
+               int i;
+               int rc;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_PLANET\n");
+#endif
+               /* get location */
+               rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
+               if (rc < 0)
+                       break;
+               rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
+               if (rc < 0)
+                       break;
+               /* get size */
+               size = render_item->u.planet.size;
+               /* rotate vertex */
+               if (motion_new.planet_rotation) {
+                       rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
+                       rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
+               }
+               rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
+               rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
+
+               /* calculate direction of the sun */
+               angle_sun = atan2(sun_x, sun_z);
+               angle_loc = atan2(loc_x, loc_z);
+               angle = angle_sun - angle_loc;
+               if (angle > M_PI)
+                       angle -= 2.0 * M_PI;
+               if (angle < -M_PI)
+                       angle += 2.0 * M_PI;
+
+               /* on which side are we (sun is always bright, vertex == 0) */
+               if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
+                       /* get front side color */
+                       opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
+               } else {
+                       /* get back side color */
+                       opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
+               }
+
+               /* create and render cicle */
+               for (i = 0; i < PLANET_VERTICES; i++) {
+                       x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+                       y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+                       z[i] = loc_z;
+               }
+               opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
+
+               if (render_item->u.planet.vertex == 0) {
+                       /* sun has no crescent */
+                       break;
+               }
+
+               /* on which side are we */
+               if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
+                       /* get back side color */
+                       opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
+               } else {
+                       /* get front side color */
+                       opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
+               }
+
+               /* create and render crescent */
+               if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
+                       angle = fabs(angle);
+                       if (angle > M_PI / 2.0)
+                               angle = M_PI - angle;
+                       /* to the right */
+                       for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
+                               x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+                               y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+                               z[i] = loc_z;
+                       }
+                       for (; i < PLANET_VERTICES; i++) {
+                               x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
+                               y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+                               z[i] = loc_z;
+                       }
+               } else {
+                       angle = fabs(angle);
+                       if (angle > M_PI / 2.0)
+                               angle = M_PI - angle;
+                       /* to the left */
+                       for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
+                               x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
+                               y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+                               z[i] = loc_z;
+                       }
+                       for (; i < PLANET_VERTICES; i++) {
+                               x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+                               y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+                               z[i] = loc_z;
+                       }
+               }
+               opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
+               opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point  */
+               break;
+       }
+       case RENDER_ITEM_STARS:
+       {
+               double tilt_offset = 0;
+               double x_offset = 0;
+               uint16_t color[16];
+               double view_width, yaw = interpolation.orientation_raw_yaw;
+               double pitch = interpolation.orientation_raw_pitch;
+               uint32_t table, table_start;
+               double x, y;
+               double z;
+               int i;
+               double red, green, blue;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_STARS\n");
+#endif
+               /* use default fov of 64 to calculate z distance */
+               z = 160.0 / frustum_slope_64;
+
+               view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
+
+               /* get palette */
+               for (i = 0; i < 16; i++)
+                       color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
+
+               /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
+                * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
+                * then we half it, so we get to the center via 91
+                */
+
+               if (render_item->u.stars.above_zenith)
+                       yaw = 0x200 + yaw;
+               yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
+               yaw *= 2.0;
+               table = mercenary_star_table();
+               table_start = table + m68k_read_memory_16(table);
+               table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
+               yaw = yaw / (double)0x800 * 1800.0;
+
+               if (render_item->u.stars.above_zenith)
+                       pitch = 0x200 - pitch;
+               pitch = fmod(pitch + 65536.0, 0x400);
+               pitch -= render_item->u.stars.v_offset;
+               pitch *= 4;
+               pitch = pitch * (double)0x6ccc / 65536.0;
+
+               while (1) {
+                       x = m68k_read_memory_16(table);
+                       if (x >= 1800.0) {
+                               x_offset += 1800.0;
+                               table = table_start;
+                       }
+                       x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
+                       table += 2;
+                       if (x < 0.0)
+                               break;
+                       /* special case where we tilt the view when flying on the planet */
+                       if (render_item->u.stars.tilt) {
+                               /* use offset as given by game: 160 is half of the screen width
+                                * we extend the width to the actual FOV, so it fits
+                                */
+                               tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
+                       }
+                       y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
+                       table += 2;
+                       if (render_item->u.stars.above_zenith) {
+                               x = (double)(view_width - 1) - x;
+                               y = -1 - y + 136;
+                       }
+                       /* get color */
+                       gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
+                       opengl_render_color(red, green, blue, debug_opacity);
+                       /* render point */
+                       opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
+               }
+               break;
+       }
+       case RENDER_ITEM_INTERSTELLAR_STARS:
+       {
+               uint16_t color[16];
+               double z;
+               int i;
+               double red, green, blue;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
+#endif
+               /* use default fov of 64 to calculate z distance */
+               z = 160.0 / frustum_slope_64;
+
+               /* get palette */
+               for (i = 0; i < 16; i++)
+                       color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
+
+               for (i = 0; i < render_item->u.interstars.count; i++) {
+                       gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
+                       opengl_render_color(red, green, blue, debug_opacity);
+                       /* render point */
+                       opengl_render_point(160.0 - (double)render_item->u.interstars.x[i], 68.0 - (double)render_item->u.interstars.y[i], z, 0.0);
+               }
+               break;
+       }
+       case RENDER_ITEM_INTERSTELLAR_SUN:
+       {
+               double red, green, blue;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
+#endif
+               /* white */
+               gamecolor2gl(&red, &green, &blue, 0x777);
+               opengl_render_color(red, green, blue, debug_opacity);
+               /* render point */
+               opengl_render_point(0.0, 0.0, 100.0, 0.0);
+               break;
+       }
+       case RENDER_ITEM_SIGHTS:
+       {
+               double x[4], y[4], z[4];
+               double red, green, blue;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_SIGHTS\n");
+#endif
+               /* use default fov of 64 to calculate z distance */
+               z[0] = z[1] = z[2] = z[3] = 160.0 / frustum_slope_64;
+
+               /* white */
+               gamecolor2gl(&red, &green, &blue, 0x777);
+               opengl_render_color(red, green, blue, debug_opacity);
+
+               y[0] = y[3] = -1.0;
+               y[1] = y[2] = 1.0;
+               x[0] = x[1] = -16.0;
+               x[2] = x[3] = -8.0;
+               opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
+               x[0] = x[1] = 8.0;
+               x[2] = x[3] = 16.0;
+               opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
+               break;
+       }
+       case RENDER_ITEM_EXPLOSION:
+       {
+               GET_ORIENTATION;
+               double loc_x, loc_y, loc_z, size;
+               double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
+               int i, e;
+
+#ifdef DEBUG_ITEMS
+               printf("RENDER_ITEM_EXPLOSION\n");
+#endif
+               opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
+
+               for (e = 0; e < render_item->u.explosion.count; e++) {
+                       loc_x = render_item->u.explosion.x[e];
+                       loc_y = render_item->u.explosion.y[e];
+                       loc_z = render_item->u.explosion.z[e];
+                       size = 20; /* round about.... */
+                       /* rotate vertex */
+                       rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
+                       /* create and render cicle */
+                       for (i = 0; i < EXPLOSION_VERTICES; i++) {
+                               x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * EXPLOSION_ELIPSE;
+                               y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
+                               z[i] = loc_z;
+                       }
+                       opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
+                       opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point  */
+               }
+               break;
+       }
+       default:
+               print_info("Unknown render item type, please fix!\n");
+       }
+}
+
+/*
+ * interpolation
+ */
+
+static double interpolate_orientation(double old, double new, double inter)
+{
+       double turn = new - old;
+
+       if (turn > M_PI)
+               turn -= 2.0 * M_PI;
+       if (turn < -M_PI)
+               turn += 2.0 * M_PI;
+
+       /* don't interpolate, if our rotation was too fast.
+        * e.g: taxi drive around corder, load/quit game, ...
+        */ 
+       if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
+               return new;
+       
+       new = old + turn * inter;
+       
+       if (new > M_PI)
+               new -= 2.0 * M_PI;
+       if (new < -M_PI)
+               new += 2.0 * M_PI;
+
+       return new;
+}
+
+static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
+{
+       int16_t turn = (new - old) & 0x3ff;
+
+       if (turn > 0x200)
+               turn -= 0x400;
+
+       /* don't interpolate, if our rotation was too fast.
+        * e.g: taxi drive around corder, load/quit game, ...
+        */ 
+       if (turn > 0x200 / 8 || turn < -0x200 / 8)
+               return new;
+
+       /* don't do modulo 0x400, since the user of this data does it */        
+       return (double)old + (double)turn * inter;
+}
+
+static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
+{
+       double offset;
+
+       /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
+       if (ground_index >= 0)
+               offset = wrap_int28(old - new);
+       else
+               offset = (int32_t)(old - new);
+
+       if (limit > 0 && (offset > limit || offset < -limit))
+               return new;
+
+       return offset * (1.0 - inter);
+}
+
+static render_item_t *interpolate_door(double inter)
+{
+       static render_item_t interpolated;
+       render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
+       int nomatch_x_count = 0;
+       int nomatch_z_count = 0;
+       int nomatch_x[4], nomatch_z[4];
+       int i, ii;
+
+       /* find old and new vertices */
+       while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
+               old_vertices = old_vertices->next;
+       while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
+               new_vertices = new_vertices->next;
+
+       /* building does not exist in old or new render */
+       if (!old_vertices || !new_vertices)
+               return NULL;
+
+       /* all verices must match except four */
+       ii = MAX_INTERIOR_VERTEX >> 2;
+       for (i = 0; i < ii; i++) {
+               if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
+                       continue;
+               if (old_vertices->u.vertices_interior.x[i] != new_vertices->u.vertices_interior.x[i]) {
+                       if (nomatch_x_count == 4)
+                               return NULL;
+                       nomatch_x[nomatch_x_count++] = i;
+               }
+       }
+       for (i = 0; i < 4; i++) {
+               if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
+                       return NULL;
+       }
+       for (i = 0; i < ii; i++) {
+               if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
+                       continue;
+               if (old_vertices->u.vertices_interior.z[i] != new_vertices->u.vertices_interior.z[i]) {
+                       if (nomatch_z_count == 4)
+                               return NULL;
+                       nomatch_z[nomatch_z_count++] = i;
+               }
+       }
+
+       /* copy, even if not interpolated */
+       memcpy(&interpolated, new_vertices, sizeof(interpolated));
+
+       /* only four x missmatch */
+       if (nomatch_x_count == 4 || nomatch_x_count == 2) {
+               for (i = 0; i < nomatch_x_count; i++) {
+                       interpolated.u.vertices_interior.x[nomatch_x[i]] =
+                       (double)old_vertices->u.vertices_interior.x[nomatch_x[i]] * (1.0 - inter) +
+                       (double)new_vertices->u.vertices_interior.x[nomatch_x[i]] * inter;
+               }
+       }
+
+       /* only four z missmatch */
+       if (nomatch_z_count == 4 || nomatch_z_count == 2) {
+               for (i = 0; i < nomatch_z_count; i++) {
+                       interpolated.u.vertices_interior.z[nomatch_z[i]] =
+                       (double)old_vertices->u.vertices_interior.z[nomatch_z[i]] * (1.0 - inter) +
+                       (double)new_vertices->u.vertices_interior.z[nomatch_z[i]] * inter;
+               }
+       }
+
+       return &interpolated;
+}
+
+/* make a list of objects that moved and store their displacement */
+static void interpolate_objects(double inter)
+{
+       render_item_t *old_info, *new_info;
+       int count;
+
+       /* hunt for objects that exist in both (old and new) lists and moved */
+       count = 0;
+       for (new_info = render_list_new; new_info; new_info = new_info -> next) {
+               /* not an object */
+               if (new_info->type != RENDER_ITEM_OBJECT_INFO)
+                       continue;
+               /* not moving */
+               if (!new_info->u.info.moving)
+                       continue;
+               /* interiors don't move */
+               if (new_info->u.info.id < 0)
+                       continue;
+               /* check matching object with same ID */
+               for (old_info = render_list_old; old_info; old_info = old_info -> next) {
+                       /* not an object */
+                       if (old_info->type != RENDER_ITEM_OBJECT_INFO)
+                               continue;
+                       /* not moving */
+                       if (!old_info->u.info.moving)
+                               continue;
+                       /* same id */
+                       if (old_info->u.info.id == new_info->u.info.id)
+                               break;
+               }
+               /* no matching object found */
+               if (!old_info)
+                       continue;
+               /* not moving */
+               if (old_info->u.info.east == new_info->u.info.east
+                && old_info->u.info.height == new_info->u.info.height
+                && old_info->u.info.north == new_info->u.info.north)
+                       continue;
+               /* interpolate and store */
+               interpolation.object_id[count] = new_info->u.info.id;
+               interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
+               interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
+               interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
+               if (count++ == MAX_MOVING_OBJECTS)
+                       break;
+       }
+       interpolation.object_count = count;
+}
+
+/* make a vertex list of interpolated planets */
+static render_item_t *interpolate_planets(double inter)
+{
+       static render_item_t interpolated;
+       render_item_t *old_info, *new_info;
+       render_item_t *old_vertices = NULL, *new_vertices = NULL;
+       int i;
+
+       /* get vertices for planets/comet */
+       for (old_info = render_list_old; old_info; old_info = old_info -> next) {
+               if (old_info->type == RENDER_ITEM_VERTICES_0)
+                       old_vertices = old_info;
+               /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
+               if (old_info->type == RENDER_ITEM_COMET_POLYGON)
+                       break;
+       }
+       for (new_info = render_list_new; new_info; new_info = new_info -> next) {
+               if (new_info->type == RENDER_ITEM_VERTICES_0)
+                       new_vertices = new_info;
+               /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
+               if (new_info->type == RENDER_ITEM_COMET_POLYGON)
+                       break;
+       }
+
+       /* check for existing planet's vertices and if planets are rendered in both lists (old and new) */
+       if (old_info == NULL || new_info == NULL || old_vertices == NULL || new_vertices == NULL)
+               return NULL;
+
+       /* interpolate vertices */
+       for (i = 0; i < (MAX_VERTEX >> 2); i++) {
+               interpolated.u.vertices.x[i] = old_vertices->u.vertices.x[i] * (1.0 - inter) + new_vertices->u.vertices.x[i] * inter;
+               interpolated.u.vertices.y[i] = old_vertices->u.vertices.y[i] * (1.0 - inter) + new_vertices->u.vertices.y[i] * inter;
+               interpolated.u.vertices.z[i] = old_vertices->u.vertices.z[i] * (1.0 - inter) + new_vertices->u.vertices.z[i] * inter;
+       }
+
+       return &interpolated;
+}
+
+/* always renders NEW! items
+ * use inter == 1.0 to render motion to vertices of NEW items
+ * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
+ * return 0, if the scene was rendered, returns < 0, if there is no scene
+ */
+int render_all_items(double inter)
+{
+       render_item_object_info = NULL;
+       render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
+       render_item_vertices_interior = NULL;
+       render_item_vertices_planets = NULL;
+
+       /* no interpolation when leaving or entering planet to/from space */
+       if ((last_ground_index < 0 && ground_index >= 0)
+        || (last_ground_index >= 0 && ground_index < 0)) {
+               inter = 1.0;
+       }
+
+       /* reset interpolation */
+       memset(&interpolation, 0, sizeof(interpolation));
+       interpolation.orientation_roll = motion_new.orientation_roll;
+       interpolation.orientation_pitch = motion_new.orientation_pitch;
+       interpolation.orientation_yaw = motion_new.orientation_yaw;
+       interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
+       interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
+       interpolation.planet_inclination = motion_new.planet_inclination;
+       interpolation.planet_azimuth = motion_new.planet_azimuth;
+//printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
+
+       /* do interpolation */
+       if (inter != 1.0 && render_list_old) {
+               /* interpolate orientation */
+               interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
+               interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
+               interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
+               interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
+               interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
+               interpolation.planet_inclination = interpolate_orientation(motion_old.planet_inclination, motion_new.planet_inclination, inter);
+               interpolation.planet_azimuth = interpolate_orientation(motion_old.planet_azimuth, motion_new.planet_azimuth, inter);
+
+               /* interpolate position */
+               interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
+               interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
+               interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
+               /* prevent glitch when using elevators: a sudden vertical move is ignored
+                * this is not the best solution, because fast vertical flying (from 0) will also be detected */
+               if (old_height_offset == 0
+                && (new_height_offset >= 150 || new_height_offset <= -150)) {
+                       interpolation.offset_east = 0.0;
+                       interpolation.offset_height = 0.0;
+                       interpolation.offset_north = 0.0;
+               }
+
+               /* interpolate doors of building (if any) */
+               interpolation.interior = interpolate_door(inter);
+
+               /* interpolate objects */
+               interpolate_objects(inter);
+
+               /* interpolate planets */
+               interpolation.planets = interpolate_planets(inter);
+       }
+
+       /* return failure, if nothing can be rendered */
+       if (!render_list_new)
+               return -1;
+
+       for (render_item = render_list_new; render_item; render_item = render_item->next) {
+               render_one_item(render_item);
+       }
+
+       return 0;
+}
+
+void render_capture_reset(void)
+{
+       /* flush old list, if exists */
+       flush_old_items();
+       /* flush new list, if exists */
+       render_list_old = render_list_new;
+       flush_old_items();
+       /* reset list pointers */
+       render_list_old = NULL;
+       render_list_new = NULL;
+       render_list_end = &render_list_new;
+       render_item = NULL;
+}
+
+int render_capture_is_interstellar(void)
+{
+       if (!render_list_new)
+               return 0;
+       for (render_item = render_list_new; render_item; render_item = render_item->next) {
+               if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)
+                       return 1;
+       }
+
+       return 0;
+}
+