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