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 "../libsdl/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_ELIPSE 1.17
63 #define EXPLOSION_VERTICES 16
64 #define EXPLOSION_ELIPSE 1.17
65 #define SIGHT_DIST 78.74 /* distanc of sights in inch */
68 * render item definition and structures
72 enum render_item_type {
73 RENDER_ITEM_OBJECT_INFO,
74 RENDER_ITEM_VERTICES_0,
75 RENDER_ITEM_VERTICES_1,
76 RENDER_ITEM_VERTICES_2,
77 RENDER_ITEM_VERTICES_INTERIOR,
80 RENDER_ITEM_OBJECT_POLYGON,
81 RENDER_ITEM_OBJECT_LINE,
82 RENDER_ITEM_BEACON_POINT,
83 RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
84 RENDER_ITEM_BUILDING_EXTERIOR_LINE,
85 RENDER_ITEM_BUILDING_INTERIOR_1TO4,
86 RENDER_ITEM_BUILDING_INTERIOR_5TO6,
87 RENDER_ITEM_BUILDING_INTERIOR_WALL,
88 RENDER_ITEM_COMET_POLYGON,
89 RENDER_ITEM_ROAD_LINE,
90 RENDER_ITEM_ROAD_POLYGON,
91 RENDER_ITEM_TAG_LINE_OBJECT,
92 RENDER_ITEM_TAG_LINE_OTHER,
93 RENDER_ITEM_TAG_POLYGON_OBJECT,
94 RENDER_ITEM_TAG_POLYGON_OTHER,
97 RENDER_ITEM_INTERSTELLAR_STARS,
98 RENDER_ITEM_INTERSTELLAR_SUN,
99 RENDER_ITEM_ISLAND_POLYGON,
101 RENDER_ITEM_EXPLOSION,
104 struct render_item_info {
107 int32_t east, height, north;
110 struct render_item_vertices {
111 double x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
114 struct render_item_vertices_interior {
115 uint8_t set[MAX_INTERIOR_VERTEX >> 2];
116 double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
119 struct render_item_sky {
120 double red, green, blue;
123 struct render_item_ground {
124 double red, green, blue;
127 struct render_item_polygon {
128 double red, green, blue;
130 int vertex[MAX_POLYGON];
133 struct render_item_interior14 {
134 double red, green, blue;
139 struct render_item_interior56 {
140 double red, green, blue;
147 struct render_item_line {
148 double red, green, blue;
152 struct render_item_point {
153 double red, green, blue;
157 struct render_item_planet {
158 double front_red, front_green, front_blue;
159 double back_red, back_green, back_blue;
164 struct render_item_stars {
171 struct render_item_interstars {
172 uint8_t color[MAX_INTERSTARS];
173 int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
177 struct render_item_explosion {
178 double red, green, blue;
179 int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
183 typedef struct render_item {
184 struct render_item *next;
185 enum render_item_type type;
187 struct render_item_info info;
188 struct render_item_vertices vertices;
189 struct render_item_vertices_interior vertices_interior;
190 struct render_item_sky sky;
191 struct render_item_ground ground;
192 struct render_item_polygon polygon;
193 struct render_item_line line;
194 struct render_item_point point;
195 struct render_item_interior14 interior14;
196 struct render_item_interior56 interior56;
197 struct render_item_planet planet;
198 struct render_item_stars stars;
199 struct render_item_interstars interstars;
200 struct render_item_explosion explosion;
204 /* information about motion in each game rendering */
205 typedef struct motion {
206 int32_t position_east, position_height, position_north;
207 double orientation_roll, orientation_pitch, orientation_yaw;
208 uint16_t orientation_raw_yaw;
209 int16_t orientation_raw_pitch;
211 double planet_inclination, planet_azimuth;
214 /* information about interpolation between two game renedrings */
215 typedef struct interpolation {
216 double offset_east, offset_height, offset_north;
217 double orientation_roll, orientation_pitch, orientation_yaw;
218 double orientation_raw_yaw, orientation_raw_pitch;
219 double planet_inclination, planet_azimuth;
220 int object_id[MAX_MOVING_OBJECTS];
221 double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
223 render_item_t *interior;
224 render_item_t *planets;
227 #define GET_ORIENTATION \
228 double roll = interpolation.orientation_roll; \
229 double pitch = interpolation.orientation_pitch; \
230 double yaw = interpolation.orientation_yaw
232 #define GET_ORIENTATION_FIX \
233 roll = motion_new.orientation_roll; \
234 pitch = motion_new.orientation_pitch; \
235 yaw = motion_new.orientation_yaw
237 /* rendering options */
238 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
240 static double debug_opacity;
241 static double frustum_slope_64, frustum_slope_fov;
243 /* states while collecting render items */
244 static motion_t motion_old, motion_new;
245 static int32_t old_height_offset = 0, new_height_offset = 0;
246 static interpolation_t interpolation;
247 static int ground_index, last_ground_index = -1;
248 static int interior_level12 = 0;
249 static int interior_level34 = 0;
250 static int tag_is_object;
251 /* current render item list */
252 static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
253 /* previous render item list */
254 static render_item_t *render_list_old = NULL;
255 /* current item to be processed */
256 static render_item_t *render_item;
257 /* current object info */
258 static render_item_t *render_item_object_info;
259 /* current vertices */
260 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
261 static render_item_t *render_item_vertices_planets, *render_item_vertices_interior;
267 static void render_item_add(enum render_item_type type)
269 render_item = calloc(1, sizeof(render_item_t));
271 print_error("No memory, must abort!\n");
274 render_item->type = type;
275 *render_list_end = render_item;
276 render_list_end = &render_item->next;
279 static void flush_old_items(void)
281 /* flush old render list */
282 while (render_list_old) {
283 render_item = render_list_old;
284 render_list_old = render_list_old->next;
289 /* rendering starts, initialize variables */
290 void render_capture_start(double _fov, int _extend_roads, int _smooth_planets, int debug)
292 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
293 printf("start rendering a new frame...\n");
298 /* move new render list to old render list */
299 render_list_old = render_list_new;
300 /* setup new render list */
301 render_list_new = NULL;
302 render_list_end = &render_list_new;
304 /* move new motion to old motion */
305 memcpy(&motion_old, &motion_new, sizeof(motion_old));
307 /* set rendering options */
309 extend_roads = _extend_roads;
310 /* set some transpareny, if debugging is enabled */
311 debug_opacity = (debug) ? 0.5 : 1.0;
313 /* calculate slope of 64 degree frustum and current FOV's frustum */
314 frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
315 frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
318 mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
319 /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
320 mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
321 mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
322 motion_new.planet_rotation = motion_old.planet_rotation;
323 mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth, _smooth_planets);
325 render_item_object_info = NULL;
326 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
327 render_item_vertices_planets = NULL;
328 render_item_vertices_interior = NULL;
330 /* detect elevator movement */
331 old_height_offset = new_height_offset;
333 new_height_offset = motion_new.position_height - motion_old.position_height;
335 /* detect switching between space (-1) and over ground (>=0) */
336 last_ground_index = ground_index;
342 void render_capture_stop(void)
344 /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
345 if (!render_list_new) {
346 render_list_new = render_list_old;
347 render_list_end = &render_list_new;
348 render_list_old = NULL;
353 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
358 /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
360 palette = mercenary_palette_render();
361 color = m68k_read_memory_16(palette + index);
363 printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
365 if (color >= 0x8000) {
367 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
370 *red = (double)((color >> 8) & 0xf) / 15.0;
371 *green = (double)((color >> 4) & 0xf) / 15.0;
372 *blue = (double)(color & 0xf) / 15.0;
375 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
382 printf("color is given as 0x%04x\n", color);
385 /* color conversion: see for example M3: 0x4f830 */
386 if (color < 0x8000) {
387 /* use given color but shift it left by 1 */
390 printf("using given color, color is now 0x%04x\n", color);
392 } else if ((color & 0xff) < 0x80) {
393 gamecolor2gl_index(red, green, blue, color & 0xf);
396 /* use given index from pre-defined palette */
397 index = color & 0x7e;
398 palette = mercenary_palette_predefined();
399 color = m68k_read_memory_16(palette + index);
401 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
403 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
404 if (nesting++ == 8) {
405 print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
410 *red = (double)((color >> 8) & 0xf) / 15.0;
411 *green = (double)((color >> 4) & 0xf) / 15.0;
412 *blue = (double)(color & 0xf) / 15.0;
415 static int32_t wrap_int28(int32_t value)
422 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
425 print_info("Vertex %d is not a multiple of four!\n", vertex);
428 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
429 if (vertex < 0x100) {
430 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
431 render_item_add(RENDER_ITEM_VERTICES_0);
432 /* copy vertices that have been captured already */
433 if (render_item_vertices_0)
434 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
435 render_item_vertices_0 = render_item;
438 if (vertex < 0x200) {
439 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
440 render_item_add(RENDER_ITEM_VERTICES_1);
441 /* copy vertices that have been captured already */
442 if (render_item_vertices_1)
443 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
444 render_item_vertices_1 = render_item;
448 if (vertex < 0x300) {
449 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
450 render_item_add(RENDER_ITEM_VERTICES_2);
451 /* copy vertices that have been captured already */
452 if (render_item_vertices_2)
453 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
454 render_item_vertices_2 = render_item;
458 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
463 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
465 /* use absolute position */
466 x += motion_new.position_east;
467 y += motion_new.position_height;
468 z += motion_new.position_north;
469 render_item->u.vertices.x[vertex] = x;
470 render_item->u.vertices.y[vertex] = y;
471 render_item->u.vertices.z[vertex] = z;
474 static void store_planets_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
477 print_info("Vertex %d is not a multiple of four!\n", vertex);
480 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
481 if (vertex >= MAX_VERTEX) {
482 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
485 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
486 render_item_add(RENDER_ITEM_VERTICES_0);
487 /* copy vertices that have been captured already */
488 if (render_item_vertices_0)
489 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
490 render_item_vertices_0 = render_item;
494 printf("storing %s coordinates: vertex=%d, x=%d, y=%d, z=%d\n", what, vertex, x, y, z);
496 render_item->u.vertices.x[vertex] = x;
497 render_item->u.vertices.y[vertex] = y;
498 render_item->u.vertices.z[vertex] = z;
501 static void store_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y1, int32_t y2, int32_t y3, int32_t y4, int32_t z)
504 print_info("Vertex is not a multiple of four!\n");
507 if (vertex >= MAX_INTERIOR_VERTEX) {
508 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
511 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
512 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
515 printf("storing %s coordinates: vertex=%d, x=%d, y=%d;%d;%d;%d, z=%d\n", what, vertex, x, y1, y2, y3, y4, z);
517 /* use absolute position */
518 x += motion_new.position_east;
519 y1 += motion_new.position_height;
520 y2 += motion_new.position_height;
521 y3 += motion_new.position_height;
522 y4 += motion_new.position_height;
523 z += motion_new.position_north;
524 render_item->u.vertices_interior.x[vertex] = (double)x;
525 render_item->u.vertices_interior.y[0] = (double)y1;
526 render_item->u.vertices_interior.y[1] = (double)y2;
527 render_item->u.vertices_interior.y[2] = (double)y3;
528 render_item->u.vertices_interior.y[3] = (double)y4;
529 render_item->u.vertices_interior.z[vertex] = (double)z;
530 render_item->u.vertices_interior.set[vertex] = 1;
533 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
535 double out_x, out_y, out_z;
537 /* rotate yaw (German: Gier, turn view to the right) */
539 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
540 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
544 /* rotate pitch (German: Nick, turn head down) */
546 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
547 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
551 /* rotate roll (tilt head to the right) */
553 out_x = (*x) * cos(roll) - (*y) * sin(roll);
554 out_y = (*x) * sin(roll) + (*y) * cos(roll);
560 /* clear screen color (sky / universe) */
561 static void clear_screen(int index)
564 printf("clear screen:\n");
567 /* allocate render item */
568 render_item_add(RENDER_ITEM_SKY);
571 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
573 /* store for later use after planets have been rendered */
574 ground_index = index;
578 static void draw_ground(void)
580 /* no ground in space :) */
581 if (ground_index < 0)
585 printf("add ground plane:\n");
588 /* allocate render item */
589 render_item_add(RENDER_ITEM_GROUND);
592 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
596 static void info_object(int moving)
599 printf("add object's info:\n");
602 /* allocate render item */
603 render_item_add(RENDER_ITEM_OBJECT_INFO);
606 render_item->u.info.moving = moving;
608 mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
611 /* coordinates ready for an object */
612 static void coord_object(void)
616 x = (int16_t)REG_D[3];
617 x += (int32_t)REG_A[1];
618 y = (int16_t)REG_D[4];
619 y += (int32_t)REG_A[2];
620 z = (int16_t)REG_D[5];
621 z += (int32_t)REG_A[3];
622 store_coord("object", REG_A[0], x, y, z);
625 /* polygon of object */
626 static void poly_object(int mercenary)
628 uint32_t vertex_address = REG_A[0];
633 printf("add object's polygon:\n");
636 /* allocate render item */
637 render_item_add(RENDER_ITEM_OBJECT_POLYGON);
641 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
644 color = m68k_read_memory_8(vertex_address++) << 8;
645 color |= m68k_read_memory_8(vertex_address++);
646 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
649 /* the vertex list is zero-terminated */
650 for (i = 0; i < MAX_POLYGON; i++) {
651 vertex = m68k_read_memory_8(vertex_address++);
652 if (vertex == 0 && i)
654 render_item->u.polygon.vertex[i] = vertex;
656 render_item->u.polygon.vertices = i;
660 static void line_object(void)
662 uint32_t vertex_address = REG_A[0];
666 printf("add object's line:\n");
669 /* allocate render item */
670 render_item_add(RENDER_ITEM_OBJECT_LINE);
673 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
676 vertex = m68k_read_memory_8(vertex_address++);
677 render_item->u.line.vertex[0] = vertex;
678 vertex = m68k_read_memory_8(vertex_address++);
679 render_item->u.line.vertex[1] = vertex;
682 /* coordinates ready for a beacon */
683 static void coord_beacon(void)
687 /* only 28 bits seem to be a correct signed int value */
688 x = (int32_t)(REG_D[3] << 4) / 16;
689 y = (int32_t)(REG_D[4] << 4) / 16;
690 z = (int32_t)(REG_D[5] << 4) / 16;
691 store_coord("beacon", 0, x, y, z);
694 /* point of beacon */
695 static void point_beacon(void)
698 printf("add beacon's point:\n");
701 /* allocate render item */
702 render_item_add(RENDER_ITEM_BEACON_POINT);
705 gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
708 render_item->u.point.vertex = 0;
711 /* coordinates ready for a building (exterior) */
712 static void coord_building_exterior(void)
716 x = (int32_t)REG_D[3];
717 y = (int32_t)REG_D[4];
718 z = (int32_t)REG_D[5];
719 store_coord("building exterior", REG_A[0], x, y, z);
722 /* polygon of building (exterior) */
723 static void poly_building_exterior(void)
726 uint32_t vertex_address = REG_A[0];
731 printf("add building's polygon:\n");
734 /* allocate render item */
735 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
738 color = m68k_read_memory_8(vertex_address++) << 8;
739 color |= m68k_read_memory_8(vertex_address++);
740 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
742 /* the vertex list is zero-terminated */
743 for (i = 0; i < MAX_POLYGON; i++) {
744 vertex = m68k_read_memory_8(vertex_address++);
745 if (vertex == 0 && i)
747 render_item->u.polygon.vertex[i] = vertex | 0x100;
749 render_item->u.polygon.vertices = i;
752 /* line of building (exterior) */
753 static void line_building_exterior(void)
755 uint32_t vertex_address = REG_A[0];
759 printf("add building's line:\n");
762 /* allocate render item */
763 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
766 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
769 vertex = m68k_read_memory_8(vertex_address++);
770 render_item->u.line.vertex[0] = vertex | 0x100;
771 vertex = m68k_read_memory_8(vertex_address++);
772 render_item->u.line.vertex[1] = vertex | 0x100;
775 /* coordinates ready for a building (interior) */
776 static void coord_building_interior(void)
779 int32_t height1, height2, height3, height4;
781 mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
782 store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
785 /* polygon of building (interior) */
786 static void poly_building_interior1to4(int level)
793 printf("add roof/floor's polygon at level %d:\n", level);
796 /* allocate render item */
797 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
800 color = m68k_read_memory_8(REG_A[0]) << 8;
801 color |= m68k_read_memory_8(REG_A[0] + 1);
802 gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
804 /* four vertices, one level */
805 for (i = 0; i < 4; i++) {
806 vertex = REG_A[(2 + i)];
807 render_item->u.interior14.vertex[i] = vertex;
809 render_item->u.interior14.level = level;
812 /* polygon of building (interior) */
813 static void poly_building_interior5to6(int level12, int level34)
818 printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
821 /* allocate render item */
822 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
825 color = m68k_read_memory_8(REG_A[0]) << 8;
826 color |= m68k_read_memory_8(REG_A[0] + 1);
827 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
829 /* two vertices, two levels */
830 render_item->u.interior56.vertex14 = REG_A[2];
831 render_item->u.interior56.vertex23 = REG_A[3];
832 render_item->u.interior56.level12 = level12;
833 render_item->u.interior56.level34 = level34;
836 /* wall part of a building */
837 static void wall_building(void)
840 printf("add wall:\n");
843 /* allocate render item */
844 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
847 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
849 /* two vertices, two levels */
850 render_item->u.interior56.vertex14 = REG_A[1];
851 render_item->u.interior56.vertex23 = REG_A[2];
852 /* get top level according to bit 12 in D3 */
853 render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
854 render_item->u.interior56.level34 = 1;
857 /* coordinates ready for comet tail */
858 static void coord_comet(void)
862 x = (int32_t)REG_D[3];
863 y = (int32_t)REG_D[4];
864 z = (int32_t)REG_D[5];
865 store_planets_coord("comet tail", REG_A[0], x, y, z);
868 /* polygon of comet tail */
869 static void poly_comet(void)
872 uint32_t vertex_address = REG_A[0];
877 printf("add comet's polygon:\n");
880 /* allocate render item */
881 render_item_add(RENDER_ITEM_COMET_POLYGON);
884 color = m68k_read_memory_8(vertex_address++) << 8;
885 color |= m68k_read_memory_8(vertex_address++);
886 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
888 /* the vertex list is zero-terminated */
889 for (i = 0; i < MAX_POLYGON; i++) {
890 vertex = m68k_read_memory_8(vertex_address++);
891 if (vertex == 0 && i)
893 render_item->u.polygon.vertex[i] = vertex;
895 render_item->u.polygon.vertices = i;
898 /* coordinates ready for lines of a road / ground surface */
899 static void coord_line_road(void)
904 y = -motion_new.position_height;
906 store_coord("road", REG_A[0], x, y, z);
910 static void line_road(void)
915 printf("add road's line:\n");
918 /* allocate render item */
919 render_item_add(RENDER_ITEM_ROAD_LINE);
922 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
926 render_item->u.line.vertex[0] = vertex;
928 render_item->u.line.vertex[1] = vertex;
931 /* coordinates ready for polygons of a road / ground surface */
932 static void coord_poly_road(void)
936 x = m68k_read_memory_32(320 + REG_A[0]);
938 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
939 y = -motion_new.position_height;
940 z = m68k_read_memory_32(576 + REG_A[0]);
942 store_coord("road/place", REG_A[0], x, y, z);
945 /* polygon of road */
946 static void poly_road()
949 uint32_t vertex_address = REG_A[0];
954 printf("add road/place's polygon:\n");
957 /* allocate render item */
958 render_item_add(RENDER_ITEM_ROAD_POLYGON);
961 color = m68k_read_memory_8(vertex_address++) << 8;
962 color |= m68k_read_memory_8(vertex_address++);
963 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
965 /* the vertex list is zero-terminated */
966 for (i = 0; i < MAX_POLYGON; i++) {
967 vertex = m68k_read_memory_8(vertex_address++);
968 if (vertex == 0 && i)
970 render_item->u.polygon.vertex[i] = vertex;
972 render_item->u.polygon.vertices = i;
975 /* coordinates ready for tags */
976 static void coord_tags(void)
980 x = (int16_t)REG_D[3];
981 x += (int32_t)REG_A[1];
982 y = (int16_t)REG_D[4];
983 y += (int32_t)REG_A[2];
984 z = (int16_t)REG_D[5];
985 z += (int32_t)REG_A[3];
986 store_coord("tags", REG_A[0], x, y, z);
989 /* coordinates ready for large tags */
990 static void coord_tags2(void)
994 x = (int16_t)REG_D[3];
995 x += 2 * (int32_t)REG_A[1];
996 y = (int16_t)REG_D[4];
997 y += 2 * (int32_t)REG_A[2];
998 z = (int16_t)REG_D[5];
999 z += 2 * (int32_t)REG_A[3];
1000 store_coord("large tags", REG_A[0], x, y, z);
1004 static void line_tags(int last_color)
1006 uint32_t vertex_address = REG_A[0];
1010 printf("add tag's line:\n");
1013 /* allocate render item */
1014 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
1018 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
1020 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
1023 vertex = m68k_read_memory_8(vertex_address++);
1024 render_item->u.line.vertex[0] = vertex | 0x200;
1025 vertex = m68k_read_memory_8(vertex_address++);
1026 render_item->u.line.vertex[1] = vertex | 0x200;
1029 /* polygon of tags */
1030 static void poly_tags(int last_color)
1032 uint32_t vertex_address = REG_A[0];
1037 printf("add tag's polygon:\n");
1040 /* allocate render item */
1041 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1045 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1047 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
1048 /* the vertex list is zero-terminated */
1049 for (i = 0; i < MAX_POLYGON; i++) {
1050 vertex = m68k_read_memory_8(vertex_address++);
1051 if (vertex == 0 && i)
1053 render_item->u.polygon.vertex[i] = vertex | 0x200;
1055 render_item->u.polygon.vertices = i;
1058 /* coordinates ready for planet */
1059 static void coord_planet(void)
1063 x = (int32_t)REG_D[3];
1064 y = (int32_t)REG_D[4];
1065 z = (int32_t)REG_D[5];
1066 store_planets_coord("planet", REG_A[0], x, y, z);
1070 static void draw_planet(int comet)
1073 uint32_t scale_index;
1074 double scale1, scale2;
1078 /* fixing (not noticable) bug in game: don't render comet twice */
1079 if (!comet && vertex == 116)
1083 printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1086 /* allocate render item */
1087 render_item_add(RENDER_ITEM_PLANET);
1091 /* make comet black on front side and bright on back */
1092 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
1093 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
1096 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
1097 /* use background color for dark side */
1098 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
1102 render_item->u.planet.vertex = vertex;
1104 /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
1105 * the long word 21584(A0) contains two scales
1106 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1107 * the upper word defines how much this scale is shifted to the left.
1109 scale_index = mercenary_planet_scale_index();
1110 scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
1111 scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
1112 render_item->u.planet.size = scale1 * scale2 / 128.0;
1116 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1119 printf("add stars\n");
1122 /* allocate render item */
1123 render_item_add(RENDER_ITEM_STARS);
1125 /* vertical offset */
1126 render_item->u.stars.v_offset = v_offset;
1128 /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
1129 render_item->u.stars.tilt = tilt;
1131 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1133 /* stars above zenith */
1134 render_item->u.stars.above_zenith = above_zenith;
1137 /* stars of interstellar flight */
1138 static void draw_stars_interstellar(void)
1144 printf("add interstellar stars\n");
1147 /* allocate render item */
1148 render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1151 count = REG_D[5] + 1;
1152 if (count > MAX_INTERSTARS) {
1153 print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
1156 for (i = 0; i < count; i++) {
1159 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1161 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1163 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1166 render_item->u.interstars.count = count;
1169 /* sun of interstellar flight (center dot) */
1170 static void draw_sun_interstellar(void)
1173 printf("add interstellar sun\n");
1176 /* allocate render item */
1177 render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1180 /* coordinates ready for polygons of islands */
1181 static void coord_islands(void)
1185 x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1186 x += (int32_t)REG_A[1];
1187 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1188 y = -motion_new.position_height;
1189 z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1190 z += (int32_t)REG_A[3];
1191 store_coord("island", REG_A[0], x, y, z);
1194 /* polygon of island */
1195 static void poly_island()
1198 uint32_t vertex_address = REG_A[0];
1203 printf("add island:\n");
1206 /* allocate render item */
1207 render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1210 color = m68k_read_memory_8(vertex_address++) << 8;
1211 color |= m68k_read_memory_8(vertex_address++);
1212 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1214 /* the vertex list is zero-terminated */
1216 while (i < MAX_POLYGON) {
1217 vertex = m68k_read_memory_8(vertex_address++);
1218 if (vertex == 0 && i)
1220 /* skip mysterious points when rendering island */
1223 render_item->u.polygon.vertex[i] = vertex;
1226 render_item->u.polygon.vertices = i;
1230 static void draw_sights(void)
1233 printf("add sights:\n");
1236 /* allocate render item */
1237 render_item_add(RENDER_ITEM_SIGHTS);
1240 static void draw_explosion(void)
1245 printf("add explosion:\n");
1248 /* allocate render item */
1249 if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
1250 render_item_add(RENDER_ITEM_EXPLOSION);
1251 /* get color from render palette */
1252 color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
1253 gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
1254 render_item->u.explosion.count = 0;
1256 if (render_item->u.explosion.count == MAX_EXPLOSION)
1258 render_item->u.explosion.x[render_item->u.explosion.count] = REG_D[3];
1259 render_item->u.explosion.y[render_item->u.explosion.count] = REG_D[4];
1260 render_item->u.explosion.z[render_item->u.explosion.count] = REG_D[5];
1261 render_item->u.explosion.count++;
1264 /* stop event from CPU received */
1265 void render_capture_event(int event)
1268 case STOP_AT_CLEAR_SCREEN1:
1269 clear_screen(16); /* color 16 is raster split */
1270 /* in case of screen clearing on the ground, there is no roll */
1271 motion_new.orientation_roll = 0;
1273 case STOP_AT_CLEAR_SCREEN2:
1276 case STOP_AT_CLEAR_SCREEN3:
1277 clear_screen(-1); /* no ground (in universe) */
1279 case STOP_AT_DRAW_GROUND:
1282 case STOP_AT_INFO_OBJECT_MOVING:
1285 case STOP_AT_INFO_OBJECT_FIX:
1288 case STOP_AT_TAG_IS_OBJECT_1:
1291 case STOP_AT_TAG_IS_OBJECT_0:
1294 case STOP_AT_COORD_OBJECT:
1297 case STOP_AT_POLY_OBJECT_M3:
1300 case STOP_AT_POLY_OBJECT_M2:
1303 case STOP_AT_LINE_OBJECT:
1306 case STOP_AT_COORD_BEACON:
1309 case STOP_AT_POINT_BEACON:
1311 /* note: we may not call the point-renderer, because projected coordinates are invalid */
1312 mercenary_patch_render();
1314 case STOP_AT_COORD_BUILDING_EXTERIOR:
1315 coord_building_exterior();
1317 case STOP_AT_POLY_BUILDING_EXTERIOR:
1318 poly_building_exterior();
1320 case STOP_AT_LINE_BUILDING_EXTERIOR:
1321 line_building_exterior();
1323 case STOP_AT_COORD_BUILDING_INTERIOR:
1324 coord_building_interior();
1326 case STOP_AT_POLY_BUILDING_INTERIOR1:
1328 interior_level12 = 1;
1329 interior_level34 = 1;
1331 case STOP_AT_POLY_BUILDING_INTERIOR2:
1333 interior_level12 = 2;
1334 interior_level34 = 2;
1336 case STOP_AT_POLY_BUILDING_INTERIOR3:
1337 /* door/window top */
1338 interior_level12 = 3;
1339 interior_level34 = 3;
1341 case STOP_AT_POLY_BUILDING_INTERIOR4:
1343 interior_level12 = 4;
1344 interior_level34 = 4;
1346 case STOP_AT_POLY_BUILDING_INTERIOR5:
1347 /* door/window top */
1348 interior_level12 = 2;
1349 interior_level34 = 3;
1351 case STOP_AT_POLY_BUILDING_INTERIOR6:
1353 interior_level12 = 1;
1354 interior_level34 = 4;
1356 case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1357 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1358 if (interior_level12 == 0) {
1359 print_info("Interior level is not set, please fix!\n");
1362 poly_building_interior1to4(interior_level12);
1363 interior_level12 = 0;
1365 case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1366 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1367 if (interior_level12 == 0) {
1368 print_info("Interior level is not set, please fix!\n");
1371 poly_building_interior5to6(interior_level12, interior_level34);
1372 interior_level12 = 0;
1374 case STOP_AT_WALL_BUILDING:
1377 case STOP_AT_COORD_COMET:
1380 case STOP_AT_MATRIX_COMET:
1381 case STOP_AT_MATRIX_PLANET:
1382 /* track the rotation matrix
1383 * if we have 0x42c44 matrix, we must add extra rotation to planet.
1384 * the rotation will change the view from the planet's surface */
1385 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1386 motion_new.planet_rotation = 1;
1388 motion_new.planet_rotation = 0;
1390 case STOP_AT_POLY_COMET:
1393 case STOP_AT_COORD_LINE_ROADS:
1396 case STOP_AT_LINE_ROADS:
1399 case STOP_AT_COORD_POLY_ROADS:
1402 case STOP_AT_LINE_ROADS_CENTER:
1403 /* we don't need to render center lines of roads, because there are polygons already
1404 * it does not make sense, since OpenGL has much higher resolution.
1407 case STOP_AT_POLY_ROADS:
1410 case STOP_AT_COORD_TAGS:
1413 case STOP_AT_COORD_TAGS2:
1416 case STOP_AT_LINE_TAGS1:
1419 case STOP_AT_LINE_TAGS2:
1422 case STOP_AT_POLY_TAGS1:
1425 case STOP_AT_POLY_TAGS2:
1428 case STOP_AT_COORD_PLANET:
1431 case STOP_AT_DRAW_PLANET:
1434 case STOP_AT_DRAW_COMET:
1437 case STOP_AT_DRAW_STARS_SPACE:
1438 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1439 draw_stars(0x1c0, 0, 0);
1441 case STOP_AT_DRAW_STARS_GROUND:
1442 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1443 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1445 case STOP_AT_DRAW_STARS_FLYING:
1446 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1447 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1449 case STOP_AT_DRAW_STARS_FLYING2:
1450 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1451 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1453 case STOP_AT_DRAW_STARS_INTERSTELLAR:
1454 draw_stars_interstellar();
1456 case STOP_AT_DRAW_SUN_INTERSTELLAR:
1457 draw_sun_interstellar();
1459 case STOP_AT_COORD_ISLANDS:
1462 case STOP_AT_POLY_ISLANDS:
1465 case STOP_AT_LINE_ISLANDS:
1466 /* this is not used, as i had noticed so far */
1467 puts("line island");
1469 case STOP_AT_DRAW_SIGHTS:
1472 case STOP_AT_POLY_UKN2:
1475 case STOP_AT_EXPLOSION:
1478 case STOP_AT_PATCH_RENDER:
1479 mercenary_patch_render();
1488 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix)
1490 render_item_t *ri = NULL;
1493 print_info("Vertex %d is not a multiple of four!\n", vertex);
1496 if (vertex < 0x100) {
1497 if (!render_item_vertices_0) {
1498 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1501 ri = render_item_vertices_0;
1503 if (vertex < 0x200) {
1504 if (!render_item_vertices_1) {
1505 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1508 ri = render_item_vertices_1;
1511 if (vertex < 0x300) {
1512 if (!render_item_vertices_2) {
1513 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1516 ri = render_item_vertices_2;
1519 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1523 /* translate to original position */
1524 *x = ri->u.vertices.x[vertex] - motion_new.position_east;
1525 *y = ri->u.vertices.y[vertex] - motion_new.position_height;
1526 *z = ri->u.vertices.z[vertex] - motion_new.position_north;
1528 /* translate to floating (interpolated) position offset */
1529 *x -= interpolation.offset_east;
1530 *y -= interpolation.offset_height;
1531 *z -= interpolation.offset_north;
1534 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1540 static int use_planet_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1542 render_item_t *ri = NULL;
1545 print_info("Vertex %d is not a multiple of four!\n", vertex);
1548 if (vertex >= MAX_VERTEX) {
1549 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1552 if (interpolation.planets)
1553 ri = interpolation.planets;
1555 ri = render_item_vertices_0;
1557 print_info("Vertices item for planets verticies not yet set!\n");
1561 *x = ri->u.vertices.x[vertex];
1562 *y = ri->u.vertices.y[vertex];
1563 *z = ri->u.vertices.z[vertex];
1565 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1571 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1574 print_info("Vertex is not a multiple of four!\n");
1577 if (vertex >= MAX_INTERIOR_VERTEX) {
1578 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1581 if (level < 1 || level > 4) {
1582 print_info("Level %d is out of range (1..4)!\n", level);
1585 if (!render_item_vertices_interior) {
1586 print_info("Vertices item for interior verticies not yet set!\n");
1590 *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1591 *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1592 *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1593 /* translate to position back to original */
1594 *x -= motion_new.position_east;
1595 *y -= motion_new.position_height;
1596 *z -= motion_new.position_north;
1597 /* translate to floating (interpolated) position offset */
1598 *x -= interpolation.offset_east;
1599 *y -= interpolation.offset_height;
1600 *z -= interpolation.offset_north;
1603 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1609 /* renders one item from render list */
1610 void render_one_item(render_item_t *render_item, int vr)
1612 switch (render_item->type) {
1613 case RENDER_ITEM_OBJECT_INFO:
1616 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1618 render_item_object_info = render_item;
1621 case RENDER_ITEM_VERTICES_0:
1624 printf("RENDER_ITEM_VERTICES_0\n");
1626 render_item_vertices_0 = render_item;
1629 case RENDER_ITEM_VERTICES_1:
1632 printf("RENDER_ITEM_VERTICES_1\n");
1634 render_item_vertices_1 = render_item;
1637 case RENDER_ITEM_VERTICES_2:
1640 printf("RENDER_ITEM_VERTICES_2\n");
1642 render_item_vertices_2 = render_item;
1645 case RENDER_ITEM_VERTICES_INTERIOR:
1648 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1650 if (interpolation.interior)
1651 render_item_vertices_interior = interpolation.interior;
1653 render_item_vertices_interior = render_item;
1656 case RENDER_ITEM_SKY:
1658 double x[4], y[4], z[4];
1661 printf("RENDER_ITEM_SKY\n");
1664 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1665 /* create box to fill view */
1666 x[0] = x[1] = y[1] = y[2] = -1000;
1667 x[2] = x[3] = y[0] = y[3] = 1000;
1668 z[0] = z[1] = z[2] = z[3] = 1000;
1669 opengl_render_polygon_and_line(x, y, z, 4);
1670 z[0] = z[1] = z[2] = z[3] = -1000;
1671 opengl_render_polygon_and_line(x, y, z, 4);
1672 x[0] = x[1] = z[1] = z[2] = -1000;
1673 x[2] = x[3] = z[0] = z[3] = 1000;
1674 y[0] = y[1] = y[2] = y[3] = 1000;
1675 opengl_render_polygon_and_line(x, y, z, 4);
1676 y[0] = y[1] = y[2] = y[3] = -1000;
1677 opengl_render_polygon_and_line(x, y, z, 4);
1678 y[0] = y[1] = z[1] = z[2] = -1000;
1679 y[2] = y[3] = z[0] = z[3] = 1000;
1680 x[0] = x[1] = x[2] = x[3] = 1000;
1681 opengl_render_polygon_and_line(x, y, z, 4);
1682 x[0] = x[1] = x[2] = x[3] = -1000;
1683 opengl_render_polygon_and_line(x, y, z, 4);
1686 case RENDER_ITEM_GROUND:
1689 double x[4], y[4], z[4];
1693 printf("RENDER_ITEM_GROUND\n");
1696 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1697 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1698 /* create huge square */
1699 x[0] = x[1] = z[1] = z[2] = -1000000000;
1700 x[2] = x[3] = z[0] = z[3] = 1000000000;
1701 y[0] = y[1] = y[2] = y[3] = -1000;
1703 for (i = 0; i < 4; i++)
1704 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1706 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1709 case RENDER_ITEM_OBJECT_POLYGON:
1710 case RENDER_ITEM_TAG_POLYGON_OBJECT:
1711 case RENDER_ITEM_TAG_POLYGON_OTHER:
1712 case RENDER_ITEM_ISLAND_POLYGON:
1716 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1721 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1722 printf("RENDER_ITEM_OBJECT_POLYGON\n");
1723 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
1724 printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
1725 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
1726 printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
1727 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1728 printf("RENDER_ITEM_ISLAND_POLYGON\n");
1731 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1732 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) {
1733 // GET_ORIENTATION_FIX;
1738 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1739 /* get and rotate vertex */
1740 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1742 rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
1745 /* interpolate motion, if object is moving */
1746 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) {
1747 for (o = 0; o < interpolation.object_count; o++) {
1748 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1751 if (o < interpolation.object_count) {
1752 x[i] += interpolation.object_offset_east[o];
1753 y[i] += interpolation.object_offset_height[o];
1754 z[i] += interpolation.object_offset_north[o];
1758 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1761 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1764 case RENDER_ITEM_OBJECT_LINE:
1765 case RENDER_ITEM_TAG_LINE_OBJECT:
1766 case RENDER_ITEM_TAG_LINE_OTHER:
1770 double x[2], y[2], z[2];
1775 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1776 printf("RENDER_ITEM_OBJECT_LINE\n");
1777 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
1778 printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
1779 if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
1780 printf("RENDER_ITEM_TAG_LINE_OTHER\n");
1783 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1784 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) {
1785 // GET_ORIENTATION_FIX;
1790 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1791 /* get and rotate vertex */
1792 for (i = 0; i < 2; i++) {
1794 rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
1797 /* interpolate motion, if object is moving */
1798 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) {
1799 for (o = 0; o < interpolation.object_count; o++) {
1800 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1803 if (o < interpolation.object_count) {
1804 x[i] += interpolation.object_offset_east[o];
1805 y[i] += interpolation.object_offset_height[o];
1806 z[i] += interpolation.object_offset_north[o];
1810 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1813 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1816 case RENDER_ITEM_BEACON_POINT:
1823 printf("RENDER_ITEM_BEACON_POINT\n");
1826 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1828 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
1832 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1834 opengl_render_point(x, y, z, 0.0);
1837 case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1840 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1845 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1848 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1849 /* get and rotate vertex */
1850 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1852 rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
1856 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1859 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1862 case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
1865 double x[2], y[2], z[2];
1870 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1873 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1874 /* get and rotate vertex */
1875 for (i = 0; i < 2; i++) {
1877 rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
1881 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1884 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1887 case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1890 double x[4], y[4], z[4];
1895 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1898 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1899 /* get and rotate vertex */
1900 for (i = 0; i < 4; i++) {
1902 rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1906 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1909 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1912 case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1915 double x[4], y[4], z[4];
1921 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1924 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1925 /* get and rotate vertex */
1926 for (i = 0; i < 4; i++) {
1928 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1929 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1930 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1934 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1937 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1940 case RENDER_ITEM_BUILDING_INTERIOR_WALL:
1943 double x[4], y[4], z[4];
1949 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
1952 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1953 /* chedck if wall is a rectangle or a line */
1954 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
1955 /* get and rotate vertex */
1956 for (i = 0; i < 4; i++) {
1958 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1959 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1960 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1964 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1967 opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
1969 /* get and rotate vertex */
1970 for (i = 0; i < 2; i++) {
1972 vertex = render_item->u.interior56.vertex14;
1973 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1974 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1978 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1981 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1985 case RENDER_ITEM_COMET_POLYGON:
1988 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
1989 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1994 printf("RENDER_ITEM_COMET_POLYGON\n");
1997 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1998 /* get and rotate vertex */
1999 for (i = 0; i < render_item->u.polygon.vertices; i++) {
2001 rc = use_planet_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
2005 if (motion_new.planet_rotation)
2006 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
2007 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2010 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
2013 case RENDER_ITEM_ROAD_LINE:
2016 double x[2], y[2], z[2];
2021 printf("RENDER_ITEM_ROAD_LINE\n");
2024 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
2025 /* get and rotate vertex */
2026 for (i = 0; i < 2; i++) {
2028 rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
2032 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2035 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
2038 case RENDER_ITEM_ROAD_POLYGON:
2041 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
2043 uint32_t vertex, vertex_prev, vertex_next;
2044 double x_current, y_current, z_current;
2045 double x_prev, y_prev, z_prev;
2046 double x_next, y_next, z_next;
2051 printf("RENDER_ITEM_ROAD_POLYGON\n");
2054 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
2055 /* get and rotate vertex */
2057 vertices_num = render_item->u.polygon.vertices;
2058 for (v = 0; v < vertices_num; v++) {
2060 vertex = render_item->u.polygon.vertex[v];
2061 rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
2064 /* check for road extension, so we extend the road to the given end point */
2065 if (extend_roads && vertex >= 0xf0) {
2066 /* previous vertex */
2067 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
2068 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
2072 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
2073 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
2076 /* extend vertices to end point position
2077 * change x or z coordinate, whatever is greater
2079 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
2080 x_prev = x_next = x_current;
2082 z_prev = z_next = z_current;
2083 /* store vertices */
2088 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2089 if (i++ == MAX_POLYGON)
2095 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2096 if (i++ == MAX_POLYGON)
2100 /* no extension, just keep the current point as is */
2105 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2106 if (i++ == MAX_POLYGON)
2111 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2114 case RENDER_ITEM_PLANET:
2117 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2118 double sun_x, sun_y, sun_z, angle_sun_h;
2119 double loc_x, loc_y, loc_z, angle_loc_h, angle_loc_v;
2120 double circle_x[PLANET_VERTICES], circle_y[PLANET_VERTICES], circle_z[PLANET_VERTICES];
2121 double crescent_x[PLANET_VERTICES], crescent_y[PLANET_VERTICES], crescent_z[PLANET_VERTICES];
2122 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
2123 double size, angle, fabs_angle, crescent;
2129 printf("RENDER_ITEM_PLANET\n");
2132 rc = use_planet_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
2135 rc = use_planet_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
2139 size = render_item->u.planet.size;
2141 if (motion_new.planet_rotation) {
2142 rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
2143 rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
2145 rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
2146 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2148 /* calculate direction of the sun */
2149 angle_sun_h = atan2(sun_x, sun_z);
2150 angle_loc_h = atan2(loc_x, loc_z);
2151 angle_loc_v = atan2(loc_y, sqrt(loc_x * loc_x + loc_z * loc_z));
2152 /* angle between planets */
2153 angle = angle_sun_h - angle_loc_h;
2155 angle -= 2.0 * M_PI;
2157 angle += 2.0 * M_PI;
2158 /* absolute angle to be used as crescent */
2159 fabs_angle = fabs(angle);
2160 if (fabs_angle > M_PI / 2.0)
2161 fabs_angle = M_PI - fabs_angle;
2163 /* on which side are we (sun is always bright, vertex == 0) */
2164 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
2165 /* get front side color */
2166 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2168 /* get back side color */
2169 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2172 /* create and render cicle */
2173 crescent = sin((1.0 - fabs_angle / (M_PI / 2)) * (M_PI / 2.0));
2175 for (i = 0; i < PLANET_VERTICES; i++) {
2176 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2177 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2178 circle_x[i] = _sin * PLANET_ELIPSE;
2181 crescent_x[i] = circle_x[i] * crescent;
2182 crescent_y[i] = circle_y[i];
2183 crescent_z[i] = circle_z[i];
2184 /* rotate circle and cresent towards observer (billboarding) */
2185 rotate_coordinate(0.0, -angle_loc_v, 0.0, &circle_x[i], &circle_y[i], &circle_z[i]);
2186 rotate_coordinate(0.0, 0.0, angle_loc_h, &circle_x[i], &circle_y[i], &circle_z[i]);
2187 rotate_coordinate(0.0, -angle_loc_v, 0.0, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2188 rotate_coordinate(0.0, 0.0, angle_loc_h, &crescent_x[i], &crescent_y[i], &crescent_z[i]);
2191 for (i = 0; i < PLANET_VERTICES; i++) {
2192 _sin = size * sin(2.0 * M_PI * (double)i / PLANET_VERTICES);
2193 _cos = size * cos(2.0 * M_PI * (double)i / PLANET_VERTICES);
2194 circle_x[i] = _sin * PLANET_ELIPSE;
2197 crescent_x[i] = circle_x[i] * crescent;
2198 crescent_y[i] = circle_y[i];
2199 crescent_z[i] = circle_z[i];
2202 for (i = 0; i < PLANET_VERTICES; i++) {
2203 x[i] = loc_x + circle_x[i];
2204 y[i] = loc_y + circle_y[i];
2205 z[i] = loc_z + circle_z[i];
2207 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2209 if (render_item->u.planet.vertex == 0) {
2210 /* sun has no crescent */
2214 /* on which side are we */
2215 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
2216 /* get back side color */
2217 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2219 /* get front side color */
2220 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2223 /* create and render crescent */
2224 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2226 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2227 x[i] = loc_x + circle_x[i];
2228 y[i] = loc_y + circle_y[i];
2229 z[i] = loc_z + circle_z[i];
2231 _sin = sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2232 for (; i < PLANET_VERTICES; i++) {
2233 x[i] = loc_x + crescent_x[i];
2234 y[i] = loc_y + crescent_y[i];
2235 z[i] = loc_z + crescent_z[i];
2239 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2240 x[i] = loc_x + crescent_x[i];
2241 y[i] = loc_y + crescent_y[i];
2242 z[i] = loc_z + crescent_z[i];
2244 for (; i < PLANET_VERTICES; i++) {
2245 x[i] = loc_x + circle_x[i];
2246 y[i] = loc_y + circle_y[i];
2247 z[i] = loc_z + circle_z[i];
2250 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2251 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
2254 case RENDER_ITEM_STARS:
2256 double tilt_offset = 0;
2257 double x_offset = 0;
2259 double view_width, yaw = interpolation.orientation_raw_yaw;
2260 double pitch = interpolation.orientation_raw_pitch;
2261 uint32_t table, table_start;
2264 double red, green, blue;
2267 printf("RENDER_ITEM_STARS\n");
2269 /* use default fov of 64 to calculate z distance */
2270 z = 160.0 / frustum_slope_64;
2272 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2275 for (i = 0; i < 16; i++)
2276 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2279 /* render legacy stars (as with the original game) */
2281 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
2282 * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
2283 * then we half it, so we get to the center via 91
2286 if (render_item->u.stars.above_zenith)
2288 yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2290 table = mercenary_star_table();
2291 table_start = table + m68k_read_memory_16(table);
2292 table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
2293 yaw = yaw / (double)0x800 * 1800.0;
2295 if (render_item->u.stars.above_zenith)
2296 pitch = 0x200 - pitch;
2297 pitch = fmod(pitch + 65536.0, 0x400);
2298 pitch -= render_item->u.stars.v_offset;
2300 pitch = pitch * (double)0x6ccc / 65536.0;
2303 x = m68k_read_memory_16(table);
2306 table = table_start;
2308 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2312 /* special case where we tilt the view when flying on the planet */
2313 if (render_item->u.stars.tilt) {
2314 /* use offset as given by game: 160 is half of the screen width
2315 * we extend the width to the actual FOV, so it fits
2317 tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2319 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2321 if (render_item->u.stars.above_zenith) {
2322 x = (double)(view_width - 1) - x;
2326 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2327 opengl_render_color(red, green, blue, debug_opacity);
2329 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2332 /* render ovr stars, render star table as a sphere */
2336 double inclination = interpolation.planet_inclination, azimuth = interpolation.planet_azimuth;
2338 if (render_item->u.stars.above_zenith)
2341 table = mercenary_star_table();
2342 table += m68k_read_memory_16(table);
2345 x = m68k_read_memory_16(table);
2349 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - 108.796875;
2352 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2353 opengl_render_color(red, green, blue, debug_opacity);
2355 h = (900.0 - x + 160) / 900.0 * M_PI;
2356 v1 = (68.0 - y) / 900.0 * M_PI;
2357 /* wrap star field (is actually 86.2 degrees high) */
2359 v2 = v1 + (86.2 / 180.0 * M_PI);
2361 v2 = v1 - (86.2 / 180.0 * M_PI);
2362 if (v1 < 0.934 && v1 > -0.934) {
2363 /* be sure that v1 will not exceed PI/2 */
2364 v1 = v1 / cos(v1); /* FIXME: there should be a better way to distribute stars equally */
2365 x = -sin(h) * cos(v1);
2367 z = cos(h) * cos(v1);
2368 if (motion_new.planet_rotation)
2369 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2370 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
2371 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2373 if (v2 < 0.934 && v2 > -0.934) {
2374 /* be sure that v2 will not exceed PI/2 */
2375 v2 = v2 / cos(v2) /* FIXME: there should be a better way to distribute stars equally */;
2376 x = -sin(h) * cos(v2);
2378 z = cos(h) * cos(v2);
2379 if (motion_new.planet_rotation)
2380 rotate_coordinate(0.0, inclination, azimuth, &x, &y, &z);
2381 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
2382 opengl_render_point(1000000.0 * x, 1000000.0 * y, 1000000.0 * z, 0.0);
2388 case RENDER_ITEM_INTERSTELLAR_STARS:
2393 double red, green, blue;
2396 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2398 /* use default fov of 64 to calculate z distance */
2399 z = 160.0 / frustum_slope_64;
2402 for (i = 0; i < 16; i++)
2403 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2405 for (i = 0; i < render_item->u.interstars.count; i++) {
2406 gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
2407 opengl_render_color(red, green, blue, debug_opacity);
2409 opengl_render_point(160.0 - (double)render_item->u.interstars.x[i], 68.0 - (double)render_item->u.interstars.y[i], z, 0.0);
2413 case RENDER_ITEM_INTERSTELLAR_SUN:
2415 double red, green, blue;
2418 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2421 gamecolor2gl(&red, &green, &blue, 0x777);
2422 opengl_render_color(red, green, blue, debug_opacity);
2424 opengl_render_point(0.0, 0.0, 1000000.0, 0.0);
2427 case RENDER_ITEM_SIGHTS:
2429 double x[4], y[4], z[4];
2430 double red, green, blue;
2433 printf("RENDER_ITEM_SIGHTS\n");
2435 /* use default fov of 64 to calculate z distance */
2436 z[0] = z[1] = z[2] = z[3] = SIGHT_DIST;
2439 gamecolor2gl(&red, &green, &blue, 0x777);
2440 opengl_render_color(red, green, blue, debug_opacity);
2442 y[0] = y[3] = -1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2443 y[1] = y[2] = 1.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2444 x[0] = x[1] = -16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2445 x[2] = x[3] = -8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2446 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2447 x[0] = x[1] = 8.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2448 x[2] = x[3] = 16.0 / 160.0 * SIGHT_DIST * frustum_slope_64;
2449 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2452 case RENDER_ITEM_EXPLOSION:
2455 double loc_x, loc_y, loc_z, size;
2456 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2460 printf("RENDER_ITEM_EXPLOSION\n");
2462 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2464 for (e = 0; e < render_item->u.explosion.count; e++) {
2465 loc_x = render_item->u.explosion.x[e];
2466 loc_y = render_item->u.explosion.y[e];
2467 loc_z = render_item->u.explosion.z[e];
2468 size = 20; /* round about.... */
2470 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2471 /* create and render cicle */
2472 for (i = 0; i < EXPLOSION_VERTICES; i++) {
2473 x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * EXPLOSION_ELIPSE;
2474 y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
2477 opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
2478 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point */
2483 print_info("Unknown render item type, please fix!\n");
2491 static double interpolate_orientation(double old, double new, double inter)
2493 double turn = new - old;
2500 /* don't interpolate, if our rotation was too fast.
2501 * e.g: taxi drive around corder, load/quit game, ...
2503 if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
2506 new = old + turn * inter;
2516 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
2518 int16_t turn = (new - old) & 0x3ff;
2523 /* don't interpolate, if our rotation was too fast.
2524 * e.g: taxi drive around corder, load/quit game, ...
2526 if (turn > 0x200 / 8 || turn < -0x200 / 8)
2529 /* don't do modulo 0x400, since the user of this data does it */
2530 return (double)old + (double)turn * inter;
2533 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
2537 /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
2538 if (ground_index >= 0)
2539 offset = wrap_int28(old - new);
2541 offset = (int32_t)(old - new);
2543 if (limit > 0 && (offset > limit || offset < -limit))
2546 return offset * (1.0 - inter);
2549 static render_item_t *interpolate_door(double inter)
2551 static render_item_t interpolated;
2552 render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
2553 int nomatch_x_count = 0;
2554 int nomatch_z_count = 0;
2555 int nomatch_x[4], nomatch_z[4];
2558 /* find old and new vertices */
2559 while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2560 old_vertices = old_vertices->next;
2561 while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2562 new_vertices = new_vertices->next;
2564 /* building does not exist in old or new render */
2565 if (!old_vertices || !new_vertices)
2568 /* all verices must match except four */
2569 ii = MAX_INTERIOR_VERTEX >> 2;
2570 for (i = 0; i < ii; i++) {
2571 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2573 if (old_vertices->u.vertices_interior.x[i] != new_vertices->u.vertices_interior.x[i]) {
2574 if (nomatch_x_count == 4)
2576 nomatch_x[nomatch_x_count++] = i;
2579 for (i = 0; i < 4; i++) {
2580 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
2583 for (i = 0; i < ii; i++) {
2584 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2586 if (old_vertices->u.vertices_interior.z[i] != new_vertices->u.vertices_interior.z[i]) {
2587 if (nomatch_z_count == 4)
2589 nomatch_z[nomatch_z_count++] = i;
2593 /* copy, even if not interpolated */
2594 memcpy(&interpolated, new_vertices, sizeof(interpolated));
2596 /* only four x missmatch */
2597 if (nomatch_x_count == 4 || nomatch_x_count == 2) {
2598 for (i = 0; i < nomatch_x_count; i++) {
2599 interpolated.u.vertices_interior.x[nomatch_x[i]] =
2600 (double)old_vertices->u.vertices_interior.x[nomatch_x[i]] * (1.0 - inter) +
2601 (double)new_vertices->u.vertices_interior.x[nomatch_x[i]] * inter;
2605 /* only four z missmatch */
2606 if (nomatch_z_count == 4 || nomatch_z_count == 2) {
2607 for (i = 0; i < nomatch_z_count; i++) {
2608 interpolated.u.vertices_interior.z[nomatch_z[i]] =
2609 (double)old_vertices->u.vertices_interior.z[nomatch_z[i]] * (1.0 - inter) +
2610 (double)new_vertices->u.vertices_interior.z[nomatch_z[i]] * inter;
2614 return &interpolated;
2617 /* make a list of objects that moved and store their displacement */
2618 static void interpolate_objects(double inter)
2620 render_item_t *old_info, *new_info;
2623 /* hunt for objects that exist in both (old and new) lists and moved */
2625 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2627 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
2630 if (!new_info->u.info.moving)
2632 /* interiors don't move */
2633 if (new_info->u.info.id < 0)
2635 /* check matching object with same ID */
2636 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2638 if (old_info->type != RENDER_ITEM_OBJECT_INFO)
2641 if (!old_info->u.info.moving)
2644 if (old_info->u.info.id == new_info->u.info.id)
2647 /* no matching object found */
2651 if (old_info->u.info.east == new_info->u.info.east
2652 && old_info->u.info.height == new_info->u.info.height
2653 && old_info->u.info.north == new_info->u.info.north)
2655 /* interpolate and store */
2656 interpolation.object_id[count] = new_info->u.info.id;
2657 interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
2658 interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
2659 interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
2660 if (count++ == MAX_MOVING_OBJECTS)
2663 interpolation.object_count = count;
2666 /* make a vertex list of interpolated planets */
2667 static render_item_t *interpolate_planets(double inter)
2669 static render_item_t interpolated;
2670 render_item_t *old_info, *new_info;
2671 render_item_t *old_vertices = NULL, *new_vertices = NULL;
2674 /* get vertices for planets/comet */
2675 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2676 if (old_info->type == RENDER_ITEM_VERTICES_0)
2677 old_vertices = old_info;
2678 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2679 if (old_info->type == RENDER_ITEM_COMET_POLYGON)
2682 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2683 if (new_info->type == RENDER_ITEM_VERTICES_0)
2684 new_vertices = new_info;
2685 /* check until comet's polygons are renderd. at this time the coordinates are all ready, so we can interpolate */
2686 if (new_info->type == RENDER_ITEM_COMET_POLYGON)
2690 /* check for existing planet's vertices and if planets are rendered in both lists (old and new) */
2691 if (old_info == NULL || new_info == NULL || old_vertices == NULL || new_vertices == NULL)
2694 /* interpolate vertices */
2695 for (i = 0; i < (MAX_VERTEX >> 2); i++) {
2696 interpolated.u.vertices.x[i] = old_vertices->u.vertices.x[i] * (1.0 - inter) + new_vertices->u.vertices.x[i] * inter;
2697 interpolated.u.vertices.y[i] = old_vertices->u.vertices.y[i] * (1.0 - inter) + new_vertices->u.vertices.y[i] * inter;
2698 interpolated.u.vertices.z[i] = old_vertices->u.vertices.z[i] * (1.0 - inter) + new_vertices->u.vertices.z[i] * inter;
2701 return &interpolated;
2704 /* always renders NEW! items
2705 * use inter == 1.0 to render motion to vertices of NEW items
2706 * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
2707 * return 0, if the scene was rendered, returns < 0, if there is no scene
2709 int render_all_items(double inter, int vr)
2711 render_item_object_info = NULL;
2712 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2713 render_item_vertices_interior = NULL;
2714 render_item_vertices_planets = NULL;
2716 /* no interpolation when leaving or entering planet to/from space */
2717 if ((last_ground_index < 0 && ground_index >= 0)
2718 || (last_ground_index >= 0 && ground_index < 0)) {
2722 /* reset interpolation */
2723 memset(&interpolation, 0, sizeof(interpolation));
2724 interpolation.orientation_roll = motion_new.orientation_roll;
2725 interpolation.orientation_pitch = motion_new.orientation_pitch;
2726 interpolation.orientation_yaw = motion_new.orientation_yaw;
2727 interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
2728 interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
2729 interpolation.planet_inclination = motion_new.planet_inclination;
2730 interpolation.planet_azimuth = motion_new.planet_azimuth;
2731 //printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
2733 /* do interpolation */
2734 if (inter != 1.0 && render_list_old) {
2735 /* interpolate orientation */
2736 interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
2737 interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
2738 interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
2739 interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
2740 interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
2741 interpolation.planet_inclination = interpolate_orientation(motion_old.planet_inclination, motion_new.planet_inclination, inter);
2742 interpolation.planet_azimuth = interpolate_orientation(motion_old.planet_azimuth, motion_new.planet_azimuth, inter);
2744 /* interpolate position */
2745 interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
2746 interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
2747 interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
2748 /* prevent glitch when using elevators: a sudden vertical move is ignored
2749 * this is not the best solution, because fast vertical flying (from 0) will also be detected */
2750 if (old_height_offset == 0
2751 && (new_height_offset >= 150 || new_height_offset <= -150)) {
2752 interpolation.offset_east = 0.0;
2753 interpolation.offset_height = 0.0;
2754 interpolation.offset_north = 0.0;
2757 /* interpolate doors of building (if any) */
2758 interpolation.interior = interpolate_door(inter);
2760 /* interpolate objects */
2761 interpolate_objects(inter);
2763 /* interpolate planets */
2764 interpolation.planets = interpolate_planets(inter);
2767 /* return failure, if nothing can be rendered */
2768 if (!render_list_new)
2771 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2772 render_one_item(render_item, vr);
2778 void render_capture_reset(void)
2780 /* flush old list, if exists */
2782 /* flush new list, if exists */
2783 render_list_old = render_list_new;
2785 /* reset list pointers */
2786 render_list_old = NULL;
2787 render_list_new = NULL;
2788 render_list_end = &render_list_new;
2792 int render_capture_is_interstellar(void)
2794 if (!render_list_new)
2796 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2797 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)