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