1 /* render routines that replaces the game rendering by OpenGL rendering
3 * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
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.
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.
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/>.
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
41 #include "../libsdl/print.h"
42 #include "../libcpu/m68k.h"
43 #include "../libcpu/m68kcpu.h"
44 #include "../libcpu/execute.h"
45 #include "../libopengl/opengl.h"
46 #include "mercenary.h"
48 #define GL3_PROTOTYPES 1
52 //#define DEBUG_VERTEX
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_STRETCH 1.19 /* stretch horizontally (this compensates NTSC/PAL line ratio of 625/525)*/
63 #define EXPLOSION_VERTICES 16
64 #define EXPLOSION_STRETCH 1.19 /* as above */
65 #define SIGHT_DIST 78.74 /* distanc of sights in inch */
66 #define FIX_OBJECT_SCALE 16 /* intercity... */
67 #define FIX_OBJECT_SCALE_TAG 2 /* line in faces of persons */
70 * render item definition and structures
74 enum render_item_type {
75 RENDER_ITEM_OBJECT_INFO,
76 RENDER_ITEM_VERTICES_0,
77 RENDER_ITEM_VERTICES_1,
78 RENDER_ITEM_VERTICES_2,
79 RENDER_ITEM_VERTICES_INTERIOR,
82 RENDER_ITEM_OBJECT_POLYGON,
83 RENDER_ITEM_OBJECT_LINE,
84 RENDER_ITEM_BEACON_POINT,
85 RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
86 RENDER_ITEM_BUILDING_EXTERIOR_LINE,
87 RENDER_ITEM_BUILDING_INTERIOR_1TO4,
88 RENDER_ITEM_BUILDING_INTERIOR_5TO6,
89 RENDER_ITEM_BUILDING_INTERIOR_WALL,
90 RENDER_ITEM_COMET_POLYGON,
91 RENDER_ITEM_ROAD_LINE,
92 RENDER_ITEM_ROAD_POLYGON,
93 RENDER_ITEM_TAG_LINE_OBJECT,
94 RENDER_ITEM_TAG_LINE_OTHER,
95 RENDER_ITEM_TAG_POLYGON_OBJECT,
96 RENDER_ITEM_TAG_POLYGON_OTHER,
99 RENDER_ITEM_INTERSTELLAR_STARS,
100 RENDER_ITEM_INTERSTELLAR_SUN,
101 RENDER_ITEM_ISLAND_POLYGON,
103 RENDER_ITEM_EXPLOSION,
106 struct render_item_info {
109 int32_t east, height, north;
112 struct render_item_vertices {
113 double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
116 struct render_item_vertices_interior {
117 uint8_t set[MAX_INTERIOR_VERTEX >> 2];
118 double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
121 struct render_item_sky {
122 double red, green, blue;
125 struct render_item_ground {
126 double red, green, blue;
129 struct render_item_polygon {
130 double red, green, blue;
132 int vertex[MAX_POLYGON];
135 struct render_item_interior14 {
136 double red, green, blue;
141 struct render_item_interior56 {
142 double red, green, blue;
149 struct render_item_line {
150 double red, green, blue;
154 struct render_item_point {
155 double red, green, blue;
159 struct render_item_planet {
160 double front_red, front_green, front_blue;
161 double back_red, back_green, back_blue;
166 struct render_item_stars {
173 struct render_item_interstars {
174 uint8_t color[MAX_INTERSTARS];
175 int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
179 struct render_item_explosion {
180 double red, green, blue;
181 int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
182 double size[MAX_EXPLOSION];
186 typedef struct render_item {
187 struct render_item *next;
188 enum render_item_type type;
190 struct render_item_info info;
191 struct render_item_vertices vertices;
192 struct render_item_vertices_interior vertices_interior;
193 struct render_item_sky sky;
194 struct render_item_ground ground;
195 struct render_item_polygon polygon;
196 struct render_item_line line;
197 struct render_item_point point;
198 struct render_item_interior14 interior14;
199 struct render_item_interior56 interior56;
200 struct render_item_planet planet;
201 struct render_item_stars stars;
202 struct render_item_interstars interstars;
203 struct render_item_explosion explosion;
207 /* information about motion in each game rendering */
208 typedef struct motion {
209 int32_t position_east, position_height, position_north;
210 double orientation_roll, orientation_pitch, orientation_yaw;
211 uint16_t orientation_raw_yaw;
212 int16_t orientation_raw_pitch;
214 double planet_inclination, planet_azimuth;
217 /* information about interpolation between two game renedrings */
218 typedef struct interpolation {
219 double offset_east, offset_height, offset_north;
220 double orientation_roll, orientation_pitch, orientation_yaw;
221 double orientation_raw_yaw, orientation_raw_pitch;
222 double planet_inclination, planet_azimuth;
223 int object_id[MAX_MOVING_OBJECTS];
224 double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
226 render_item_t *interior;
227 render_item_t *planets;
230 #define GET_ORIENTATION \
231 double roll = interpolation.orientation_roll; \
232 double pitch = interpolation.orientation_pitch; \
233 double yaw = interpolation.orientation_yaw
235 #define GET_ORIENTATION_FIX \
236 roll = motion_new.orientation_roll; \
237 pitch = motion_new.orientation_pitch; \
238 yaw = motion_new.orientation_yaw
240 /* rendering options */
241 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
242 static int improve_stars; /* stars are rendered spherical */
243 static int fix_sky_rotation; /* sky will rotate correctly by rotating planets/comet by 180 degrees */
244 static double planet_aspect, explosion_aspect; /* aspect ratio */
246 static double debug_opacity;
247 static double frustum_slope_64, frustum_slope_fov;
249 /* states while collecting render items */
250 static motion_t motion_old, motion_new;
251 static int32_t old_height_offset = 0, new_height_offset = 0;
252 static interpolation_t interpolation;
253 static int ground_index, last_ground_index = -1;
254 static int interior_level12 = 0;
255 static int interior_level34 = 0;
256 static int tag_is_object;
257 /* current render item list */
258 static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
259 /* previous render item list */
260 static render_item_t *render_list_old = NULL;
261 /* current item to be processed */
262 static render_item_t *render_item;
263 /* current object info */
264 static render_item_t *render_item_object_info;
265 /* current vertices */
266 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
267 static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
273 static void render_item_add(enum render_item_type type)
275 render_item = calloc(1, sizeof(render_item_t));
277 print_error("No memory, must abort!\n");
280 render_item->type = type;
281 *render_list_end = render_item;
282 render_list_end = &render_item->next;
285 static void flush_old_items(void)
287 /* flush old render list */
288 while (render_list_old) {
289 render_item = render_list_old;
290 render_list_old = render_list_old->next;
295 /* rendering starts, initialize variables */
296 void render_capture_start(double _fov, int _extend_roads, int _smooth_planets, int _improve_stars, int _fix_sky_rotation, int _round_planets, int debug)
298 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
299 printf("start rendering a new frame...\n");
304 /* move new render list to old render list */
305 render_list_old = render_list_new;
306 /* setup new render list */
307 render_list_new = NULL;
308 render_list_end = &render_list_new;
310 /* move new motion to old motion */
311 memcpy(&motion_old, &motion_new, sizeof(motion_old));
313 /* set rendering options */
315 extend_roads = _extend_roads;
316 fix_sky_rotation = _fix_sky_rotation;
317 improve_stars = _improve_stars;
318 planet_aspect = (_round_planets) ? 1.0 : PLANET_STRETCH;
319 explosion_aspect = (_round_planets) ? 1.0 : EXPLOSION_STRETCH;
320 /* set some transpareny, if debugging is enabled */
321 debug_opacity = (debug) ? 0.5 : 1.0;
323 /* calculate slope of 64 degree frustum and current FOV's frustum */
324 frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
325 frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
328 mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
329 /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
330 mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
331 mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
332 motion_new.planet_rotation = motion_old.planet_rotation;
333 mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth, _smooth_planets);
335 render_item_object_info = NULL;
336 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
337 render_item_vertices_planets = NULL;
338 render_item_vertices_interior = NULL;
340 /* detect elevator movement */
341 old_height_offset = new_height_offset;
343 new_height_offset = motion_new.position_height - motion_old.position_height;
345 /* detect switching between space (-1) and over ground (>=0) */
346 last_ground_index = ground_index;
352 void render_capture_stop(void)
354 /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
355 if (!render_list_new) {
356 render_list_new = render_list_old;
357 render_list_end = &render_list_new;
358 render_list_old = NULL;
363 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
368 /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
370 palette = mercenary_palette_render();
371 color = m68k_read_memory_16(palette + index);
373 printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
375 if (color >= 0x8000) {
377 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
380 *red = (double)((color >> 8) & 0xf) / 15.0;
381 *green = (double)((color >> 4) & 0xf) / 15.0;
382 *blue = (double)(color & 0xf) / 15.0;
385 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
392 printf("color is given as 0x%04x\n", color);
395 /* color conversion: see for example M3: 0x4f830 */
396 if (color < 0x8000) {
397 /* use given color but shift it left by 1 */
400 printf("using given color, color is now 0x%04x\n", color);
402 } else if ((color & 0xff) < 0x80) {
403 gamecolor2gl_index(red, green, blue, color & 0xf);
406 /* use given index from pre-defined palette */
407 index = color & 0x7e;
408 palette = mercenary_palette_predefined();
409 color = m68k_read_memory_16(palette + index);
411 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
413 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
414 if (nesting++ == 8) {
415 print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
420 *red = (double)((color >> 8) & 0xf) / 15.0;
421 *green = (double)((color >> 4) & 0xf) / 15.0;
422 *blue = (double)(color & 0xf) / 15.0;
425 static int32_t wrap_int28(int32_t value)
432 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z, double scale)
435 print_info("Vertex %d is not a multiple of four!\n", vertex);
438 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
439 if (vertex < 0x100) {
440 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
441 render_item_add(RENDER_ITEM_VERTICES_0);
442 /* copy vertices that have been captured already */
443 if (render_item_vertices_0)
444 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
445 render_item_vertices_0 = render_item;
448 if (vertex < 0x200) {
449 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
450 render_item_add(RENDER_ITEM_VERTICES_1);
451 /* copy vertices that have been captured already */
452 if (render_item_vertices_1)
453 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
454 render_item_vertices_1 = render_item;
458 if (vertex < 0x300) {
459 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
460 render_item_add(RENDER_ITEM_VERTICES_2);
461 /* copy vertices that have been captured already */
462 if (render_item_vertices_2)
463 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
464 render_item_vertices_2 = render_item;
468 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
473 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
475 /* use absolute position */
476 render_item->u.vertices.x[vertex] = (double)x * scale + motion_new.position_east;
477 render_item->u.vertices.y[vertex] = (double)y * scale + motion_new.position_height;
478 render_item->u.vertices.z[vertex] = (double)z * scale + motion_new.position_north;
481 static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
484 print_info("Vertex %d is not a multiple of four!\n", vertex);
487 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
488 if (vertex >= MAX_VERTEX) {
489 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
492 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
493 render_item_add(RENDER_ITEM_VERTICES_0);
494 /* copy vertices that have been captured already */
495 if (render_item_vertices_0)
496 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
497 render_item_vertices_0 = render_item;
501 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
503 render_item->u.vertices.x[vertex] = x;
504 render_item->u.vertices.y[vertex] = y;
505 render_item->u.vertices.z[vertex] = z;
508 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)
511 print_info("Vertex is not a multiple of four!\n");
514 if (vertex >= MAX_INTERIOR_VERTEX) {
515 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
518 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
519 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
522 printf("storing %s coordinates: vertex=%d, x=%d, y=%d;%d;%d;%d, z=%d\n", what, vertex, x, y1, y2, y3, y4, z);
524 /* use absolute position */
525 x += motion_new.position_east;
526 y1 += motion_new.position_height;
527 y2 += motion_new.position_height;
528 y3 += motion_new.position_height;
529 y4 += motion_new.position_height;
530 z += motion_new.position_north;
531 render_item->u.vertices_interior.x[vertex] = (double)x;
532 render_item->u.vertices_interior.y[0] = (double)y1;
533 render_item->u.vertices_interior.y[1] = (double)y2;
534 render_item->u.vertices_interior.y[2] = (double)y3;
535 render_item->u.vertices_interior.y[3] = (double)y4;
536 render_item->u.vertices_interior.z[vertex] = (double)z;
537 render_item->u.vertices_interior.set[vertex] = 1;
540 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
542 double out_x, out_y, out_z;
544 /* rotate yaw (German: Gier, turn view to the right) */
546 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
547 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
551 /* rotate pitch (German: Nick, turn head down) */
553 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
554 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
558 /* rotate roll (tilt head to the right) */
560 out_x = (*x) * cos(roll) - (*y) * sin(roll);
561 out_y = (*x) * sin(roll) + (*y) * cos(roll);
567 /* clear screen color (sky / universe) */
568 static void clear_screen(int index)
571 printf("clear screen:\n");
574 /* allocate render item */
575 render_item_add(RENDER_ITEM_SKY);
578 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
580 /* store for later use after planets have been rendered */
581 ground_index = index;
585 static void draw_ground(void)
587 /* no ground in space :) */
588 if (ground_index < 0)
592 printf("add ground plane:\n");
595 /* allocate render item */
596 render_item_add(RENDER_ITEM_GROUND);
599 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
603 static void info_object(int moving)
606 printf("add object's info:\n");
609 /* allocate render item */
610 render_item_add(RENDER_ITEM_OBJECT_INFO);
613 render_item->u.info.moving = moving;
615 mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
618 /* coordinates ready for an object */
619 static void coord_object(void)
623 x = (int16_t)REG_D[3];
624 x += (int32_t)REG_A[1];
625 y = (int16_t)REG_D[4];
626 y += (int32_t)REG_A[2];
627 z = (int16_t)REG_D[5];
628 z += (int32_t)REG_A[3];
629 store_coord("object", REG_A[0], x, y, z, 1.0);
632 /* polygon of object */
633 static void poly_object(int mercenary)
635 uint32_t vertex_address = REG_A[0];
640 printf("add object's polygon:\n");
643 /* allocate render item */
644 render_item_add(RENDER_ITEM_OBJECT_POLYGON);
648 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
651 color = m68k_read_memory_8(vertex_address++) << 8;
652 color |= m68k_read_memory_8(vertex_address++);
653 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
656 /* the vertex list is zero-terminated */
657 for (i = 0; i < MAX_POLYGON; i++) {
658 vertex = m68k_read_memory_8(vertex_address++);
659 if (vertex == 0 && i)
661 render_item->u.polygon.vertex[i] = vertex;
663 render_item->u.polygon.vertices = i;
667 static void line_object(void)
669 uint32_t vertex_address = REG_A[0];
673 printf("add object's line:\n");
676 /* allocate render item */
677 render_item_add(RENDER_ITEM_OBJECT_LINE);
680 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
683 vertex = m68k_read_memory_8(vertex_address++);
684 render_item->u.line.vertex[0] = vertex;
685 vertex = m68k_read_memory_8(vertex_address++);
686 render_item->u.line.vertex[1] = vertex;
689 /* coordinates ready for a beacon */
690 static void coord_beacon(void)
694 /* only 28 bits seem to be a correct signed int value */
695 x = (int32_t)(REG_D[3] << 4) / 16;
696 y = (int32_t)(REG_D[4] << 4) / 16;
697 z = (int32_t)(REG_D[5] << 4) / 16;
698 store_coord("beacon", 0, x, y, z, 1.0);
701 /* point of beacon */
702 static void point_beacon(void)
705 printf("add beacon's point:\n");
708 /* allocate render item */
709 render_item_add(RENDER_ITEM_BEACON_POINT);
712 gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
715 render_item->u.point.vertex = 0;
718 /* coordinates ready for a building (exterior) */
719 static void coord_building_exterior(void)
723 x = (int32_t)REG_D[3];
724 y = (int32_t)REG_D[4];
725 z = (int32_t)REG_D[5];
726 store_coord("building exterior", REG_A[0], x, y, z, 1.0);
729 /* polygon of building (exterior) */
730 static void poly_building_exterior(void)
733 uint32_t vertex_address = REG_A[0];
738 printf("add building's polygon:\n");
741 /* allocate render item */
742 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
745 color = m68k_read_memory_8(vertex_address++) << 8;
746 color |= m68k_read_memory_8(vertex_address++);
747 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
749 /* the vertex list is zero-terminated */
750 for (i = 0; i < MAX_POLYGON; i++) {
751 vertex = m68k_read_memory_8(vertex_address++);
752 if (vertex == 0 && i)
754 render_item->u.polygon.vertex[i] = vertex | 0x100;
756 render_item->u.polygon.vertices = i;
759 /* line of building (exterior) */
760 static void line_building_exterior(void)
762 uint32_t vertex_address = REG_A[0];
766 printf("add building's line:\n");
769 /* allocate render item */
770 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
773 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
776 vertex = m68k_read_memory_8(vertex_address++);
777 render_item->u.line.vertex[0] = vertex | 0x100;
778 vertex = m68k_read_memory_8(vertex_address++);
779 render_item->u.line.vertex[1] = vertex | 0x100;
782 /* coordinates ready for a building (interior) */
783 static void coord_building_interior(void)
786 int32_t height1, height2, height3, height4;
788 mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
789 store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
792 /* polygon of building (interior) */
793 static void poly_building_interior1to4(int level)
800 printf("add roof/floor's polygon at level %d:\n", level);
803 /* allocate render item */
804 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
807 color = m68k_read_memory_8(REG_A[0]) << 8;
808 color |= m68k_read_memory_8(REG_A[0] + 1);
809 gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
811 /* four vertices, one level */
812 for (i = 0; i < 4; i++) {
813 vertex = REG_A[(2 + i)];
814 render_item->u.interior14.vertex[i] = vertex;
816 render_item->u.interior14.level = level;
819 /* polygon of building (interior) */
820 static void poly_building_interior5to6(int level12, int level34)
825 printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
828 /* allocate render item */
829 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
832 color = m68k_read_memory_8(REG_A[0]) << 8;
833 color |= m68k_read_memory_8(REG_A[0] + 1);
834 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
836 /* two vertices, two levels */
837 render_item->u.interior56.vertex14 = REG_A[2];
838 render_item->u.interior56.vertex23 = REG_A[3];
839 render_item->u.interior56.level12 = level12;
840 render_item->u.interior56.level34 = level34;
843 /* wall part of a building */
844 static void wall_building(void)
847 printf("add wall:\n");
850 /* allocate render item */
851 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
854 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
856 /* two vertices, two levels */
857 render_item->u.interior56.vertex14 = REG_A[1];
858 render_item->u.interior56.vertex23 = REG_A[2];
859 /* get top level according to bit 12 in D3 */
860 render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
861 render_item->u.interior56.level34 = 1;
864 /* coordinates ready for comet tail */
865 static void coord_comet(void)
869 x = (int32_t)REG_D[3];
870 y = (int32_t)REG_D[4];
871 z = (int32_t)REG_D[5];
872 store_planets_coord("comet tail", REG_A[0], x, y, z);
875 /* polygon of comet tail */
876 static void poly_comet(void)
879 uint32_t vertex_address = REG_A[0];
884 printf("add comet's polygon:\n");
887 /* allocate render item */
888 render_item_add(RENDER_ITEM_COMET_POLYGON);
891 color = m68k_read_memory_8(vertex_address++) << 8;
892 color |= m68k_read_memory_8(vertex_address++);
893 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
895 /* the vertex list is zero-terminated */
896 for (i = 0; i < MAX_POLYGON; i++) {
897 vertex = m68k_read_memory_8(vertex_address++);
898 if (vertex == 0 && i)
900 render_item->u.polygon.vertex[i] = vertex;
902 render_item->u.polygon.vertices = i;
905 /* coordinates ready for lines of a road / ground surface */
906 static void coord_line_road(void)
911 y = -motion_new.position_height;
913 store_coord("road", REG_A[0], x, y, z, 1.0);
917 static void line_road(void)
922 printf("add road's line:\n");
925 /* allocate render item */
926 render_item_add(RENDER_ITEM_ROAD_LINE);
929 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
933 render_item->u.line.vertex[0] = vertex;
935 render_item->u.line.vertex[1] = vertex;
938 /* coordinates ready for polygons of a road / ground surface */
939 static void coord_poly_road(void)
943 x = m68k_read_memory_32(320 + REG_A[0]);
945 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
946 y = -motion_new.position_height;
947 z = m68k_read_memory_32(576 + REG_A[0]);
949 store_coord("road/place", REG_A[0], x, y, z, 1.0);
952 /* polygon of road */
953 static void poly_road()
956 uint32_t vertex_address = REG_A[0];
961 printf("add road/place's polygon:\n");
964 /* allocate render item */
965 render_item_add(RENDER_ITEM_ROAD_POLYGON);
968 color = m68k_read_memory_8(vertex_address++) << 8;
969 color |= m68k_read_memory_8(vertex_address++);
970 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
972 /* the vertex list is zero-terminated */
973 for (i = 0; i < MAX_POLYGON; i++) {
974 vertex = m68k_read_memory_8(vertex_address++);
975 if (vertex == 0 && i)
977 render_item->u.polygon.vertex[i] = vertex;
979 render_item->u.polygon.vertices = i;
982 /* coordinates ready for tags */
983 static void coord_tags(void)
987 x = (int16_t)REG_D[3];
988 x += (int32_t)REG_A[1];
989 y = (int16_t)REG_D[4];
990 y += (int32_t)REG_A[2];
991 z = (int16_t)REG_D[5];
992 z += (int32_t)REG_A[3];
993 store_coord("tags", REG_A[0], x, y, z, 1.0);
996 /* coordinates ready for large tags */
997 static void coord_tags2(void)
1001 x = (int16_t)REG_D[3];
1002 x += 2 * (int32_t)REG_A[1];
1003 y = (int16_t)REG_D[4];
1004 y += 2 * (int32_t)REG_A[2];
1005 z = (int16_t)REG_D[5];
1006 z += 2 * (int32_t)REG_A[3];
1007 /* note that large tags have double distance, so the resolution is vitrually doubled.
1008 * since we use interpolation and VR, we need to scale the vertex back to normal distance.
1010 store_coord("large tags", REG_A[0], x, y, z, 0.5);
1014 static void line_tags(int last_color)
1016 uint32_t vertex_address = REG_A[0];
1020 printf("add tag's line:\n");
1023 /* allocate render item */
1024 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
1028 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
1030 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
1033 vertex = m68k_read_memory_8(vertex_address++);
1034 render_item->u.line.vertex[0] = vertex | 0x200;
1035 vertex = m68k_read_memory_8(vertex_address++);
1036 render_item->u.line.vertex[1] = vertex | 0x200;
1039 /* polygon of tags */
1040 static void poly_tags(int last_color)
1042 uint32_t vertex_address = REG_A[0];
1047 printf("add tag's polygon:\n");
1050 /* allocate render item */
1051 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1055 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1057 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
1058 /* the vertex list is zero-terminated */
1059 for (i = 0; i < MAX_POLYGON; i++) {
1060 vertex = m68k_read_memory_8(vertex_address++);
1061 if (vertex == 0 && i)
1063 render_item->u.polygon.vertex[i] = vertex | 0x200;
1065 render_item->u.polygon.vertices = i;
1068 /* coordinates ready for planet */
1069 static void coord_planet(void)
1073 x = (int32_t)REG_D[3];
1074 y = (int32_t)REG_D[4];
1075 z = (int32_t)REG_D[5];
1076 store_planets_coord("planet", REG_A[0], x, y, z);
1080 static void draw_planet(int comet)
1083 uint32_t scale_index;
1084 double scale1, scale2;
1088 /* fixing (not noticable) bug in game: don't render comet twice */
1089 if (!comet && vertex == 116)
1093 printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1096 /* allocate render item */
1097 render_item_add(RENDER_ITEM_PLANET);
1101 /* make comet black on front side and bright on back */
1102 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
1103 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
1106 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
1107 /* use background color for dark side */
1108 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
1112 render_item->u.planet.vertex = vertex;
1114 /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
1115 * the long word 21584(A0) contains two scales
1116 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1117 * the upper word defines how much this scale is shifted to the left.
1119 scale_index = mercenary_planet_scale_index();
1120 scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 4096.0;
1121 scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
1122 render_item->u.planet.size = scale1 * scale2 / 256.0;
1126 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1129 printf("add stars\n");
1132 /* allocate render item */
1133 render_item_add(RENDER_ITEM_STARS);
1135 /* vertical offset */
1136 render_item->u.stars.v_offset = v_offset;
1138 /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
1139 render_item->u.stars.tilt = tilt;
1141 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1143 /* stars above zenith */
1144 render_item->u.stars.above_zenith = above_zenith;
1147 /* stars of interstellar flight */
1148 static void draw_stars_interstellar(void)
1154 printf("add interstellar stars\n");
1157 /* allocate render item */
1158 render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1161 count = REG_D[5] + 1;
1162 if (count > MAX_INTERSTARS) {
1163 print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
1166 for (i = 0; i < count; i++) {
1169 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1171 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1173 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1176 render_item->u.interstars.count = count;
1179 /* sun of interstellar flight (center dot) */
1180 static void draw_sun_interstellar(void)
1183 printf("add interstellar sun\n");
1186 /* allocate render item */
1187 render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1190 /* coordinates ready for polygons of islands */
1191 static void coord_islands(void)
1195 x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1196 x += (int32_t)REG_A[1];
1197 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1198 y = -motion_new.position_height;
1199 z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1200 z += (int32_t)REG_A[3];
1201 store_coord("island", REG_A[0], x, y, z, 1.0);
1204 /* polygon of island */
1205 static void poly_island()
1208 uint32_t vertex_address = REG_A[0];
1213 printf("add island:\n");
1216 /* allocate render item */
1217 render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1220 color = m68k_read_memory_8(vertex_address++) << 8;
1221 color |= m68k_read_memory_8(vertex_address++);
1222 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1224 /* the vertex list is zero-terminated */
1226 while (i < MAX_POLYGON) {
1227 vertex = m68k_read_memory_8(vertex_address++);
1228 if (vertex == 0 && i)
1230 /* skip mysterious points when rendering island */
1233 render_item->u.polygon.vertex[i] = vertex;
1236 render_item->u.polygon.vertices = i;
1240 static void draw_sights(void)
1243 printf("add sights:\n");
1246 /* allocate render item */
1247 render_item_add(RENDER_ITEM_SIGHTS);
1250 static int32_t coord_explosion_x, coord_explosion_y, coord_explosion_z;
1252 static void coord_explosion(void)
1254 coord_explosion_x = REG_D[3];
1255 coord_explosion_y = REG_D[4];
1256 coord_explosion_z = REG_D[5];
1259 static void draw_explosion(void)
1262 double scale1, scale2;
1265 printf("add explosion:\n");
1268 /* allocate render item */
1269 if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
1270 render_item_add(RENDER_ITEM_EXPLOSION);
1271 /* get color from render palette */
1272 color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
1273 gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
1274 render_item->u.explosion.count = 0;
1276 if (render_item->u.explosion.count == MAX_EXPLOSION)
1279 /* the D1 register contains two scales
1280 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1281 * the upper word defines how much this scale is shifted to the left.
1283 if ((int16_t)(REG_D[1] >> 16) < 0) {
1284 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1285 scale2 = (double)(256 >> -(int16_t)(REG_D[1] >> 16)) / 256.0;
1287 if ((int16_t)(REG_D[1] >> 16) <= 10) {
1288 scale1 = (double)(REG_D[1] & 0x1fff) / 4096.0;
1289 scale2 = (double)(1 << (int16_t)(REG_D[1] >> 16));
1294 render_item->u.explosion.size[render_item->u.explosion.count] = scale1 * scale2;
1295 render_item->u.explosion.x[render_item->u.explosion.count] = coord_explosion_x;
1296 render_item->u.explosion.y[render_item->u.explosion.count] = coord_explosion_y;
1297 render_item->u.explosion.z[render_item->u.explosion.count] = coord_explosion_z;
1298 render_item->u.explosion.count++;
1301 /* stop event from CPU received */
1302 void render_capture_event(int event)
1305 case STOP_AT_CLEAR_SCREEN1:
1306 clear_screen(16); /* color 16 is raster split */
1307 /* in case of screen clearing on the ground, there is no roll */
1308 motion_new.orientation_roll = 0;
1310 case STOP_AT_CLEAR_SCREEN2:
1313 case STOP_AT_CLEAR_SCREEN3:
1314 clear_screen(-1); /* no ground (in universe) */
1316 case STOP_AT_DRAW_GROUND:
1319 case STOP_AT_INFO_OBJECT_MOVING:
1322 case STOP_AT_INFO_OBJECT_FIX:
1325 case STOP_AT_TAG_IS_OBJECT_1:
1328 case STOP_AT_TAG_IS_OBJECT_0:
1331 case STOP_AT_COORD_OBJECT:
1334 case STOP_AT_POLY_OBJECT_M3:
1337 case STOP_AT_POLY_OBJECT_M2:
1340 case STOP_AT_LINE_OBJECT:
1343 case STOP_AT_COORD_BEACON:
1346 case STOP_AT_POINT_BEACON:
1348 /* note: we may not call the point-renderer, because projected coordinates are invalid */
1349 mercenary_patch_render();
1351 case STOP_AT_COORD_BUILDING_EXTERIOR:
1352 coord_building_exterior();
1354 case STOP_AT_POLY_BUILDING_EXTERIOR:
1355 poly_building_exterior();
1357 case STOP_AT_LINE_BUILDING_EXTERIOR:
1358 line_building_exterior();
1360 case STOP_AT_COORD_BUILDING_INTERIOR:
1361 coord_building_interior();
1363 case STOP_AT_POLY_BUILDING_INTERIOR1:
1365 interior_level12 = 1;
1366 interior_level34 = 1;
1368 case STOP_AT_POLY_BUILDING_INTERIOR2:
1370 interior_level12 = 2;
1371 interior_level34 = 2;
1373 case STOP_AT_POLY_BUILDING_INTERIOR3:
1374 /* door/window top */
1375 interior_level12 = 3;
1376 interior_level34 = 3;
1378 case STOP_AT_POLY_BUILDING_INTERIOR4:
1380 interior_level12 = 4;
1381 interior_level34 = 4;
1383 case STOP_AT_POLY_BUILDING_INTERIOR5:
1384 /* door/window top */
1385 interior_level12 = 2;
1386 interior_level34 = 3;
1388 case STOP_AT_POLY_BUILDING_INTERIOR6:
1390 interior_level12 = 1;
1391 interior_level34 = 4;
1393 case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1394 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1395 if (interior_level12 == 0) {
1396 print_info("Interior level is not set, please fix!\n");
1399 poly_building_interior1to4(interior_level12);
1400 interior_level12 = 0;
1402 case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1403 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1404 if (interior_level12 == 0) {
1405 print_info("Interior level is not set, please fix!\n");
1408 poly_building_interior5to6(interior_level12, interior_level34);
1409 interior_level12 = 0;
1411 case STOP_AT_WALL_BUILDING:
1414 case STOP_AT_COORD_COMET:
1417 case STOP_AT_MATRIX_COMET:
1418 case STOP_AT_MATRIX_PLANET:
1419 /* track the rotation matrix
1420 * if we have 0x42c44 matrix, we must add extra rotation to planet.
1421 * the rotation will change the view from the planet's surface */
1422 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1423 motion_new.planet_rotation = 1;
1425 motion_new.planet_rotation = 0;
1427 case STOP_AT_POLY_COMET:
1430 case STOP_AT_COORD_LINE_ROADS:
1433 case STOP_AT_LINE_ROADS:
1436 case STOP_AT_COORD_POLY_ROADS:
1439 case STOP_AT_LINE_ROADS_CENTER:
1440 /* we don't need to render center lines of roads, because there are polygons already
1441 * it does not make sense, since OpenGL has much higher resolution.
1444 case STOP_AT_POLY_ROADS:
1447 case STOP_AT_COORD_TAGS:
1450 case STOP_AT_COORD_TAGS2:
1453 case STOP_AT_LINE_TAGS1:
1456 case STOP_AT_LINE_TAGS2:
1459 case STOP_AT_POLY_TAGS1:
1462 case STOP_AT_POLY_TAGS2:
1465 case STOP_AT_COORD_PLANET:
1468 case STOP_AT_DRAW_PLANET:
1471 case STOP_AT_DRAW_COMET:
1474 case STOP_AT_DRAW_STARS_SPACE:
1475 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1476 draw_stars(0x1c0, 0, 0);
1478 case STOP_AT_DRAW_STARS_GROUND:
1479 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1480 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1482 case STOP_AT_DRAW_STARS_FLYING:
1483 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1484 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1486 case STOP_AT_DRAW_STARS_FLYING2:
1487 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1488 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1490 case STOP_AT_DRAW_STARS_INTERSTELLAR:
1491 draw_stars_interstellar();
1493 case STOP_AT_DRAW_SUN_INTERSTELLAR:
1494 draw_sun_interstellar();
1496 case STOP_AT_COORD_ISLANDS:
1499 case STOP_AT_POLY_ISLANDS:
1502 case STOP_AT_LINE_ISLANDS:
1503 /* this is not used, as i had noticed so far */
1504 puts("line island");
1506 case STOP_AT_DRAW_SIGHTS:
1509 case STOP_AT_POLY_UKN2:
1512 case STOP_AT_COORD_EXPLOSION:
1515 case STOP_AT_DRAW_EXPLOSION:
1518 case STOP_AT_PATCH_RENDER:
1519 mercenary_patch_render();
1528 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix)
1530 render_item_t *ri = NULL;
1533 print_info("Vertex %d is not a multiple of four!\n", vertex);
1536 if (vertex < 0x100) {
1537 if (!render_item_vertices_0) {
1538 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1541 ri = render_item_vertices_0;
1543 if (vertex < 0x200) {
1544 if (!render_item_vertices_1) {
1545 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1548 ri = render_item_vertices_1;
1551 if (vertex < 0x300) {
1552 if (!render_item_vertices_2) {
1553 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1556 ri = render_item_vertices_2;
1559 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1563 /* translate to original position */
1564 *x = ri->u.vertices.x[vertex] - motion_new.position_east;
1565 *y = ri->u.vertices.y[vertex] - motion_new.position_height;
1566 *z = ri->u.vertices.z[vertex] - motion_new.position_north;
1568 /* translate to floating (interpolated) position offset */
1569 *x -= interpolation.offset_east;
1570 *y -= interpolation.offset_height;
1571 *z -= interpolation.offset_north;
1574 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1580 static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1582 render_item_t *ri = NULL;
1585 print_info("Vertex %d is not a multiple of four!\n", vertex);
1588 if (vertex >= MAX_VERTEX) {
1589 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1592 if (interpolation.planets)
1593 ri = interpolation.planets;
1595 ri = render_item_vertices_0;
1597 print_info("Vertices item for planets verticies not yet set!\n");
1601 *x = ri->u.vertices.x[vertex];
1602 *y = ri->u.vertices.y[vertex];
1603 *z = ri->u.vertices.z[vertex];
1605 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1611 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1614 print_info("Vertex is not a multiple of four!\n");
1617 if (vertex >= MAX_INTERIOR_VERTEX) {
1618 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1621 if (level < 1 || level > 4) {
1622 print_info("Level %d is out of range (1..4)!\n", level);
1625 if (!render_item_vertices_interior) {
1626 print_info("Vertices item for interior verticies not yet set!\n");
1630 *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1631 *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1632 *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1633 /* translate to position back to original */
1634 *x -= motion_new.position_east;
1635 *y -= motion_new.position_height;
1636 *z -= motion_new.position_north;
1637 /* translate to floating (interpolated) position offset */
1638 *x -= interpolation.offset_east;
1639 *y -= interpolation.offset_height;
1640 *z -= interpolation.offset_north;
1643 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1649 /* renders one item from render list */
1650 void render_one_item(render_item_t *render_item, int vr)
1652 switch (render_item->type) {
1653 case RENDER_ITEM_OBJECT_INFO:
1656 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1658 render_item_object_info = render_item;
1661 case RENDER_ITEM_VERTICES_0:
1664 printf("RENDER_ITEM_VERTICES_0\n");
1666 render_item_vertices_0 = render_item;
1669 case RENDER_ITEM_VERTICES_1:
1672 printf("RENDER_ITEM_VERTICES_1\n");
1674 render_item_vertices_1 = render_item;
1677 case RENDER_ITEM_VERTICES_2:
1680 printf("RENDER_ITEM_VERTICES_2\n");
1682 render_item_vertices_2 = render_item;
1685 case RENDER_ITEM_VERTICES_INTERIOR:
1688 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1690 if (interpolation.interior)
1691 render_item_vertices_interior = interpolation.interior;
1693 render_item_vertices_interior = render_item;
1696 case RENDER_ITEM_SKY:
1698 double x[4], y[4], z[4];
1701 printf("RENDER_ITEM_SKY\n");
1704 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1705 /* create box to fill view */
1706 x[0] = x[1] = y[1] = y[2] = -1000;
1707 x[2] = x[3] = y[0] = y[3] = 1000;
1708 z[0] = z[1] = z[2] = z[3] = 1000;
1709 opengl_render_polygon_and_line(x, y, z, 4);
1710 z[0] = z[1] = z[2] = z[3] = -1000;
1711 opengl_render_polygon_and_line(x, y, z, 4);
1712 x[0] = x[1] = z[1] = z[2] = -1000;
1713 x[2] = x[3] = z[0] = z[3] = 1000;
1714 y[0] = y[1] = y[2] = y[3] = 1000;
1715 opengl_render_polygon_and_line(x, y, z, 4);
1716 y[0] = y[1] = y[2] = y[3] = -1000;
1717 opengl_render_polygon_and_line(x, y, z, 4);
1718 y[0] = y[1] = z[1] = z[2] = -1000;
1719 y[2] = y[3] = z[0] = z[3] = 1000;
1720 x[0] = x[1] = x[2] = x[3] = 1000;
1721 opengl_render_polygon_and_line(x, y, z, 4);
1722 x[0] = x[1] = x[2] = x[3] = -1000;
1723 opengl_render_polygon_and_line(x, y, z, 4);
1726 case RENDER_ITEM_GROUND:
1729 double x[4], y[4], z[4];
1733 printf("RENDER_ITEM_GROUND\n");
1736 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1737 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1738 /* create huge square */
1739 x[0] = x[1] = z[1] = z[2] = -10000000;
1740 x[2] = x[3] = z[0] = z[3] = 10000000;
1741 y[0] = y[1] = y[2] = y[3] = -1000;
1743 for (i = 0; i < 4; i++)
1744 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1746 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1749 case RENDER_ITEM_OBJECT_POLYGON:
1750 case RENDER_ITEM_TAG_POLYGON_OBJECT:
1751 case RENDER_ITEM_TAG_POLYGON_OTHER:
1752 case RENDER_ITEM_ISLAND_POLYGON:
1756 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1761 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1762 printf("RENDER_ITEM_OBJECT_POLYGON\n");
1763 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
1764 printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
1765 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
1766 printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
1767 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1768 printf("RENDER_ITEM_ISLAND_POLYGON\n");
1771 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1772 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) {
1773 // GET_ORIENTATION_FIX;
1778 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1779 /* get and rotate vertex */
1780 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1782 rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
1785 /* fixed objects are pre-scaled by 16, so we correct this */
1787 x[i] /= FIX_OBJECT_SCALE;
1788 y[i] /= FIX_OBJECT_SCALE;
1789 z[i] /= FIX_OBJECT_SCALE;
1791 /* interpolate motion, if object is moving */
1792 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) {
1793 for (o = 0; o < interpolation.object_count; o++) {
1794 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1797 if (o < interpolation.object_count) {
1798 x[i] += interpolation.object_offset_east[o];
1799 y[i] += interpolation.object_offset_height[o];
1800 z[i] += interpolation.object_offset_north[o];
1804 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1807 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1810 case RENDER_ITEM_OBJECT_LINE:
1811 case RENDER_ITEM_TAG_LINE_OBJECT:
1812 case RENDER_ITEM_TAG_LINE_OTHER:
1816 double x[2], y[2], z[2];
1821 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1822 printf("RENDER_ITEM_OBJECT_LINE\n");
1823 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
1824 printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
1825 if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
1826 printf("RENDER_ITEM_TAG_LINE_OTHER\n");
1829 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1830 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) {
1831 // GET_ORIENTATION_FIX;
1836 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1837 /* get and rotate vertex */
1838 for (i = 0; i < 2; i++) {
1840 rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
1843 /* fixed objects are pre-scaled by 16, so we correct this */
1845 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT) {
1846 x[i] /= FIX_OBJECT_SCALE_TAG;
1847 y[i] /= FIX_OBJECT_SCALE_TAG;
1848 z[i] /= FIX_OBJECT_SCALE_TAG;
1850 x[i] /= FIX_OBJECT_SCALE;
1851 y[i] /= FIX_OBJECT_SCALE;
1852 z[i] /= FIX_OBJECT_SCALE;
1855 /* interpolate motion, if object is moving */
1856 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) {
1857 for (o = 0; o < interpolation.object_count; o++) {
1858 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1861 if (o < interpolation.object_count) {
1862 x[i] += interpolation.object_offset_east[o];
1863 y[i] += interpolation.object_offset_height[o];
1864 z[i] += interpolation.object_offset_north[o];
1868 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1871 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1874 case RENDER_ITEM_BEACON_POINT:
1881 printf("RENDER_ITEM_BEACON_POINT\n");
1884 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1886 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
1890 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1892 opengl_render_point(x, y, z, 0.0);
1895 case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1898 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1903 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1906 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1907 /* get and rotate vertex */
1908 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1910 rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
1914 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1917 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1920 case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
1923 double x[2], y[2], z[2];
1928 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1931 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1932 /* get and rotate vertex */
1933 for (i = 0; i < 2; i++) {
1935 rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
1939 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1942 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1945 case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1948 double x[4], y[4], z[4];
1953 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1956 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1957 /* get and rotate vertex */
1958 for (i = 0; i < 4; i++) {
1960 rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1964 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1967 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1970 case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1973 double x[4], y[4], z[4];
1979 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1982 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1983 /* get and rotate vertex */
1984 for (i = 0; i < 4; i++) {
1986 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1987 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1988 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1992 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1995 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1998 case RENDER_ITEM_BUILDING_INTERIOR_WALL:
2001 double x[4], y[4], z[4];
2007 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
2010 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
2011 /* chedck if wall is a rectangle or a line */
2012 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
2013 /* get and rotate vertex */
2014 for (i = 0; i < 4; i++) {
2016 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
2017 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2018 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2022 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2025 opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
2027 /* get and rotate vertex */
2028 for (i = 0; i < 2; i++) {
2030 vertex = render_item->u.interior56.vertex14;
2031 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
2032 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
2036 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2039 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2043 case RENDER_ITEM_COMET_POLYGON:
2046 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2047 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2050 double rotate_sky = 0.0;
2053 printf("RENDER_ITEM_COMET_POLYGON\n");
2056 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2057 /* get and rotate vertex */
2058 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2060 rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
2064 if (motion_new.planet_rotation) {
2065 if (fix_sky_rotation)
2067 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
2069 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x[i], &y[i], &z[i]);
2072 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
2075 case RENDER_ITEM_ROAD_LINE:
2078 double x[2], y[2], z[2];
2083 printf("RENDER_ITEM_ROAD_LINE\n");
2086 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2087 /* get and rotate vertex */
2088 for (i = 0; i < 2; i++) {
2090 rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2094 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2097 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2100 case RENDER_ITEM_ROAD_POLYGON:
2103 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2105 uint32_t vertex, vertex_prev, vertex_next;
2106 double x_current, y_current, z_current;
2107 double x_prev, y_prev, z_prev;
2108 double x_next, y_next, z_next;
2113 printf("RENDER_ITEM_ROAD_POLYGON\n");
2116 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2117 /* get and rotate vertex */
2119 vertices_num = render_item->u.polygon.vertices;
2120 for (v = 0; v < vertices_num; v++) {
2122 vertex = render_item->u.polygon.vertex[v];
2123 rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
2126 /* check for road extension, so we extend the road to the given end point */
2127 if (extend_roads && vertex >= 0xf0) {
2128 /* previous vertex */
2129 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
2130 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
2134 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
2135 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
2138 /* extend vertices to end point position
2139 * change x or z coordinate, whatever is greater
2141 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
2142 x_prev = x_next = x_current;
2144 z_prev = z_next = z_current;
2145 /* store vertices */
2150 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2151 if (i++ == MAX_POLYGON)
2157 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2158 if (i++ == MAX_POLYGON)
2162 /* no extension, just keep the current point as is */
2167 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2168 if (i++ == MAX_POLYGON)
2173 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2176 case RENDER_ITEM_PLANET:
2179 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2180 double sun_x, sun_y, sun_z, angle_sun_h;
2181 double loc_x, loc_y, loc_z, angle_loc_h, angle_loc_v;
2182 double circle_x[PLANET_VERTICES], circle_y[PLANET_VERTICES], circle_z[PLANET_VERTICES];
2183 double crescent_x[PLANET_VERTICES], crescent_y[PLANET_VERTICES], crescent_z[PLANET_VERTICES];
2184 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
2185 double dist, size, angle, fabs_angle, crescent;
2189 double rotate_sky = 0.0;
2192 printf("RENDER_ITEM_PLANET\n");
2195 rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
2198 rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
2202 size = render_item->u.planet.size;
2204 if (motion_new.planet_rotation) {
2205 if (fix_sky_rotation)
2207 rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
2208 rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
2210 rotate_coordinate(roll, pitch, yaw + rotate_sky, &sun_x, &sun_y, &sun_z);
2211 rotate_coordinate(roll, pitch, yaw + rotate_sky, &loc_x, &loc_y, &loc_z);
2213 /* distance to planet */
2214 dist = sqrt(loc_x * loc_x + loc_y * loc_y + loc_z * loc_z);
2216 /* calculate direction of the sun */
2217 angle_sun_h = atan2(sun_x, sun_z);
2218 angle_loc_h = atan2(loc_x, loc_z);
2219 angle_loc_v = atan2(loc_y, sqrt(loc_x * loc_x + loc_z * loc_z));
2220 /* angle between planets */
2221 angle = angle_sun_h - angle_loc_h;
2223 angle -= 2.0 * M_PI;
2225 angle += 2.0 * M_PI;
2226 /* absolute angle to be used as crescent */
2227 fabs_angle = fabs(angle);
2228 if (fabs_angle > M_PI / 2.0)
2229 fabs_angle = M_PI - fabs_angle;
2231 /* on which side are we (sun is always bright, vertex == 0) */
2232 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
2233 /* get front side color */
2234 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2236 /* get back side color */
2237 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2240 /* create and render cicle */
2241 crescent = sin((1.0 - fabs_angle / (M_PI / 2)) * (M_PI / 2.0));
2243 for (i = 0; i < PLANET_VERTICES; i++) {
2244 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2245 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2246 circle_x[i] = _sin * planet_aspect;
2249 crescent_x[i] = circle_x[i] * crescent;
2250 crescent_y[i] = circle_y[i];
2251 crescent_z[i] = circle_z[i];
2252 /* rotate circle and cresent towards observer (billboarding) */
2253 rotate_coordinate(0.0, -angle_loc_v, 0.0, &circle_x[i], &circle_y[i], &circle_z[i]);
2254 rotate_coordinate(0.0, 0.0, angle_loc_h, &circle_x[i], &circle_y[i], &circle_z[i]);
2255 rotate_coordinate(0.0, -angle_loc_v, 0.0, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2256 rotate_coordinate(0.0, 0.0, angle_loc_h, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2259 for (i = 0; i < PLANET_VERTICES; i++) {
2260 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2261 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2262 circle_x[i] = _sin * planet_aspect;
2265 crescent_x[i] = circle_x[i] * crescent;
2266 crescent_y[i] = circle_y[i];
2267 crescent_z[i] = circle_z[i];
2270 for (i = 0; i < PLANET_VERTICES; i++) {
2271 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2272 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2273 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2275 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2277 if (render_item->u.planet.vertex == 0) {
2278 /* sun has no crescent */
2282 /* on which side are we */
2283 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
2284 /* get back side color */
2285 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2287 /* get front side color */
2288 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2291 /* create and render crescent */
2292 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2294 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2295 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2296 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2297 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2299 _sin = sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2300 for (; i < PLANET_VERTICES; i++) {
2301 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2302 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2303 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2307 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2308 x[i] = (loc_x + crescent_x[i]) / dist * 1000000.0;
2309 y[i] = (loc_y + crescent_y[i]) / dist * 1000000.0;
2310 z[i] = (loc_z + crescent_z[i]) / dist * 1000000.0;
2312 for (; i < PLANET_VERTICES; i++) {
2313 x[i] = (loc_x + circle_x[i]) / dist * 1000000.0;
2314 y[i] = (loc_y + circle_y[i]) / dist * 1000000.0;
2315 z[i] = (loc_z + circle_z[i]) / dist * 1000000.0;
2318 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2319 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
2322 case RENDER_ITEM_STARS:
2324 double tilt_offset = 0;
2325 double x_offset = 0;
2327 double view_width, yaw = interpolation.orientation_raw_yaw;
2328 double pitch = interpolation.orientation_raw_pitch;
2329 uint32_t table, table_start;
2332 double red, green, blue;
2333 double rotate_sky = 0.0;
2336 printf("RENDER_ITEM_STARS\n");
2338 /* use default fov of 64 to calculate z distance */
2339 z = 160.0 / frustum_slope_64;
2341 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2344 for (i = 0; i < 16; i++)
2345 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2347 if (!vr && !improve_stars) {
2348 /* render legacy stars (as with the original game) */
2350 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
2351 * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
2352 * then we half it, so we get to the center via 91
2355 if (render_item->u.stars.above_zenith)
2357 yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2359 table = mercenary_star_table();
2360 table_start = table + m68k_read_memory_16(table);
2361 table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
2362 yaw = yaw / (double)0x800 * 1800.0;
2364 if (render_item->u.stars.above_zenith)
2365 pitch = 0x200 - pitch;
2366 pitch = fmod(pitch + 65536.0, 0x400);
2367 pitch -= render_item->u.stars.v_offset;
2369 pitch = pitch * (double)0x6ccc / 65536.0;
2372 x = m68k_read_memory_16(table);
2375 table = table_start;
2377 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2381 /* special case where we tilt the view when flying on the planet */
2382 if (render_item->u.stars.tilt) {
2383 /* use offset as given by game: 160 is half of the screen width
2384 * we extend the width to the actual FOV, so it fits
2386 tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2388 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2390 if (render_item->u.stars.above_zenith) {
2391 x = (double)(view_width - 1) - x;
2395 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2396 opengl_render_color(red, green, blue, debug_opacity);
2398 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2401 /* render ovr stars, render star table as a sphere */
2405 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2407 if (render_item->u.stars.above_zenith)
2410 table = mercenary_star_table();
2411 table += m68k_read_memory_16(table);
2414 x = m68k_read_memory_16(table);
2418 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - 108.796875;
2421 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2422 opengl_render_color(red, green, blue, debug_opacity);
2424 h = (900.0 - x + 160) / 900.0 * M_PI;
2425 v1 = (68.0 - y) / 900.0 * M_PI;
2426 /* wrap star field (is actually 86.2 degrees high) */
2428 v2 = v1 + (86.2 / 180.0 * M_PI);
2430 v2 = v1 - (86.2 / 180.0 * M_PI);
2431 if (v1 < 0.934 && v1 > -0.934) {
2432 /* be sure that v1 will not exceed PI/2 */
2433 v1 = v1 / cos(v1); /* FIXME: there should be a better way to distribute stars equally */
2434 x = -sin(h) * cos(v1);
2436 z = cos(h) * cos(v1);
2437 if (motion_new.planet_rotation) {
2438 if (fix_sky_rotation)
2440 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2442 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2443 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2445 if (v2 < 0.934 && v2 > -0.934) {
2446 /* be sure that v2 will not exceed PI/2 */
2447 v2 = v2 / cos(v2) /* FIXME: there should be a better way to distribute stars equally */;
2448 x = -sin(h) * cos(v2);
2450 z = cos(h) * cos(v2);
2451 if (motion_new.planet_rotation) {
2452 if (fix_sky_rotation)
2454 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2456 rotate_coordinate(roll, pitch, yaw + rotate_sky, &x, &y, &z);
2457 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2463 case RENDER_ITEM_INTERSTELLAR_STARS:
2468 double red, green, blue;
2471 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2473 /* use default fov of 64 to calculate z distance */
2474 z = 160.0 / frustum_slope_64;
2477 for (i = 0; i < 16; i++)
2478 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2480 for (i = 0; i < render_item->u.interstars.count; i++) {
2481 gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
2482 opengl_render_color(red, green, blue, debug_opacity);
2484 opengl_render_point((160.0 - (double)render_item->u.interstars.x[i]) * 100, (68.0 - (double)render_item->u.interstars.y[i]) * 100, z * 100, 0.0);
2488 case RENDER_ITEM_INTERSTELLAR_SUN:
2490 double red, green, blue;
2493 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2496 gamecolor2gl(&red, &green, &blue, 0x777);
2497 opengl_render_color(red, green, blue, debug_opacity);
2499 opengl_render_point(0.0, 0.0, 1000000.0, 0.0);
2502 case RENDER_ITEM_SIGHTS:
2504 double x[4], y[4], z[4];
2505 double red, green, blue;
2508 printf("RENDER_ITEM_SIGHTS\n");
2510 /* use default fov of 64 to calculate z distance */
2511 z[0] = z[1] = z[2] = z[3] = SIGHT_DIST;
2514 gamecolor2gl(&red, &green, &blue, 0x777);
2515 opengl_render_color(red, green, blue, debug_opacity);
2517 y[0] = y[3] = -1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2518 y[1] = y[2] = 1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2519 x[0] = x[1] = -16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2520 x[2] = x[3] = -8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2521 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2522 x[0] = x[1] = 8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2523 x[2] = x[3] = 16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2524 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2527 case RENDER_ITEM_EXPLOSION:
2530 double loc_x, loc_y, loc_z, size;
2531 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2535 printf("RENDER_ITEM_EXPLOSION\n");
2537 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2539 for (e = 0; e < render_item->u.explosion.count; e++) {
2540 loc_x = render_item->u.explosion.x[e];
2541 loc_y = render_item->u.explosion.y[e];
2542 loc_z = render_item->u.explosion.z[e];
2544 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2545 /* calculate size from projected size and z (256 is the distance of the game's projection plane) */
2546 size = render_item->u.explosion.size[e] * (fabs(loc_z) / 256.0);
2547 /* create and render cicle */
2548 for (i = 0; i < EXPLOSION_VERTICES; i++) {
2549 x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * explosion_aspect;
2550 y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
2553 opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
2554 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point */
2559 print_info("Unknown render item type, please fix!\n");
2567 static double interpolate_orientation(double old, double new, double inter)
2569 double turn = new - old;
2576 /* don't interpolate, if our rotation was too fast.
2577 * e.g: taxi drive around corder, load/quit game, ...
2579 if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
2582 new = old + turn * inter;
2592 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
2594 int16_t turn = (new - old) & 0x3ff;
2599 /* don't interpolate, if our rotation was too fast.
2600 * e.g: taxi drive around corder, load/quit game, ...
2602 if (turn > 0x200 / 8 || turn < -0x200 / 8)
2605 /* don't do modulo 0x400, since the user of this data does it */
2606 return (double)old + (double)turn * inter;
2609 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
2613 /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
2614 if (ground_index >= 0)
2615 offset = wrap_int28(old - new);
2617 offset = (int32_t)(old - new);
2619 if (limit > 0 && (offset > limit || offset < -limit))
2622 return offset * (1.0 - inter);
2625 static render_item_t *interpolate_door(double inter)
2627 static render_item_t interpolated;
2628 render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
2631 /* find old and new vertices */
2632 while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2633 old_vertices = old_vertices->next;
2634 while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2635 new_vertices = new_vertices->next;
2637 /* building does not exist in old or new render */
2638 if (!old_vertices || !new_vertices)
2641 memcpy(&interpolated, new_vertices, sizeof(interpolated));
2642 ii = MAX_INTERIOR_VERTEX >> 2;
2643 for (i = 0; i < ii; i++) {
2644 /* vertex must exist in both frames */
2645 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2647 /* all verices must not have be too far away */
2648 if (fabs(old_vertices->u.vertices_interior.x[i] - new_vertices->u.vertices_interior.x[i]) > 100.0)
2650 if (fabs(old_vertices->u.vertices_interior.z[i] - new_vertices->u.vertices_interior.z[i]) > 100.0)
2653 interpolated.u.vertices_interior.x[i] =
2654 (double)old_vertices->u.vertices_interior.x[i] * (1.0 - inter) +
2655 (double)new_vertices->u.vertices_interior.x[i] * inter;
2656 interpolated.u.vertices_interior.z[i] =
2657 (double)old_vertices->u.vertices_interior.z[i] * (1.0 - inter) +
2658 (double)new_vertices->u.vertices_interior.z[i] * inter;
2660 for (i = 0; i < 4; i++) {
2661 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
2665 return &interpolated;
2668 /* make a list of objects that moved and store their displacement */
2669 static void interpolate_objects(double inter)
2671 render_item_t *old_info, *new_info;
2674 /* hunt for objects that exist in both (old and new) lists and moved */
2676 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2678 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
2681 if (!new_info->u.info.moving)
2683 /* interiors don't move */
2684 if (new_info->u.info.id < 0)
2686 /* check matching object with same ID */
2687 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2689 if (old_info->type != RENDER_ITEM_OBJECT_INFO)
2692 if (!old_info->u.info.moving)
2695 if (old_info->u.info.id == new_info->u.info.id)
2698 /* no matching object found */
2702 if (old_info->u.info.east == new_info->u.info.east
2703 && old_info->u.info.height == new_info->u.info.height
2704 && old_info->u.info.north == new_info->u.info.north)
2706 /* interpolate and store */
2707 interpolation.object_id[count] = new_info->u.info.id;
2708 interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
2709 interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
2710 interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
2711 if (count++ == MAX_MOVING_OBJECTS)
2714 interpolation.object_count = count;
2717 /* make a vertex list of interpolated planets */
2718 static render_item_t *interpolate_planets(double inter)
2720 static render_item_t interpolated;
2721 render_item_t *old_info, *new_info;
2722 render_item_t *old_vertices = NULL, *new_vertices = NULL;
2725 /* get vertices for planets/comet */
2726 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2727 if (old_info->type == RENDER_ITEM_VERTICES_0)
2728 old_vertices = old_info;
2729 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2730 if (old_info->type == RENDER_ITEM_COMET_POLYGON)
2733 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2734 if (new_info->type == RENDER_ITEM_VERTICES_0)
2735 new_vertices = new_info;
2736 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2737 if (new_info->type == RENDER_ITEM_COMET_POLYGON)
2741 /* check for existing planet's vertices and if planets are rendered in both lists (old and new) */
2742 if (old_info == NULL || new_info == NULL || old_vertices == NULL || new_vertices == NULL)
2745 /* interpolate vertices */
2746 for (i = 0; i < (MAX_VERTEX >> 2); i++) {
2747 interpolated.u.vertices.x[i] = old_vertices->u.vertices.x[i] * (1.0 - inter) + new_vertices->u.vertices.x[i] * inter;
2748 interpolated.u.vertices.y[i] = old_vertices->u.vertices.y[i] * (1.0 - inter) + new_vertices->u.vertices.y[i] * inter;
2749 interpolated.u.vertices.z[i] = old_vertices->u.vertices.z[i] * (1.0 - inter) + new_vertices->u.vertices.z[i] * inter;
2752 return &interpolated;
2755 /* always renders NEW! items
2756 * use inter == 1.0 to render motion to vertices of NEW items
2757 * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
2758 * return 0, if the scene was rendered, returns < 0, if there is no scene
2760 int render_all_items(double inter, int vr)
2762 render_item_object_info = NULL;
2763 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2764 render_item_vertices_interior = NULL;
2765 render_item_vertices_planets = NULL;
2767 /* no interpolation when leaving or entering planet to/from space */
2768 if ((last_ground_index < 0 && ground_index >= 0)
2769 || (last_ground_index >= 0 && ground_index < 0)) {
2773 /* reset interpolation */
2774 memset(&interpolation, 0, sizeof(interpolation));
2775 interpolation.orientation_roll = motion_new.orientation_roll;
2776 interpolation.orientation_pitch = motion_new.orientation_pitch;
2777 interpolation.orientation_yaw = motion_new.orientation_yaw;
2778 interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
2779 interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
2780 interpolation.planet_inclination = motion_new.planet_inclination;
2781 interpolation.planet_azimuth = motion_new.planet_azimuth;
2782 //printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
2784 /* do interpolation */
2785 if (inter != 1.0 && render_list_old) {
2786 /* interpolate orientation */
2787 interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
2788 interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
2789 interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
2790 interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
2791 interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
2792 interpolation.planet_inclination = interpolate_orientation(motion_old.planet_inclination, motion_new.planet_inclination, inter);
2793 interpolation.planet_azimuth = interpolate_orientation(motion_old.planet_azimuth, motion_new.planet_azimuth, inter);
2795 /* interpolate position */
2796 interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
2797 interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
2798 interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
2799 /* prevent glitch when using elevators: a sudden vertical move is ignored
2800 * this is not the best solution, because fast vertical flying (from 0) will also be detected */
2801 if (old_height_offset == 0
2802 && (new_height_offset >= 150 || new_height_offset <= -150)) {
2803 interpolation.offset_east = 0.0;
2804 interpolation.offset_height = 0.0;
2805 interpolation.offset_north = 0.0;
2808 /* interpolate doors of building (if any) */
2809 interpolation.interior = interpolate_door(inter);
2811 /* interpolate objects */
2812 interpolate_objects(inter);
2814 /* interpolate planets */
2815 interpolation.planets = interpolate_planets(inter);
2818 /* return failure, if nothing can be rendered */
2819 if (!render_list_new)
2822 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2823 render_one_item(render_item, vr);
2829 int render_all_white(int vr)
2831 render_item_t sky_item;
2833 memset(&sky_item, 0, sizeof(sky_item));
2834 sky_item.type = RENDER_ITEM_SKY;
2837 sky_item.u.ground.red = 1.0;
2838 sky_item.u.ground.green = 1.0;
2839 sky_item.u.ground.blue = 1.0;
2841 render_one_item(&sky_item, vr);
2846 void render_capture_reset(void)
2848 /* flush old list, if exists */
2850 /* flush new list, if exists */
2851 render_list_old = render_list_new;
2853 /* reset list pointers */
2854 render_list_old = NULL;
2855 render_list_new = NULL;
2856 render_list_end = &render_list_new;
2860 int render_capture_is_interstellar(void)
2862 if (!render_list_new)
2864 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2865 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)