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