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