Fix interpolation of objects
[mercenary-reloaded.git] / src / mercenary / render.c
index 85498fc..f672eac 100644 (file)
@@ -105,7 +105,7 @@ struct render_item_info {
 };
 
 struct render_item_vertices {
-       int32_t x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
+       double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
 };
 
 struct render_item_vertices_interior {
@@ -213,10 +213,12 @@ 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 \
@@ -253,7 +255,7 @@ static render_item_t *render_item;
 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_interior;
+static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
 
 /*
  * capturing
@@ -319,6 +321,7 @@ void render_capture_start(double _fov, int _extend_roads, int debug)
 
        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 */
@@ -358,7 +361,7 @@ static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_
 #endif
        if (color >= 0x8000) {
 #ifdef DEBUG_COLOR
-               print_error("Use of color index from current palette, but index is not defined as being set!\n");
+               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;
@@ -396,7 +399,7 @@ again:
 #endif
                /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
                if (nesting++ == 8) {
-                       print_error("Color lookup from pre-defined palette is nesting too much, please fix!\n");
+                       print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
                        return;
                }
                goto again;
@@ -416,7 +419,7 @@ static int32_t wrap_int28(int32_t value)
 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_error("Vertex %d is not a multiple of four!\n", vertex);
+               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 */
@@ -449,12 +452,12 @@ static void store_coord(const char __attribute__((unused)) *what, uint32_t verte
                }
                vertex -= 0x200;
        } else {
-               print_error("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
+               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=%.0f, y=%.0f, z=%.0f\n", what, vertex, x, y, z);
+       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;
@@ -465,21 +468,48 @@ static void store_coord(const char __attribute__((unused)) *what, uint32_t verte
        render_item->u.vertices.z[vertex] = z;
 }
 
+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;
+}
+
 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_error("Vertex is not a multiple of four!\n");
+               print_info("Vertex is not a multiple of four!\n");
                return;
        }
        if (vertex >= MAX_INTERIOR_VERTEX) {
-               print_error("Vertex %d exceeds maximum vertex number %d!\n", 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=%.0f, y=%.0f;%.0f;%.0f;%.0F, Z=%.0F\n", what, vertex, x, y1, y2, y3, y4, z);
+       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;
@@ -825,7 +855,7 @@ static void coord_comet(void)
        x = (int32_t)REG_D[3];
        y = (int32_t)REG_D[4];
        z = (int32_t)REG_D[5];
-       store_coord("comet tail", REG_A[0], x, y, z);
+       store_planets_coord("comet tail", REG_A[0], x, y, z);
 }
 
 /* polygon of comet tail */
@@ -1026,7 +1056,7 @@ static void coord_planet(void)
        x = (int32_t)REG_D[3];
        y = (int32_t)REG_D[4];
        z = (int32_t)REG_D[5];
-       store_coord("planet", REG_A[0], x, y, z);
+       store_planets_coord("planet", REG_A[0], x, y, z);
 }
 
 /* planet */
@@ -1113,7 +1143,7 @@ static void draw_stars_interstellar(void)
        table = REG_A[0];
        count = REG_D[5] + 1;
        if (count > MAX_INTERSTARS) {
-               print_error("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
+               print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
                return;
        }
        for (i = 0; i < count; i++) {
@@ -1317,7 +1347,7 @@ void render_capture_event(int event)
        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_error("Interior level is not set, please fix!\n");
+                       print_info("Interior level is not set, please fix!\n");
                        break;
                }
                poly_building_interior1to4(interior_level12);
@@ -1326,7 +1356,7 @@ void render_capture_event(int event)
        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_error("Interior level is not set, please fix!\n");
+                       print_info("Interior level is not set, please fix!\n");
                        break;
                }
                poly_building_interior5to6(interior_level12, interior_level34);
@@ -1448,19 +1478,19 @@ static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex,
        render_item_t *ri = NULL;
 
        if ((vertex & 3)) {
-               print_error("Vertex %d is not a multiple of four!\n", vertex);
+               print_info("Vertex %d is not a multiple of four!\n", vertex);
                return -1;
        }
        if (vertex < 0x100) {
                if (!render_item_vertices_0) {
-                       print_error("Vertices item for vertex %d not yet set!\n", vertex);
+                       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_error("Vertices item for vertex %d not yet set!\n", vertex);
+                       print_info("Vertices item for vertex %d not yet set!\n", vertex);
                        return -1;
                }
                ri = render_item_vertices_1;
@@ -1468,13 +1498,13 @@ static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex,
        } else
        if (vertex < 0x300) {
                if (!render_item_vertices_2) {
-                       print_error("Vertices item for vertex %d not yet set!\n", vertex);
+                       print_info("Vertices item for vertex %d not yet set!\n", vertex);
                        return -1;
                }
                ri = render_item_vertices_2;
                vertex -= 0x200;
        } else {
-               print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
                return -1;
        }
        vertex >>= 2;
@@ -1495,22 +1525,53 @@ static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex,
        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_error("Vertex is not a multiple of four!\n");
+               print_info("Vertex is not a multiple of four!\n");
                return -1;
        }
        if (vertex >= MAX_INTERIOR_VERTEX) {
-               print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+               print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
                return -1;
        }
        if (level < 1 || level > 4) {
-               print_error("Level %d is out of range (1..4)!\n", level);
+               print_info("Level %d is out of range (1..4)!\n", level);
                return -1;
        }
        if (!render_item_vertices_interior) {
-               print_error("Vertices item for interior verticies not yet set!\n");
+               print_info("Vertices item for interior verticies not yet set!\n");
                return -1;
        }
        vertex >>= 2;
