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