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