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