7c0bc1ff1e693a7413bba86e492fcfdc2099bd01
[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 #include <stdio.h>
21 #include <stdint.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <math.h>
25 #include <GL/glew.h>
26 #include "../libsdl/print.h"
27 #include "../libcpu/m68k.h"
28 #include "../libcpu/m68kcpu.h"
29 #include "../libcpu/execute.h"
30 #include "../libsdl/opengl.h"
31 #include "mercenary.h"
32
33 //#define DEBUG_COLOR
34 //#define DEBUG_VERTEX
35 #define DEBUG_ITEMS
36
37 #define MAX_POLYGON             16      /* number of polygon complexity (vertices) */
38 #define MAX_VERTEX              0x100   /* this is the value range, these are 64 vertices */
39 #define MAX_INTERIOR_VERTEX     0x400   /* do we need that much? */
40 #define MAX_INTERSTARS          80      /* always 80 stars */
41 #define PLANET_VERTICES         128
42 #define PLANET_ELIPSE           1.17
43
44
45 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
46 static double fov;
47 static double debug_opacity;
48 static double frustum_slope_64, frustum_slope_fov;
49 static double orientation_roll, orientation_pitch, orientation_yaw;
50 static uint16_t orientation_raw_yaw;
51 static int16_t orientation_raw_pitch;
52 static double planet_inclination, planet_azimuth;
53
54 enum render_item_type {
55         RENDER_ITEM_VERTICES_0,
56         RENDER_ITEM_VERTICES_1,
57         RENDER_ITEM_VERTICES_2,
58         RENDER_ITEM_VERTICES_INTERIOR,
59         RENDER_ITEM_SKY,
60         RENDER_ITEM_GROUND,
61         RENDER_ITEM_OBJECT_POLYGON,
62         RENDER_ITEM_OBJECT_LINE,
63         RENDER_ITEM_BEACON_POINT,
64         RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
65         RENDER_ITEM_BUILDING_EXTERIOR_LINE,
66         RENDER_ITEM_BUILDING_INTERIOR_1TO4,
67         RENDER_ITEM_BUILDING_INTERIOR_5TO6,
68         RENDER_ITEM_BUILDING_INTERIOR_WALL,
69         RENDER_ITEM_COMET_POLYGON,
70         RENDER_ITEM_ROAD_LINE,
71         RENDER_ITEM_ROAD_POLYGON,
72         RENDER_ITEM_TAG_LINE,
73         RENDER_ITEM_TAG_POLYGON,
74         RENDER_ITEM_PLANET,
75         RENDER_ITEM_STARS,
76         RENDER_ITEM_INTERSTELLAR_STARS,
77         RENDER_ITEM_INTERSTELLAR_SUN,
78         RENDER_ITEM_ISLAND_POLYGON,
79         RENDER_ITEM_SIGHTS,
80 };
81
82 struct render_item_vertices {
83         int32_t x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
84 };
85
86 struct render_item_vertices_interior {
87         int32_t x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
88 };
89
90 struct render_item_sky {
91         double red, green, blue;
92 };
93
94 struct render_item_ground {
95         double red, green, blue;
96 };
97
98 struct render_item_polygon {
99         double red, green, blue;
100         int vertices;
101         int vertex[MAX_POLYGON];
102 };
103
104 struct render_item_interior14 {
105         double red, green, blue;
106         int level;
107         int vertex[4];
108 };
109
110 struct render_item_interior56 {
111         double red, green, blue;
112         int level12;
113         int level34;
114         int vertex14;
115         int vertex23;
116 };
117
118 struct render_item_line {
119         double red, green, blue;
120         int vertex[2];
121 };
122
123 struct render_item_point {
124         double red, green, blue;
125         int vertex;
126 };
127
128 struct render_item_planet {
129         double front_red, front_green, front_blue;
130         double back_red, back_green, back_blue;
131         int vertex;
132         double size;
133 };
134
135 struct render_item_stars {
136         int16_t v_offset;
137         int tilt;
138         int32_t tilt_value;
139         int above_zenith;
140 };
141
142 struct render_item_interstars {
143         uint8_t color[MAX_INTERSTARS];
144         int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
145         int     count;
146 };
147
148 typedef struct render_item {
149         struct render_item *next;
150         enum render_item_type type;
151         union {
152                 struct render_item_vertices             vertices;
153                 struct render_item_vertices_interior    vertices_interior;
154                 struct render_item_sky                  sky;
155                 struct render_item_ground               ground;
156                 struct render_item_polygon              polygon;
157                 struct render_item_line                 line;
158                 struct render_item_point                point;
159                 struct render_item_interior14           interior14;
160                 struct render_item_interior56           interior56;
161                 struct render_item_planet               planet;
162                 struct render_item_stars                stars;
163                 struct render_item_interstars           interstars;
164         } u;
165 } render_item_t;
166
167 static render_item_t *render_list_start = NULL, **render_list_end = &render_list_start;
168 static render_item_t *render_item;
169 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
170 static render_item_t *render_item_vertices_interior;
171
172 void render_item_add(enum render_item_type type)
173 {
174         render_item = calloc(1, sizeof(render_item_t));
175         if (!render_item) {
176                 print_error("No memory, must abort!\n");
177                 abort();
178         }
179         render_item->type = type;
180         *render_list_end = render_item;
181         render_list_end = &render_item->next;
182 }
183
184 /* rendering starts, initialize variables */
185 void render_capture_start(double _fov, int _extend_roads, int debug)
186 {
187 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
188         printf("start rendering a new frame...\n");
189 #endif
190
191         /* flush render list */
192         while (render_list_start) {
193                 render_item = render_list_start;
194                 render_list_start = render_list_start->next;
195                 free(render_item);
196         }
197         render_list_end = &render_list_start;
198         render_item = NULL;
199
200         /* set rendering options */
201         fov = _fov;
202         extend_roads = _extend_roads;
203         /* set some transpareny, if debugging is enabled */
204         debug_opacity = (debug) ? 0.5 : 1.0;
205
206         /* calculate slope of 64 degree frustum and current FOV's frustum */    
207         frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
208         frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
209
210         /* get orientation */
211         mercenary_get_orientation(&orientation_roll, &orientation_pitch, &orientation_yaw);
212         mercenary_get_orientation_raw(&orientation_raw_pitch, &orientation_raw_yaw);
213         mercenary_get_orientation_planet(&planet_inclination, &planet_azimuth);
214
215         render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
216         render_item_vertices_interior = NULL;
217 }
218
219 void render_capture_stop(void)
220 {
221 }
222
223 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
224 {
225         uint32_t palette;
226         uint16_t color;
227
228         /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
229         index <<= 1;
230         palette = mercenary_palette_render();
231         color = m68k_read_memory_16(palette + index);
232 #ifdef DEBUG_COLOR
233         printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
234 #endif
235         if (color >= 0x8000) {
236 #ifdef DEBUG_COLOR
237                 print_error("Use of color index from current palette, but index is not defined as being set!\n");
238 #endif
239         }
240         *red = (double)((color >> 8) & 0xf) / 15.0;
241         *green = (double)((color >> 4) & 0xf) / 15.0;
242         *blue = (double)(color & 0xf) / 15.0;
243 }
244
245 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
246 {
247         uint16_t index;
248         uint32_t palette;
249         int nesting = 0;
250
251 #ifdef DEBUG_COLOR
252         printf("color is given as 0x%04x\n", color);
253 #endif
254 again:
255         /* color conversion: see for example M3: 0x4f830 */
256         if (color < 0x8000) {
257                 /* use given color but shift it left by 1 */
258                 color = color << 1;
259 #ifdef DEBUG_COLOR
260                 printf("using given color, color is now 0x%04x\n", color);
261 #endif
262         } else if ((color & 0xff) < 0x80) {
263                 gamecolor2gl_index(red, green, blue, color & 0xf);
264                 return;
265         } else {
266                 /* use given index from pre-defined palette */
267                 index = color & 0x7e;
268                 palette = mercenary_palette_predefined();
269                 color = m68k_read_memory_16(palette + index);
270 #ifdef DEBUG_COLOR
271                 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
272 #endif
273                 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
274                 if (nesting++ == 8) {
275                         print_error("Color lookup from pre-defined palette is nesting too much, please fix!\n");
276                         return;
277                 }
278                 goto again;
279         }
280         *red = (double)((color >> 8) & 0xf) / 15.0;
281         *green = (double)((color >> 4) & 0xf) / 15.0;
282         *blue = (double)(color & 0xf) / 15.0;
283 }
284
285 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
286 {
287         if ((vertex & 3)) {
288                 print_error("Vertex %d is not a multiple of four!\n", vertex);
289                 return;
290         }
291         /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
292         if (vertex < 0x100) {
293                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
294                         render_item_add(RENDER_ITEM_VERTICES_0);
295                         /* copy vertices that have been captured already */
296                         if (render_item_vertices_0)
297                                 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
298                         render_item_vertices_0 = render_item;
299                 }
300         } else
301         if (vertex < 0x200) {
302                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
303                         render_item_add(RENDER_ITEM_VERTICES_1);
304                         /* copy vertices that have been captured already */
305                         if (render_item_vertices_1)
306                                 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
307                         render_item_vertices_1 = render_item;
308                 }
309                 vertex -= 0x100;
310         } else
311         if (vertex < 0x300) {
312                 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
313                         render_item_add(RENDER_ITEM_VERTICES_2);
314                         /* copy vertices that have been captured already */
315                         if (render_item_vertices_2)
316                                 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
317                         render_item_vertices_2 = render_item;
318                 }
319                 vertex -= 0x200;
320         } else {
321                 print_error("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
322                 return;
323         }
324         vertex >>= 2;
325 #ifdef DEBUG_VERTEX
326         printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, x, y, z);
327 #endif
328         render_item->u.vertices.x[vertex] = x;
329         render_item->u.vertices.y[vertex] = y;
330         render_item->u.vertices.z[vertex] = z;
331 }
332
333 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)
334 {
335         if ((vertex & 3)) {
336                 print_error("Vertex is not a multiple of four!\n");
337                 return;
338         }
339         if (vertex >= MAX_INTERIOR_VERTEX) {
340                 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
341                 return;
342         }
343         if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
344                 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
345         vertex >>= 2;
346 #ifdef DEBUG_VERTEX
347         printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f;%.0f;%.0f;%.0F, Z=%.0F\n", what, vertex, x, y1, y2, y3, y4, z);
348 #endif
349         render_item->u.vertices_interior.x[vertex] = x;
350         render_item->u.vertices_interior.y[0] = y1;
351         render_item->u.vertices_interior.y[1] = y2;
352         render_item->u.vertices_interior.y[2] = y3;
353         render_item->u.vertices_interior.y[3] = y4;
354         render_item->u.vertices_interior.z[vertex] = z;
355 }
356
357 static int planet_rotation = 0;
358
359 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
360 {
361         double out_x, out_y, out_z;
362
363         /* rotate yaw (German: Gier, turn view to the right) */
364         out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
365         out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
366         *z = out_z;
367         *x = out_x;
368         /* rotate pitch (German: Nick, turn head down) */
369         out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
370         out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
371         *y = out_y;
372         *z = out_z;
373         if (roll == 0.0)
374                 return;
375         /* rotate roll (tilt head to the right) */
376         out_x = (*x) * cos(roll) - (*y) * sin(roll);
377         out_y = (*x) * sin(roll) + (*y) * cos(roll);
378         *x = out_x;
379         *y = out_y;
380 }
381
382 static int ground_index;
383
384 /* clear screen color (sky / universe) */
385 static void clear_screen(int index)
386 {
387 #ifdef DEBUG_VERTEX
388         printf("clear screen:\n");
389 #endif
390
391         /* allocate render item */
392         render_item_add(RENDER_ITEM_SKY);
393
394         /* set color */
395         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
396
397         /* store for later use after planets have been rendered */
398         ground_index = index;
399 }
400
401 /* ground color */
402 static void draw_ground(void)
403 {
404         /* no ground in space :) */
405         if (ground_index < 0)
406                 return;
407
408 #ifdef DEBUG_VERTEX
409         printf("add ground plane:\n");
410 #endif
411
412         /* allocate render item */
413         render_item_add(RENDER_ITEM_GROUND);
414
415         /* set color */
416         gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
417 }
418
419 /* coordinates ready for an object */
420 static void coord_object(void)
421 {
422         int32_t x, y, z;
423
424         x = (int16_t)REG_D[3];
425         x += (int32_t)REG_A[1];
426         y = (int16_t)REG_D[4];
427         y += (int32_t)REG_A[2];
428         z = (int16_t)REG_D[5];
429         z += (int32_t)REG_A[3];
430         store_coord("object", REG_A[0], x, y, z);
431 }
432
433 /* polygon of object */
434 static void poly_object(int mercenary)
435 {
436         uint32_t vertex_address = REG_A[0];
437         uint32_t vertex;
438         int i;
439
440 #ifdef DEBUG_VERTEX
441         printf("add object's polygon:\n");
442 #endif
443
444         /* allocate render item */
445         render_item_add(RENDER_ITEM_OBJECT_POLYGON);
446
447         /* set color */
448         if (mercenary == 3)
449                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
450         else {
451                 uint16_t color;
452                 color = m68k_read_memory_8(vertex_address++) << 8;
453                 color |= m68k_read_memory_8(vertex_address++);
454                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
455         }
456
457         /* the vertex list is zero-terminated */
458         for (i = 0; i < MAX_POLYGON; i++) {
459                 vertex = m68k_read_memory_8(vertex_address++);
460                 if (vertex == 0 && i)
461                         break;
462                 render_item->u.polygon.vertex[i] = vertex;
463         }
464         render_item->u.polygon.vertices = i;
465 }
466
467 /* line of object */
468 static void line_object(void)
469 {
470         uint32_t vertex_address = REG_A[0];
471         uint32_t vertex;
472
473 #ifdef DEBUG_VERTEX
474         printf("add object's line:\n");
475 #endif
476
477         /* allocate render item */
478         render_item_add(RENDER_ITEM_OBJECT_LINE);
479
480         /* set color */
481         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
482
483         /* two vertices */
484         vertex = m68k_read_memory_8(vertex_address++);
485         render_item->u.line.vertex[0] = vertex;
486         vertex = m68k_read_memory_8(vertex_address++);
487         render_item->u.line.vertex[1] = vertex;
488 }
489
490 /* coordinates ready for a beacon */
491 static void coord_beacon(void)
492 {
493         int32_t x, y, z;
494
495         /* only 28 bits seem to be a correct signed int value */
496         x = ((int32_t)REG_D[3] << 4) / 16;
497         y = ((int32_t)REG_D[4] << 4) / 16;
498         z = ((int32_t)REG_D[5] << 4) / 16;
499         store_coord("beacon", 0, x, y, z);
500 }
501
502 /* point of beacon */
503 static void point_beacon(void)
504 {
505 #ifdef DEBUG_VERTEX
506         printf("add beacon's point:\n");
507 #endif
508
509         /* allocate render item */
510         render_item_add(RENDER_ITEM_BEACON_POINT);
511
512         /* set color */
513         gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
514
515         /* one vertex */
516         render_item->u.point.vertex = 0;
517 }
518
519 /* coordinates ready for a building (exterior) */
520 static void coord_building_exterior(void)
521 {
522         int32_t x, y, z;
523
524         x = (int32_t)REG_D[3];
525         y = (int32_t)REG_D[4];
526         z = (int32_t)REG_D[5];
527         store_coord("building exterior", REG_A[0], x, y, z);
528 }
529
530 /* polygon of building (exterior) */
531 static void poly_building_exterior(void)
532 {
533         uint16_t color;
534         uint32_t vertex_address = REG_A[0];
535         uint32_t vertex;
536         int i;
537
538 #ifdef DEBUG_VERTEX
539         printf("add building's polygon:\n");
540 #endif
541
542         /* allocate render item */
543         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
544
545         /* set color */
546         color = m68k_read_memory_8(vertex_address++) << 8;
547         color |= m68k_read_memory_8(vertex_address++);
548         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
549
550         /* the vertex list is zero-terminated */
551         for (i = 0; i < MAX_POLYGON; i++) {
552                 vertex = m68k_read_memory_8(vertex_address++);
553                 if (vertex == 0 && i)
554                         break;
555                 render_item->u.polygon.vertex[i] = vertex | 0x100;
556         }
557         render_item->u.polygon.vertices = i;
558 }
559
560 /* line of building (exterior) */
561 static void line_building_exterior(void)
562 {
563         uint32_t vertex_address = REG_A[0];
564         uint32_t vertex;
565
566 #ifdef DEBUG_VERTEX
567         printf("add building's line:\n");
568 #endif
569
570         /* allocate render item */
571         render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
572
573         /* set color */
574         gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
575
576         /* two vertices */
577         vertex = m68k_read_memory_8(vertex_address++);
578         render_item->u.line.vertex[0] = vertex | 0x100;
579         vertex = m68k_read_memory_8(vertex_address++);
580         render_item->u.line.vertex[1] = vertex | 0x100;
581 }
582
583 static int interior_level12 = 0;
584 static int interior_level34 = 0;
585
586 /* coordinates ready for a building (interior) */
587 static void coord_building_interior(void)
588 {
589         int16_t east, north;
590         int32_t height1, height2, height3, height4;
591
592         mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
593         store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
594 }
595
596 /* polygon of building (interior) */
597 static void poly_building_interior1to4(int level)
598 {
599         uint16_t color;
600         uint32_t vertex;
601         int i;
602
603 #ifdef DEBUG_VERTEX
604         printf("add roof/floor's polygon at level %d:\n", level);
605 #endif
606
607         /* allocate render item */
608         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
609
610         /* set color */
611         color = m68k_read_memory_8(REG_A[0]) << 8;
612         color |= m68k_read_memory_8(REG_A[0] + 1);
613         gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
614
615         /* four vertices, one level */
616         for (i = 0; i < 4; i++) {
617                 vertex = REG_A[(2 + i)];
618                 render_item->u.interior14.vertex[i] = vertex;
619         }
620         render_item->u.interior14.level = level;
621 }
622
623 /* polygon of building (interior) */
624 static void poly_building_interior5to6(int level12, int level34)
625 {
626         uint16_t color;
627
628 #ifdef DEBUG_VERTEX
629         printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
630 #endif
631
632         /* allocate render item */
633         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
634
635         /* set color */
636         color = m68k_read_memory_8(REG_A[0]) << 8;
637         color |= m68k_read_memory_8(REG_A[0] + 1);
638         gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
639
640         /* two vertices, two levels */
641         render_item->u.interior56.vertex14 = REG_A[2];
642         render_item->u.interior56.vertex23 = REG_A[3];
643         render_item->u.interior56.level12 = level12;
644         render_item->u.interior56.level34 = level34;
645 }
646
647 /* wall part of a building */
648 static void wall_building(void)
649 {
650 #ifdef DEBUG_VERTEX
651         printf("add wall:\n");
652 #endif
653
654         /* allocate render item */
655         render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
656
657         /* set color */
658         gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
659
660         /* two vertices, two levels */
661         render_item->u.interior56.vertex14 = REG_A[1];
662         render_item->u.interior56.vertex23 = REG_A[2];
663         /* get top level according to bit 12 in D3 */
664         render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
665         render_item->u.interior56.level34 = 1;
666 }
667
668 /* coordinates ready for comet tail */
669 static void coord_comet(void)
670 {
671         int32_t x, y, z;
672
673         x = (int32_t)REG_D[3];
674         y = (int32_t)REG_D[4];
675         z = (int32_t)REG_D[5];
676         store_coord("comet tail", REG_A[0], x, y, z);
677 }
678
679 /* polygon of comet tail */
680 static void poly_comet(void)
681 {
682         uint16_t color;
683         uint32_t vertex_address = REG_A[0];
684         uint32_t vertex;
685         int i;
686
687 #ifdef DEBUG_VERTEX
688         printf("add comet's polygon:\n");
689 #endif
690
691         /* allocate render item */
692         render_item_add(RENDER_ITEM_COMET_POLYGON);
693
694         /* set color */
695         color = m68k_read_memory_8(vertex_address++) << 8;
696         color |= m68k_read_memory_8(vertex_address++);
697         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
698
699         /* the vertex list is zero-terminated */
700         for (i = 0; i < MAX_POLYGON; i++) {
701                 vertex = m68k_read_memory_8(vertex_address++);
702                 if (vertex == 0 && i)
703                         break;
704                 render_item->u.polygon.vertex[i] = vertex;
705         }
706         render_item->u.polygon.vertices = i;
707 }
708
709 /* coordinates ready for lines of a road / ground surface */
710 static void coord_line_road(void)
711 {
712         int32_t x, y, z;
713
714         x = REG_D[3];
715         mercenary_get_height(&y);
716         y = -y;
717         z = REG_D[5];
718         store_coord("road", REG_A[0], x, y, z);
719 }
720
721 /* line of road */
722 static void line_road(void)
723 {
724         uint32_t vertex;
725
726 #ifdef DEBUG_VERTEX
727         printf("add road's line:\n");
728 #endif
729
730         /* allocate render item */
731         render_item_add(RENDER_ITEM_ROAD_LINE);
732
733         /* set color */
734         gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
735
736         /* two vertices */
737         vertex = REG_A[1];
738         render_item->u.line.vertex[0] = vertex;
739         vertex = REG_A[2];
740         render_item->u.line.vertex[1] = vertex;
741 }
742
743 /* coordinates ready for polygons of a road / ground surface */
744 static void coord_poly_road(void)
745 {
746         int32_t x, y, z;
747
748 //      puts("road");
749         x = m68k_read_memory_32(320 + REG_A[0]);
750         x -= REG_A[1];
751         /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
752         mercenary_get_height(&y);
753         y = -y;
754         z = m68k_read_memory_32(576 + REG_A[0]);
755         z -= REG_A[3];
756         store_coord("road/place", REG_A[0], x, y, z);
757 }
758
759 /* polygon of road */
760 static void poly_road()
761 {
762         uint16_t color;
763         uint32_t vertex_address = REG_A[0];
764         uint32_t vertex;
765         int i;
766
767 #ifdef DEBUG_VERTEX
768         printf("add road/place's polygon:\n");
769 #endif
770
771         /* allocate render item */
772         render_item_add(RENDER_ITEM_ROAD_POLYGON);
773
774         /* set color */
775         color = m68k_read_memory_8(vertex_address++) << 8;
776         color |= m68k_read_memory_8(vertex_address++);
777         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
778
779         /* the vertex list is zero-terminated */
780         for (i = 0; i < MAX_POLYGON; i++) {
781                 vertex = m68k_read_memory_8(vertex_address++);
782                 if (vertex == 0 && i)
783                         break;
784                 render_item->u.polygon.vertex[i] = vertex;
785         }
786         render_item->u.polygon.vertices = i;
787 }
788
789 /* coordinates ready for tags */
790 static void coord_tags(void)
791 {
792         int32_t x, y, z;
793
794         x = (int16_t)REG_D[3];
795         x += (int32_t)REG_A[1];
796         y = (int16_t)REG_D[4];
797         y += (int32_t)REG_A[2];
798         z = (int16_t)REG_D[5];
799         z += (int32_t)REG_A[3];
800         store_coord("tags", REG_A[0], x, y, z);
801 }
802
803 /* coordinates ready for large tags */
804 static void coord_tags2(void)
805 {
806         int32_t x, y, z;
807
808         x = (int16_t)REG_D[3];
809         x += 2 * (int32_t)REG_A[1];
810         y = (int16_t)REG_D[4];
811         y += 2 * (int32_t)REG_A[2];
812         z = (int16_t)REG_D[5];
813         z += 2 * (int32_t)REG_A[3];
814         store_coord("large tags", REG_A[0], x, y, z);
815 }
816
817 /* line of tag */
818 static void line_tags(int last_color)
819 {
820         uint32_t vertex_address = REG_A[0];
821         uint32_t vertex;
822
823 #ifdef DEBUG_VERTEX
824         printf("add tag's line:\n");
825 #endif
826
827         /* allocate render item */
828         render_item_add(RENDER_ITEM_TAG_LINE);
829
830         /* set color */
831         if (!last_color)
832                 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
833         else
834                 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
835
836         /* two vertices */
837         vertex = m68k_read_memory_8(vertex_address++);
838         render_item->u.line.vertex[0] = vertex | 0x200;
839         vertex = m68k_read_memory_8(vertex_address++);
840         render_item->u.line.vertex[1] = vertex | 0x200;
841 }
842
843 /* polygon of tags */
844 static void poly_tags(int last_color)
845 {
846         uint32_t vertex_address = REG_A[0];
847         uint32_t vertex;
848         int i;
849
850 #ifdef DEBUG_VERTEX
851         printf("add tag's polygon:\n");
852 #endif
853
854         /* allocate render item */
855         render_item_add(RENDER_ITEM_TAG_POLYGON);
856
857         /* set color */
858         if (!last_color)
859                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
860         else
861                 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
862         /* the vertex list is zero-terminated */
863         for (i = 0; i < MAX_POLYGON; i++) {
864                 vertex = m68k_read_memory_8(vertex_address++);
865                 if (vertex == 0 && i)
866                         break;
867                 render_item->u.polygon.vertex[i] = vertex | 0x200;
868         }
869         render_item->u.polygon.vertices = i;
870 }
871
872 /* coordinates ready for planet */
873 static void coord_planet(void)
874 {
875         int32_t x, y, z;
876
877         x = (int32_t)REG_D[3];
878         y = (int32_t)REG_D[4];
879         z = (int32_t)REG_D[5];
880         store_coord("planet", REG_A[0], x, y, z);
881 }
882
883 /* planet */
884 static void draw_planet(int comet)
885 {
886         uint32_t vertex;
887         uint32_t scale_index;
888         double scale1, scale2;
889
890         vertex = REG_A[0];
891
892         /* fixing (not noticable) bug in game: don't render comet twice */
893         if (!comet && vertex == 116)
894                 return;
895
896 #ifdef DEBUG_VERTEX
897         printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
898 #endif
899
900         /* allocate render item */
901         render_item_add(RENDER_ITEM_PLANET);
902
903         /* set color */
904         if (comet) {
905                 /* make comet black on front side and bright on back */
906                 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
907                 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
908
909         } else {
910                 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
911                 /* use background color for dark side */
912                 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
913         }
914
915         /* set vertex */
916         render_item->u.planet.vertex = vertex;
917
918         /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
919          * the long word 21584(A0) contains two scales
920          * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
921          * the upper word defines how much this scale is shifted to the left.
922          */
923         scale_index = mercenary_planet_scale_index();
924         scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
925         scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
926         render_item->u.planet.size = scale1 * scale2 / 128.0;
927 }
928
929 /* stars */
930 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
931 {
932 #ifdef DEBUG_VERTEX
933         printf("add stars\n");
934 #endif
935
936         /* allocate render item */
937         render_item_add(RENDER_ITEM_STARS);
938
939         /* vertical offset */
940         render_item->u.stars.v_offset = v_offset;
941
942         /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
943         render_item->u.stars.tilt = tilt;
944         if (tilt)
945                 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
946
947         /* stars above zenith */
948         render_item->u.stars.above_zenith = above_zenith;
949 }
950
951 /* stars of interstellar flight */
952 static void draw_stars_interstellar(void)
953 {
954         int i, count;
955         uint32_t table;
956
957 #ifdef DEBUG_VERTEX
958         printf("add interstellar stars\n");
959 #endif
960
961         /* allocate render item */
962         render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
963
964         table = REG_A[0];
965         count = REG_D[5] + 1;
966         if (count > MAX_INTERSTARS) {
967                 print_error("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
968                 return;
969         }
970         for (i = 0; i < count; i++) {
971                 table += 12;
972                 /* get color */
973                 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
974                 table += 2;
975                 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
976                 table += 2;
977                 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
978                 table += 2;
979         }
980         render_item->u.interstars.count = count;
981 }
982
983 /* sun of interstellar flight (center dot) */
984 static void draw_sun_interstellar(void)
985 {
986 #ifdef DEBUG_VERTEX
987         printf("add interstellar sun\n");
988 #endif
989
990         /* allocate render item */
991         render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
992 }
993
994 /* coordinates ready for polygons of islands */
995 static void coord_islands(void)
996 {
997         int32_t x, y, z;
998
999         x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1000         x += (int32_t)REG_A[1];
1001         /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1002         mercenary_get_height(&y);
1003         y = -y;
1004         z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1005         z += (int32_t)REG_A[3];
1006         store_coord("island", REG_A[0], x, y, z);
1007 }
1008
1009 /* polygon of island */
1010 static void poly_island()
1011 {
1012         uint16_t color;
1013         uint32_t vertex_address = REG_A[0];
1014         uint32_t vertex;
1015         int i;
1016
1017 #ifdef DEBUG_VERTEX
1018         printf("add island:\n");
1019 #endif
1020
1021         /* allocate render item */
1022         render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1023
1024         /* set color */
1025         color = m68k_read_memory_8(vertex_address++) << 8;
1026         color |= m68k_read_memory_8(vertex_address++);
1027         gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1028
1029         /* the vertex list is zero-terminated */
1030         i = 0;
1031         while (i < MAX_POLYGON) {
1032                 vertex = m68k_read_memory_8(vertex_address++);
1033                 if (vertex == 0 && i)
1034                         break;
1035                 /* skip mysterious points when rendering island */
1036                 if (vertex >= 0xf0)
1037                         continue;
1038                 render_item->u.polygon.vertex[i] = vertex;
1039                 i++;
1040         }
1041         render_item->u.polygon.vertices = i;
1042 }
1043
1044 /* sights */
1045 static void draw_sights(void)
1046 {
1047 #ifdef DEBUG_VERTEX
1048         printf("add sights:\n");
1049 #endif
1050
1051         /* allocate render item */
1052         render_item_add(RENDER_ITEM_SIGHTS);
1053 }
1054
1055 /* stop event from CPU received */
1056 void render_capture_event(int event)
1057 {
1058         switch (event) {
1059         case STOP_AT_CLEAR_SCREEN1:
1060                 clear_screen(16); /* color 16 is raster split */
1061                 break;
1062         case STOP_AT_CLEAR_SCREEN2:
1063                 clear_screen(15);
1064                 break;
1065         case STOP_AT_CLEAR_SCREEN3:
1066                 clear_screen(-1); /* no ground (in universe) */
1067                 break;
1068         case STOP_AT_DRAW_GROUND:
1069                 draw_ground();
1070                 break;
1071         case STOP_AT_COORD_OBJECT:
1072                 coord_object();
1073                 break;
1074         case STOP_AT_POLY_OBJECT_M3:
1075                 poly_object(3);
1076                 break;
1077         case STOP_AT_POLY_OBJECT_M2:
1078                 poly_object(2);
1079                 break;
1080         case STOP_AT_LINE_OBJECT:
1081                 line_object();
1082                 break;
1083         case STOP_AT_COORD_BEACON:
1084                 coord_beacon();
1085                 break;
1086         case STOP_AT_POINT_BEACON:
1087                 point_beacon();
1088                 break;
1089         case STOP_AT_COORD_BUILDING_EXTERIOR:
1090                 coord_building_exterior();
1091                 break;
1092         case STOP_AT_POLY_BUILDING_EXTERIOR:
1093                 poly_building_exterior();
1094                 break;
1095         case STOP_AT_LINE_BUILDING_EXTERIOR:
1096                 line_building_exterior();
1097                 break;
1098         case STOP_AT_COORD_BUILDING_INTERIOR:
1099                 coord_building_interior();
1100                 break;
1101         case STOP_AT_POLY_BUILDING_INTERIOR1:
1102                 /* floor */
1103                 interior_level12 = 1;
1104                 interior_level34 = 1;
1105                 break;
1106         case STOP_AT_POLY_BUILDING_INTERIOR2:
1107                 /* ceiling */
1108                 interior_level12 = 2;
1109                 interior_level34 = 2;
1110                 break;
1111         case STOP_AT_POLY_BUILDING_INTERIOR3:
1112                 /* door/window top */
1113                 interior_level12 = 3;
1114                 interior_level34 = 3;
1115                 break;
1116         case STOP_AT_POLY_BUILDING_INTERIOR4:
1117                 /* window bottom */
1118                 interior_level12 = 4;
1119                 interior_level34 = 4;
1120                 break;
1121         case STOP_AT_POLY_BUILDING_INTERIOR5:
1122                 /* door/window top */
1123                 interior_level12 = 2;
1124                 interior_level34 = 3;
1125                 break;
1126         case STOP_AT_POLY_BUILDING_INTERIOR6:
1127                 /* window bottom */
1128                 interior_level12 = 1;
1129                 interior_level34 = 4;
1130                 break;
1131         case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1132                 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1133                 if (interior_level12 == 0) {
1134                         print_error("Interior level is not set, please fix!\n");
1135                         break;
1136                 }
1137                 poly_building_interior1to4(interior_level12);
1138                 interior_level12 = 0;
1139                 break;
1140         case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1141                 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1142                 if (interior_level12 == 0) {
1143                         print_error("Interior level is not set, please fix!\n");
1144                         break;
1145                 }
1146                 poly_building_interior5to6(interior_level12, interior_level34);
1147                 interior_level12 = 0;
1148                 break;
1149         case STOP_AT_WALL_BUILDING:
1150                 wall_building();
1151                 break;
1152         case STOP_AT_COORD_COMET:
1153                 coord_comet();
1154                 break;
1155         case STOP_AT_MATRIX_COMET:
1156         case STOP_AT_MATRIX_PLANET:
1157                 /* track the rotation matrix
1158                  * if we have 0x42c44 matrix, we must add extra rotation to planet.
1159                  * the rotation will change the view from the planet's surface */
1160                 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1161                         planet_rotation = 1;
1162                 else
1163                         planet_rotation = 0;
1164                 break;
1165         case STOP_AT_POLY_COMET:
1166                 poly_comet();
1167                 break;
1168         case STOP_AT_COORD_LINE_ROADS:
1169                 coord_line_road();
1170                 break;
1171         case STOP_AT_LINE_ROADS:
1172                 line_road();
1173                 break;
1174         case STOP_AT_COORD_POLY_ROADS:
1175                 coord_poly_road();
1176                 break;
1177         case STOP_AT_LINE_ROADS_CENTER:
1178                 /* we don't need to render center lines of roads, because there are polygons already
1179                  * it does not make sense, since OpenGL has much higher resolution.
1180                  */
1181                 break;
1182         case STOP_AT_POLY_ROADS:
1183                 poly_road();
1184                 break;
1185         case STOP_AT_COORD_TAGS:
1186                 coord_tags();
1187                 break;
1188         case STOP_AT_COORD_TAGS2:
1189                 coord_tags2();
1190                 break;
1191         case STOP_AT_LINE_TAGS1:
1192                 line_tags(0);
1193                 break;
1194         case STOP_AT_LINE_TAGS2:
1195                 line_tags(1);
1196                 break;
1197         case STOP_AT_POLY_TAGS1:
1198                 poly_tags(0);
1199                 break;
1200         case STOP_AT_POLY_TAGS2:
1201                 poly_tags(1);
1202                 break;
1203         case STOP_AT_COORD_PLANET:
1204                 coord_planet();
1205                 break;
1206         case STOP_AT_DRAW_PLANET:
1207                 draw_planet(0);
1208                 break;
1209         case STOP_AT_DRAW_COMET:
1210                 draw_planet(1);
1211                 break;
1212         case STOP_AT_DRAW_STARS_SPACE:
1213                 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1214                 draw_stars(0x1c0, 0, 0);
1215                 break;
1216         case STOP_AT_DRAW_STARS_GROUND:
1217                 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1218                 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1219                 break;
1220         case STOP_AT_DRAW_STARS_FLYING:
1221                 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1222                 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1223                 break;
1224         case STOP_AT_DRAW_STARS_FLYING2:
1225                 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1226                 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1227                 break;
1228         case STOP_AT_DRAW_STARS_INTERSTELLAR:
1229                 draw_stars_interstellar();
1230                 break;
1231         case STOP_AT_DRAW_SUN_INTERSTELLAR:
1232                 draw_sun_interstellar();
1233                 break;
1234         case STOP_AT_COORD_ISLANDS:
1235                 coord_islands();
1236                 break;
1237         case STOP_AT_POLY_ISLANDS:
1238                 poly_island();
1239                 break;
1240         case STOP_AT_LINE_ISLANDS:
1241                 /* this is not used, as i had noticed so far */
1242                 puts("line island");
1243                 break;
1244         case STOP_AT_DRAW_SIGHTS:
1245                 draw_sights();
1246                 break;
1247         case STOP_AT_POLY_UKN2:
1248                 puts("poly ukn2");
1249                 break;
1250         case STOP_AT_PLANET_UKN1:
1251                 puts("planet ukn1");
1252                 break;
1253         case STOP_AT_PLANET_UKN2:
1254                 puts("planet ukn2");
1255                 break;
1256         }
1257 }
1258
1259 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1260 {
1261         render_item_t *ri = NULL;
1262
1263         if ((vertex & 3)) {
1264                 print_error("Vertex %d is not a multiple of four!\n", vertex);
1265                 return -1;
1266         }
1267         if (vertex < 0x100) {
1268                 if (!render_item_vertices_0) {
1269                         print_error("Vertices item for vertex %d not yet set!\n", vertex);
1270                         return -1;
1271                 }
1272                 ri = render_item_vertices_0;
1273         } else
1274         if (vertex < 0x200) {
1275                 if (!render_item_vertices_1) {
1276                         print_error("Vertices item for vertex %d not yet set!\n", vertex);
1277                         return -1;
1278                 }
1279                 ri = render_item_vertices_1;
1280                 vertex -= 0x100;
1281         } else
1282         if (vertex < 0x300) {
1283                 if (!render_item_vertices_2) {
1284                         print_error("Vertices item for vertex %d not yet set!\n", vertex);
1285                         return -1;
1286                 }
1287                 ri = render_item_vertices_2;
1288                 vertex -= 0x200;
1289         } else {
1290                 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1291                 return -1;
1292         }
1293         vertex >>= 2;
1294         *x = ri->u.vertices.x[vertex];
1295         *y = ri->u.vertices.y[vertex];
1296         *z = ri->u.vertices.z[vertex];
1297 #ifdef DEBUG_VERTEX
1298         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1299 #endif
1300
1301         return 0;
1302 }
1303
1304 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1305 {
1306         if ((vertex & 3)) {
1307                 print_error("Vertex is not a multiple of four!\n");
1308                 return -1;
1309         }
1310         if (vertex >= MAX_VERTEX) {
1311                 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1312                 return -1;
1313         }
1314         if (level < 1 || level > 4) {
1315                 print_error("Level %d is out of range (1..4)!\n", level);
1316                 return -1;
1317         }
1318         if (!render_item_vertices_interior) {
1319                 print_error("Vertices item for interior verticies not yet set!\n");
1320                 return -1;
1321         }
1322         vertex >>= 2;
1323         *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1324         *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1325         *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1326 #ifdef DEBUG_VERTEX
1327         printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1328 #endif
1329
1330         return 0;
1331 }
1332
1333 /* renders one item from render list */
1334 void render_one_item(render_item_t *render_item)
1335 {
1336         switch (render_item->type) {
1337         case RENDER_ITEM_VERTICES_0:
1338         {
1339 #ifdef DEBUG_ITEMS
1340                 printf("RENDER_ITEM_VERTICES_0\n");
1341 #endif
1342                 render_item_vertices_0 = render_item;
1343                 break;
1344         }
1345         case RENDER_ITEM_VERTICES_1:
1346         {
1347 #ifdef DEBUG_ITEMS
1348                 printf("RENDER_ITEM_VERTICES_1\n");
1349 #endif
1350                 render_item_vertices_1 = render_item;
1351                 break;
1352         }
1353         case RENDER_ITEM_VERTICES_2:
1354         {
1355 #ifdef DEBUG_ITEMS
1356                 printf("RENDER_ITEM_VERTICES_2\n");
1357 #endif
1358                 render_item_vertices_2 = render_item;
1359                 break;
1360         }
1361         case RENDER_ITEM_VERTICES_INTERIOR:
1362         {
1363 #ifdef DEBUG_ITEMS
1364                 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1365 #endif
1366                 render_item_vertices_interior = render_item;
1367                 break;
1368         }
1369         case RENDER_ITEM_SKY:
1370         {
1371                 double x[4], y[4], z[4];
1372
1373 #ifdef DEBUG_ITEMS
1374                 printf("RENDER_ITEM_SKY\n");
1375 #endif
1376                 /* get color */
1377                 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1378                 /* create plane to fill view */
1379                 x[0] = x[1] = y[1] = y[2] = -1000000;
1380                 x[2] = x[3] = y[0] = y[3] = 1000000;
1381                 z[0] = z[1] = z[2] = z[3] = 10;
1382                 /* render */
1383                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sky (background) is always visible! */
1384                 break;
1385         }
1386         case RENDER_ITEM_GROUND:
1387         {
1388                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1389                 double x[4], y[4], z[4];
1390                 int i;
1391
1392 #ifdef DEBUG_ITEMS
1393                 printf("RENDER_ITEM_GROUND\n");
1394 #endif
1395                 /* get color */
1396                 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1397                 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1398                 /* create huge square */
1399                 x[0] = x[1] = z[1] = z[2] = -1000000;
1400                 x[2] = x[3] = z[0] = z[3] = 1000000;
1401                 y[0] = y[1] = y[2] = y[3] = -10;
1402                 /* rotate vertex */
1403                 for (i = 0; i < 4; i++)
1404                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1405                 /* render */
1406                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1407                 break;
1408         }
1409         case RENDER_ITEM_OBJECT_POLYGON:
1410         case RENDER_ITEM_TAG_POLYGON:
1411         case RENDER_ITEM_ISLAND_POLYGON:
1412         {
1413                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1414                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1415                 int i;
1416                 int rc;
1417
1418 #ifdef DEBUG_ITEMS
1419                 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1420                         printf("RENDER_ITEM_OBJECT_POLYGON\n");
1421                 if (render_item->type == RENDER_ITEM_TAG_POLYGON)
1422                         printf("RENDER_ITEM_TAG_POLYGON\n");
1423                 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1424                         printf("RENDER_ITEM_ISLAND_POLYGON\n");
1425 #endif
1426                 /* get color */
1427                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1428                 /* get and rotate vertex */
1429                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1430                         /* get vertex */
1431                         rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1432                         if (rc < 0)
1433                                 break;
1434                         /* rotate vertex */
1435                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1436                 }
1437                 /* render */
1438                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1439                 break;
1440         }
1441         case RENDER_ITEM_OBJECT_LINE:
1442         case RENDER_ITEM_TAG_LINE:
1443         {
1444                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1445                 double x[2], y[2], z[2];
1446                 int i;
1447                 int rc;
1448
1449 #ifdef DEBUG_ITEMS
1450                 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1451                         printf("RENDER_ITEM_OBJECT_LINE\n");
1452                 if (render_item->type == RENDER_ITEM_TAG_LINE)
1453                         printf("RENDER_ITEM_TAG_LINE\n");
1454 #endif
1455                 /* get color */
1456                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1457                 /* get and rotate vertex */
1458                 for (i = 0; i < 2; i++) {
1459                         /* get vertex */
1460                         rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1461                         if (rc < 0)
1462                                 break;
1463                         /* rotate vertex */
1464                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1465                 }
1466                 /* render */
1467                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1468                 break;
1469         }
1470         case RENDER_ITEM_BEACON_POINT:
1471         {
1472                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1473                 double x, y, z;
1474                 int rc;
1475
1476 #ifdef DEBUG_ITEMS
1477                 printf("RENDER_ITEM_BEACON_POINT\n");
1478 #endif
1479                 /* get color */
1480                 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1481                 /* get vertex */
1482                 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z);
1483                 if (rc < 0)
1484                         break;
1485                 /* rotate vertex */
1486                 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1487                 /* render */
1488                 opengl_render_point(x, y, z, 0.0);
1489                 break;
1490         }
1491         case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1492         {
1493                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1494                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1495                 int i;
1496                 int rc;
1497
1498 #ifdef DEBUG_ITEMS
1499                 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1500 #endif
1501                 /* get color */
1502                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1503                 /* get and rotate vertex */
1504                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1505                         /* get vertex */
1506                         rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1507                         if (rc < 0)
1508                                 break;
1509                         /* rotate vertex */
1510                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1511                 }
1512                 /* render */
1513                 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1514                 break;
1515         }
1516         case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
1517         {
1518                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1519                 double x[2], y[2], z[2];
1520                 int i;
1521                 int rc;
1522
1523 #ifdef DEBUG_ITEMS
1524                 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1525 #endif
1526                 /* get color */
1527                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1528                 /* get and rotate vertex */
1529                 for (i = 0; i < 2; i++) {
1530                         /* get vertex */
1531                         rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1532                         if (rc < 0)
1533                                 break;
1534                         /* rotate vertex */
1535                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1536                 }
1537                 /* render */
1538                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1539                 break;
1540         }
1541         case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1542         {
1543                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1544                 double x[4], y[4], z[4];
1545                 int i;
1546                 int rc;
1547
1548 #ifdef DEBUG_ITEMS
1549                 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1550 #endif
1551                 /* get color */
1552                 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1553                 /* get and rotate vertex */
1554                 for (i = 0; i < 4; i++) {
1555                         /* get vertex */
1556                         rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1557                         if (rc < 0)
1558                                 break;
1559                         /* rotate vertex */
1560                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1561                 }
1562                 /* render */
1563                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1564                 break;
1565         }
1566         case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1567         {
1568                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1569                 double x[4], y[4], z[4];
1570                 int i;
1571                 int vertex, level;
1572                 int rc;
1573
1574 #ifdef DEBUG_ITEMS
1575                 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1576 #endif
1577                 /* get color */
1578                 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1579                 /* get and rotate vertex */
1580                 for (i = 0; i < 4; i++) {
1581                         /* get vertex */
1582                         vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1583                         level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1584                         rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1585                         if (rc < 0)
1586                                 break;
1587                         /* rotate vertex */
1588                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1589                 }
1590                 /* render */
1591                 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1592                 break;
1593         }
1594         case RENDER_ITEM_BUILDING_INTERIOR_WALL:
1595         {
1596                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1597                 double x[4], y[4], z[4];
1598                 int i;
1599                 int vertex, level;
1600                 int rc;
1601
1602 #ifdef DEBUG_ITEMS
1603                 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
1604 #endif
1605                 /* get color */
1606                 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1607                 /* chedck if wall is a rectangle or a line */
1608                 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
1609                         /* get and rotate vertex */
1610                         for (i = 0; i < 4; i++) {
1611                                 /* get vertex */
1612                                 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1613                                 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1614                                 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1615                                 if (rc < 0)
1616                                         break;
1617                                 /* rotate vertex */
1618                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1619                         }
1620                         /* render */
1621                         opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
1622                 } else {
1623                         /* get and rotate vertex */
1624                         for (i = 0; i < 2; i++) {
1625                                 /* get vertex */
1626                                 vertex = render_item->u.interior56.vertex14;
1627                                 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1628                                 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1629                                 if (rc < 0)
1630                                         break;
1631                                 /* rotate vertex */
1632                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1633                         }
1634                         /* render */
1635                         opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1636                 }
1637                 break;
1638         }
1639         case RENDER_ITEM_COMET_POLYGON:
1640         {
1641                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1642                 double inclination = planet_inclination, azimuth = planet_azimuth;
1643                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1644                 int i;
1645                 int rc;
1646
1647 #ifdef DEBUG_ITEMS
1648                 printf("RENDER_ITEM_COMET_POLYGON\n");
1649 #endif
1650                 /* get color */
1651                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1652                 /* get and rotate vertex */
1653                 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1654                         /* get vertex */
1655                         rc = use_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1656                         if (rc < 0)
1657                                 break;
1658                         /* rotate vertex */
1659                         if (planet_rotation)
1660                                 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
1661                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1662                 }
1663                 /* render */
1664                 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
1665                 break;
1666         }
1667         case RENDER_ITEM_ROAD_LINE:
1668         {
1669                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1670                 double x[2], y[2], z[2];
1671                 int i;
1672                 int rc;
1673
1674 #ifdef DEBUG_ITEMS
1675                 printf("RENDER_ITEM_ROAD_LINE\n");
1676 #endif
1677                 /* get color */
1678                 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1679                 /* get and rotate vertex */
1680                 for (i = 0; i < 2; i++) {
1681                         /* get vertex */
1682                         rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1683                         if (rc < 0)
1684                                 break;
1685                         /* rotate vertex */
1686                         rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1687                 }
1688                 /* render */
1689                 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1690                 break;
1691         }
1692         case RENDER_ITEM_ROAD_POLYGON:
1693         {
1694                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1695                 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1696                 int i, v;
1697                 uint32_t vertex, vertex_prev, vertex_next;
1698                 double x_current, y_current, z_current;
1699                 double x_prev, y_prev, z_prev;
1700                 double x_next, y_next, z_next;
1701                 int vertices_num;
1702                 int rc;
1703
1704 #ifdef DEBUG_ITEMS
1705                 printf("RENDER_ITEM_ROAD_POLYGON\n");
1706 #endif
1707                 /* get color */
1708                 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1709                 /* get and rotate vertex */
1710                 i = 0;
1711                 vertices_num = render_item->u.polygon.vertices;
1712                 for (v = 0; v < vertices_num; v++) {
1713                         /* get vertex */
1714                         vertex = render_item->u.polygon.vertex[v];
1715                         rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current);
1716                         if (rc < 0)
1717                                 break;
1718                         /* check for road extension, so we extend the road to the given end point */
1719                         if (extend_roads && vertex >= 0xf0) {
1720                                 /* previous vertex */
1721                                 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
1722                                 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev);
1723                                 if (rc < 0)
1724                                         break;
1725                                 /* next vertex */
1726                                 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
1727                                 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next);
1728                                 if (rc < 0)
1729                                         break;
1730                                 /* extend vertices to end point position
1731                                  * change x or z coordinate, whatever is greater
1732                                 */
1733                                 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
1734                                         x_prev = x_next = x_current;
1735                                 else
1736                                         z_prev = z_next = z_current;
1737                                 /* store vertices */
1738                                 x[i] = x_prev;
1739                                 y[i] = y_prev;
1740                                 z[i] = z_prev;
1741                                 /* rotate vertex */
1742                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1743                                 if (i++ == MAX_POLYGON)
1744                                         break;
1745                                 x[i] = x_next;
1746                                 y[i] = y_next;
1747                                 z[i] = z_next;
1748                                 /* rotate vertex */
1749                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1750                                 if (i++ == MAX_POLYGON)
1751                                         break;
1752                                 continue;
1753                         } else {
1754                                 /* no extension, just keep the current point as is */
1755                                 x[i] = x_current;
1756                                 y[i] = y_current;
1757                                 z[i] = z_current;
1758                                 /* rotate vertex */
1759                                 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1760                                 if (i++ == MAX_POLYGON)
1761                                         break;
1762                         }
1763                 }
1764                 /* render */
1765                 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
1766                 break;
1767         }
1768         case RENDER_ITEM_PLANET:
1769         {
1770                 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1771                 double inclination = planet_inclination, azimuth = planet_azimuth;
1772                 double sun_x, sun_y, sun_z, angle_sun;
1773                 double loc_x, loc_y, loc_z, angle_loc;
1774                 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
1775                 double size, angle;
1776                 int i;
1777                 int rc;
1778
1779 #ifdef DEBUG_ITEMS
1780                 printf("RENDER_ITEM_PLANET\n");
1781 #endif
1782                 /* get location */
1783                 rc = use_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
1784                 if (rc < 0)
1785                         break;
1786                 rc = use_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
1787                 if (rc < 0)
1788                         break;
1789                 /* get size */
1790                 size = render_item->u.planet.size;
1791                 /* rotate vertex */
1792                 if (planet_rotation) {
1793                         rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
1794                         rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
1795                 }
1796                 rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
1797                 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
1798
1799                 /* calculate direction of the sun */
1800                 angle_sun = atan2(sun_x, sun_z);
1801                 angle_loc = atan2(loc_x, loc_z);
1802                 angle = angle_sun - angle_loc;
1803                 if (angle > M_PI)
1804                         angle -= 2.0 * M_PI;
1805                 if (angle < -M_PI)
1806                         angle += 2.0 * M_PI;
1807
1808                 /* on which side are we (sun is always bright, vertex == 0) */
1809                 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
1810                         /* get front side color */
1811                         opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
1812                 } else {
1813                         /* get back side color */
1814                         opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
1815                 }
1816
1817                 /* create and render cicle */
1818                 for (i = 0; i < PLANET_VERTICES; i++) {
1819                         x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1820                         y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1821                         z[i] = loc_z;
1822                 }
1823                 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
1824
1825                 if (render_item->u.planet.vertex == 0) {
1826                         /* sun has no crescent */
1827                         break;
1828                 }
1829
1830                 /* on which side are we */
1831                 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
1832                         /* get back side color */
1833                         opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
1834                 } else {
1835                         /* get front side color */
1836                         opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
1837                 }
1838
1839                 /* create and render crescent */
1840                 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
1841                         angle = fabs(angle);
1842                         if (angle > M_PI / 2.0)
1843                                 angle = M_PI - angle;
1844                         /* to the right */
1845                         for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
1846                                 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1847                                 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1848                                 z[i] = loc_z;
1849                         }
1850                         for (; i < PLANET_VERTICES; i++) {
1851                                 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
1852                                 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1853                                 z[i] = loc_z;
1854                         }
1855                 } else {
1856                         angle = fabs(angle);
1857                         if (angle > M_PI / 2.0)
1858                                 angle = M_PI - angle;
1859                         /* to the left */
1860                         for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
1861                                 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
1862                                 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1863                                 z[i] = loc_z;
1864                         }
1865                         for (; i < PLANET_VERTICES; i++) {
1866                                 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1867                                 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1868                                 z[i] = loc_z;
1869                         }
1870                 }
1871                 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
1872                 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point  */
1873                 break;
1874         }
1875         case RENDER_ITEM_STARS:
1876         {
1877                 int16_t tilt_offset = 0;
1878                 int x_offset = 0;
1879                 uint16_t color[16];
1880                 uint16_t view_width, yaw = orientation_raw_yaw;
1881                 int16_t pitch = orientation_raw_pitch;
1882                 uint32_t table, table_start;
1883                 int16_t x, y;
1884                 double z;
1885                 int i;
1886                 double red, green, blue;
1887
1888 #ifdef DEBUG_ITEMS
1889                 printf("RENDER_ITEM_STARS\n");
1890 #endif
1891                 /* use default fov of 64 to calculate z distance */
1892                 z = 160.0 / frustum_slope_64;
1893
1894                 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
1895
1896                 /* get palette */
1897                 for (i = 0; i < 16; i++)
1898                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
1899
1900                 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
1901                  * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
1902                  * then we half it, so we get to the center via 91
1903                  */
1904
1905                 if (render_item->u.stars.above_zenith)
1906                         yaw = 0x200 + yaw;
1907                 yaw = (yaw + 91 - (int)(91.0 * (frustum_slope_fov / frustum_slope_64))) & 0x3ff;
1908                 yaw <<= 1;
1909                 table = mercenary_star_table();
1910                 table_start = table + m68k_read_memory_16(table);
1911                 table += m68k_read_memory_16(table + yaw);
1912                 yaw = ((uint32_t)yaw * 0xe10e) >> 16;
1913
1914                 if (render_item->u.stars.above_zenith)
1915                         pitch = 0x200 - pitch;
1916                 pitch = pitch & 0x3ff;
1917                 pitch -= render_item->u.stars.v_offset;
1918                 pitch <<= 2;
1919                 pitch = (pitch * 0x6ccc) >> 16;
1920
1921                 while (1) {
1922                         x = m68k_read_memory_16(table);
1923                         if (x >= 1800) {
1924                                 x_offset += 1800;
1925                                 table = table_start;
1926                         }
1927                         x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
1928                         table += 2;
1929                         if (x < 0)
1930                                 break;
1931                         /* special case where we tilt the view when flying on the planet */
1932                         if (render_item->u.stars.tilt) {
1933                                 /* use offset as given by game: 160 is half of the screen width
1934                                  * we extend the width to the actual FOV, so it fits
1935                                  */
1936                                 tilt_offset = (int32_t)((x - (int16_t)(160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) >> 16;
1937                         }
1938                         y = ((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
1939                         table += 2;
1940                         if (render_item->u.stars.above_zenith) {
1941                                 x = (view_width - 1) - x;
1942                                 y = ~y + 136;
1943                         }
1944                         /* get color */
1945                         gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
1946                         opengl_render_color(red, green, blue, debug_opacity);
1947                         /* render point */
1948                         opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - (double)x, 68.0 - (double)y, z, 0.0);
1949                 }
1950                 break;
1951         }
1952         case RENDER_ITEM_INTERSTELLAR_STARS:
1953         {
1954                 uint16_t color[16];
1955                 double z;
1956                 int i;
1957                 double red, green, blue;
1958
1959 #ifdef DEBUG_ITEMS
1960                 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
1961 #endif
1962                 /* use default fov of 64 to calculate z distance */
1963                 z = 160.0 / frustum_slope_64;
1964
1965                 /* get palette */
1966                 for (i = 0; i < 16; i++)
1967                         color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
1968
1969                 for (i = 0; i < render_item->u.interstars.count; i++) {
1970                         gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
1971                         opengl_render_color(red, green, blue, debug_opacity);
1972                         /* render point */
1973                         opengl_render_point(160.0 - (double)render_item->u.interstars.x[i], 68.0 - (double)render_item->u.interstars.y[i], z, 0.0);
1974                 }
1975                 break;
1976         }
1977         case RENDER_ITEM_INTERSTELLAR_SUN:
1978         {
1979                 double red, green, blue;
1980
1981 #ifdef DEBUG_ITEMS
1982                 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
1983 #endif
1984                 /* white */
1985                 gamecolor2gl(&red, &green, &blue, 0x777);
1986                 opengl_render_color(red, green, blue, debug_opacity);
1987                 /* render point */
1988                 opengl_render_point(0.0, 0.0, 100.0, 0.0);
1989                 break;
1990         }
1991         case RENDER_ITEM_SIGHTS:
1992         {
1993                 double x[4], y[4], z[4];
1994                 double red, green, blue;
1995
1996 #ifdef DEBUG_ITEMS
1997                 printf("RENDER_ITEM_SIGHTS\n");
1998 #endif
1999                 /* use default fov of 64 to calculate z distance */
2000                 z[0] = z[1] = z[2] = z[3] = 160.0 / frustum_slope_64;
2001
2002                 /* white */
2003                 gamecolor2gl(&red, &green, &blue, 0x777);
2004                 opengl_render_color(red, green, blue, debug_opacity);
2005
2006                 y[0] = y[3] = -1.0;
2007                 y[1] = y[2] = 1.0;
2008                 x[0] = x[1] = -16.0;
2009                 x[2] = x[3] = -8.0;
2010                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2011                 x[0] = x[1] = 8.0;
2012                 x[2] = x[3] = 16.0;
2013                 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2014                 break;
2015         }
2016         default:
2017                 print_error("Unknown type, please fix!\n");
2018         }
2019 }
2020
2021 void render_all_items()
2022 {
2023         render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2024         render_item_vertices_interior = NULL;
2025
2026         for (render_item = render_list_start; render_item; render_item = render_item->next) {
2027                 render_one_item(render_item);
2028         }
2029 }
2030