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