@@ -1643,7 +1704,7 @@ void render_one_item(render_item_t *render_item)
 #endif
 
                /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
-               if (render_item->type == RENDER_ITEM_OBJECT_POLYGON && render_item_object_info && !render_item_object_info->u.info.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) {
 //                     GET_ORIENTATION_FIX;
                        fix = 1;
                }
@@ -1682,7 +1743,7 @@ void render_one_item(render_item_t *render_item)
                GET_ORIENTATION;
                int fix = 0;
                double x[2], y[2], z[2];
-               int i;
+               int i, o;
                int rc;
 
 #ifdef DEBUG_ITEMS
@@ -1708,6 +1769,18 @@ void render_one_item(render_item_t *render_item)
                        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]);
                }
@@ -1887,7 +1960,7 @@ void render_one_item(render_item_t *render_item)
        case RENDER_ITEM_COMET_POLYGON:
        {
                GET_ORIENTATION;
-               double inclination = motion_new.planet_inclination, azimuth = motion_new.planet_azimuth;
+               double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
                double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
                int i;
                int rc;
@@ -1900,7 +1973,7 @@ void render_one_item(render_item_t *render_item)
                /* get and rotate vertex */
                for (i = 0; i < render_item->u.polygon.vertices; i++) {
                        /* get vertex */
-                       rc = use_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], motion_new.planet_rotation);
+                       rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
                        if (rc < 0)
                                break;
                        /* rotate vertex */
@@ -2016,7 +2089,7 @@ void render_one_item(render_item_t *render_item)
        case RENDER_ITEM_PLANET:
        {
                GET_ORIENTATION;
-               double inclination = motion_new.planet_inclination, azimuth = motion_new.planet_azimuth;
+               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];
@@ -2028,10 +2101,10 @@ void render_one_item(render_item_t *render_item)
                printf("RENDER_ITEM_PLANET\n");
 #endif
                /* get location */
-               rc = use_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z, motion_new.planet_rotation);
+               rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
                if (rc < 0)
                        break;
-               rc = use_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z, motion_new.planet_rotation);
+               rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
                if (rc < 0)
                        break;
                /* get size */
@@ -2292,7 +2365,7 @@ void render_one_item(render_item_t *render_item)
                break;
        }
        default:
-               print_error("Unknown type, please fix!\n");
+               print_info("Unknown render item type, please fix!\n");
        }
 }
 
@@ -2475,15 +2548,55 @@ static void interpolate_objects(double inter)
        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
  */
-void render_all_items(double inter)
+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)
@@ -2498,6 +2611,8 @@ void render_all_items(double inter)
        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 */
@@ -2508,6 +2623,8 @@ void render_all_items(double 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);
@@ -2527,23 +2644,20 @@ void render_all_items(double inter)
 
                /* interpolate objects */
                interpolate_objects(inter);
-       }
 
-       /* add a blank background, if render list is empty */
-       if (!render_list_new) {
-               render_item_t blank;
-               memset(&blank, 0, sizeof(blank));
-               blank.type = RENDER_ITEM_SKY;
-               blank.u.sky.red = 0.5;
-               blank.u.sky.green = 0.5;
-               blank.u.sky.blue = 0.5;
-               render_one_item(&blank);
-               return;
+               /* 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)