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
42 #include "../libsdl/print.h"
43 #include "../libcpu/m68k.h"
44 #include "../libcpu/m68kcpu.h"
45 #include "../libcpu/execute.h"
46 #include "../libsdl/opengl.h"
47 #include "mercenary.h"
50 //#define DEBUG_VERTEX
53 #define MAX_POLYGON 16 /* number of polygon complexity (vertices) */
54 #define MAX_VERTEX 0x100 /* this is the value range, these are 64 vertices */
55 #define MAX_INTERIOR_VERTEX 0x400 /* do we need that much? */
56 #define MAX_INTERSTARS 80 /* always 80 stars */
57 #define MAX_MOVING_OBJECTS 16 /* maximum number of moving objects (used for interpolation) */
58 #define MAX_EXPLOSION 256 /* how many explosion particles can be stored in one object */
59 #define PLANET_VERTICES 128
60 #define PLANET_ELIPSE 1.17
61 #define EXPLOSION_VERTICES 16
62 #define EXPLOSION_ELIPSE 1.17
65 * render item definition and structures
69 enum render_item_type {
70 RENDER_ITEM_OBJECT_INFO,
71 RENDER_ITEM_VERTICES_0,
72 RENDER_ITEM_VERTICES_1,
73 RENDER_ITEM_VERTICES_2,
74 RENDER_ITEM_VERTICES_INTERIOR,
77 RENDER_ITEM_OBJECT_POLYGON,
78 RENDER_ITEM_OBJECT_LINE,
79 RENDER_ITEM_BEACON_POINT,
80 RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
81 RENDER_ITEM_BUILDING_EXTERIOR_LINE,
82 RENDER_ITEM_BUILDING_INTERIOR_1TO4,
83 RENDER_ITEM_BUILDING_INTERIOR_5TO6,
84 RENDER_ITEM_BUILDING_INTERIOR_WALL,
85 RENDER_ITEM_COMET_POLYGON,
86 RENDER_ITEM_ROAD_LINE,
87 RENDER_ITEM_ROAD_POLYGON,
88 RENDER_ITEM_TAG_LINE_OBJECT,
89 RENDER_ITEM_TAG_LINE_OTHER,
90 RENDER_ITEM_TAG_POLYGON_OBJECT,
91 RENDER_ITEM_TAG_POLYGON_OTHER,
94 RENDER_ITEM_INTERSTELLAR_STARS,
95 RENDER_ITEM_INTERSTELLAR_SUN,
96 RENDER_ITEM_ISLAND_POLYGON,
98 RENDER_ITEM_EXPLOSION,
101 struct render_item_info {
104 int32_t east, height, north;
107 struct render_item_vertices {
108 int32_t x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
111 struct render_item_vertices_interior {
112 uint8_t set[MAX_INTERIOR_VERTEX >> 2];
113 double x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
116 struct render_item_sky {
117 double red, green, blue;
120 struct render_item_ground {
121 double red, green, blue;
124 struct render_item_polygon {
125 double red, green, blue;
127 int vertex[MAX_POLYGON];
130 struct render_item_interior14 {
131 double red, green, blue;
136 struct render_item_interior56 {
137 double red, green, blue;
144 struct render_item_line {
145 double red, green, blue;
149 struct render_item_point {
150 double red, green, blue;
154 struct render_item_planet {
155 double front_red, front_green, front_blue;
156 double back_red, back_green, back_blue;
161 struct render_item_stars {
168 struct render_item_interstars {
169 uint8_t color[MAX_INTERSTARS];
170 int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
174 struct render_item_explosion {
175 double red, green, blue;
176 int32_t x[MAX_EXPLOSION], y[MAX_EXPLOSION], z[MAX_EXPLOSION];
180 typedef struct render_item {
181 struct render_item *next;
182 enum render_item_type type;
184 struct render_item_info info;
185 struct render_item_vertices vertices;
186 struct render_item_vertices_interior vertices_interior;
187 struct render_item_sky sky;
188 struct render_item_ground ground;
189 struct render_item_polygon polygon;
190 struct render_item_line line;
191 struct render_item_point point;
192 struct render_item_interior14 interior14;
193 struct render_item_interior56 interior56;
194 struct render_item_planet planet;
195 struct render_item_stars stars;
196 struct render_item_interstars interstars;
197 struct render_item_explosion explosion;
201 /* information about motion in each game rendering */
202 typedef struct motion {
203 int32_t position_east, position_height, position_north;
204 double orientation_roll, orientation_pitch, orientation_yaw;
205 uint16_t orientation_raw_yaw;
206 int16_t orientation_raw_pitch;
208 double planet_inclination, planet_azimuth;
211 /* information about interpolation between two game renedrings */
212 typedef struct interpolation {
213 double offset_east, offset_height, offset_north;
214 double orientation_roll, orientation_pitch, orientation_yaw;
215 double orientation_raw_yaw, orientation_raw_pitch;
216 int object_id[MAX_MOVING_OBJECTS];
217 double object_offset_east[MAX_MOVING_OBJECTS], object_offset_height[MAX_MOVING_OBJECTS], object_offset_north[MAX_MOVING_OBJECTS];
219 render_item_t *interior;
222 #define GET_ORIENTATION \
223 double roll = interpolation.orientation_roll; \
224 double pitch = interpolation.orientation_pitch; \
225 double yaw = interpolation.orientation_yaw
227 #define GET_ORIENTATION_FIX \
228 roll = motion_new.orientation_roll; \
229 pitch = motion_new.orientation_pitch; \
230 yaw = motion_new.orientation_yaw
232 /* rendering options */
233 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
235 static double debug_opacity;
236 static double frustum_slope_64, frustum_slope_fov;
238 /* states while collecting render items */
239 static motion_t motion_old, motion_new;
240 static int32_t old_height_offset = 0, new_height_offset = 0;
241 static interpolation_t interpolation;
242 static int ground_index, last_ground_index = -1;
243 static int interior_level12 = 0;
244 static int interior_level34 = 0;
245 static int tag_is_object;
246 /* current render item list */
247 static render_item_t *render_list_new = NULL, **render_list_end = &render_list_new;
248 /* previous render item list */
249 static render_item_t *render_list_old = NULL;
250 /* current item to be processed */
251 static render_item_t *render_item;
252 /* current object info */
253 static render_item_t *render_item_object_info;
254 /* current vertices */
255 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
256 static render_item_t *render_item_vertices_interior;
262 static void render_item_add(enum render_item_type type)
264 render_item = calloc(1, sizeof(render_item_t));
266 print_error("No memory, must abort!\n");
269 render_item->type = type;
270 *render_list_end = render_item;
271 render_list_end = &render_item->next;
274 static void flush_old_items(void)
276 /* flush old render list */
277 while (render_list_old) {
278 render_item = render_list_old;
279 render_list_old = render_list_old->next;
284 /* rendering starts, initialize variables */
285 void render_capture_start(double _fov, int _extend_roads, int debug)
287 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
288 printf("start rendering a new frame...\n");
293 /* move new render list to old render list */
294 render_list_old = render_list_new;
295 /* setup new render list */
296 render_list_new = NULL;
297 render_list_end = &render_list_new;
299 /* move new motion to old motion */
300 memcpy(&motion_old, &motion_new, sizeof(motion_old));
302 /* set rendering options */
304 extend_roads = _extend_roads;
305 /* set some transpareny, if debugging is enabled */
306 debug_opacity = (debug) ? 0.5 : 1.0;
308 /* calculate slope of 64 degree frustum and current FOV's frustum */
309 frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
310 frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
313 mercenary_get_location(&motion_new.position_east, &motion_new.position_height, &motion_new.position_north);
314 /* in case of player on the ground, there is no roll, so it will be reset to 0 when screen is cleared */
315 mercenary_get_orientation(&motion_new.orientation_roll, &motion_new.orientation_pitch, &motion_new.orientation_yaw);
316 mercenary_get_orientation_raw(&motion_new.orientation_raw_pitch, &motion_new.orientation_raw_yaw);
317 motion_new.planet_rotation = 0;
318 mercenary_get_orientation_planet(&motion_new.planet_inclination, &motion_new.planet_azimuth);
320 render_item_object_info = NULL;
321 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
322 render_item_vertices_interior = NULL;
324 /* detect elevator movement */
325 old_height_offset = new_height_offset;
327 new_height_offset = motion_new.position_height - motion_old.position_height;
329 /* detect switching between space (-1) and over ground (>=0) */
330 last_ground_index = ground_index;
336 void render_capture_stop(void)
338 /* no new list (due to STOP_AT_WAIT_INPUT), use old list, if any */
339 if (!render_list_new) {
340 render_list_new = render_list_old;
341 render_list_end = &render_list_new;
342 render_list_old = NULL;
347 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
352 /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
354 palette = mercenary_palette_render();
355 color = m68k_read_memory_16(palette + index);
357 printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
359 if (color >= 0x8000) {
361 fprintf(stderr, "Use of color index from current palette, but index is not defined as being set!\n");
364 *red = (double)((color >> 8) & 0xf) / 15.0;
365 *green = (double)((color >> 4) & 0xf) / 15.0;
366 *blue = (double)(color & 0xf) / 15.0;
369 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
376 printf("color is given as 0x%04x\n", color);
379 /* color conversion: see for example M3: 0x4f830 */
380 if (color < 0x8000) {
381 /* use given color but shift it left by 1 */
384 printf("using given color, color is now 0x%04x\n", color);
386 } else if ((color & 0xff) < 0x80) {
387 gamecolor2gl_index(red, green, blue, color & 0xf);
390 /* use given index from pre-defined palette */
391 index = color & 0x7e;
392 palette = mercenary_palette_predefined();
393 color = m68k_read_memory_16(palette + index);
395 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
397 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
398 if (nesting++ == 8) {
399 print_info("Color lookup from pre-defined palette is nesting too much, please fix!\n");
404 *red = (double)((color >> 8) & 0xf) / 15.0;
405 *green = (double)((color >> 4) & 0xf) / 15.0;
406 *blue = (double)(color & 0xf) / 15.0;
409 static int32_t wrap_int28(int32_t value)
416 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
419 print_info("Vertex %d is not a multiple of four!\n", vertex);
422 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
423 if (vertex < 0x100) {
424 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
425 render_item_add(RENDER_ITEM_VERTICES_0);
426 /* copy vertices that have been captured already */
427 if (render_item_vertices_0)
428 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
429 render_item_vertices_0 = render_item;
432 if (vertex < 0x200) {
433 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
434 render_item_add(RENDER_ITEM_VERTICES_1);
435 /* copy vertices that have been captured already */
436 if (render_item_vertices_1)
437 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
438 render_item_vertices_1 = render_item;
442 if (vertex < 0x300) {
443 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
444 render_item_add(RENDER_ITEM_VERTICES_2);
445 /* copy vertices that have been captured already */
446 if (render_item_vertices_2)
447 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
448 render_item_vertices_2 = render_item;
452 print_info("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
457 printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, x, y, z);
459 /* use absolute position */
460 x += motion_new.position_east;
461 y += motion_new.position_height;
462 z += motion_new.position_north;
463 render_item->u.vertices.x[vertex] = x;
464 render_item->u.vertices.y[vertex] = y;
465 render_item->u.vertices.z[vertex] = z;
468 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)
471 print_info("Vertex is not a multiple of four!\n");
474 if (vertex >= MAX_INTERIOR_VERTEX) {
475 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
478 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
479 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
482 printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f;%.0f;%.0f;%.0F, Z=%.0F\n", what, vertex, x, y1, y2, y3, y4, z);
484 /* use absolute position */
485 x += motion_new.position_east;
486 y1 += motion_new.position_height;
487 y2 += motion_new.position_height;
488 y3 += motion_new.position_height;
489 y4 += motion_new.position_height;
490 z += motion_new.position_north;
491 render_item->u.vertices_interior.x[vertex] = (double)x;
492 render_item->u.vertices_interior.y[0] = (double)y1;
493 render_item->u.vertices_interior.y[1] = (double)y2;
494 render_item->u.vertices_interior.y[2] = (double)y3;
495 render_item->u.vertices_interior.y[3] = (double)y4;
496 render_item->u.vertices_interior.z[vertex] = (double)z;
497 render_item->u.vertices_interior.set[vertex] = 1;
500 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
502 double out_x, out_y, out_z;
504 /* rotate yaw (German: Gier, turn view to the right) */
505 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
506 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
509 /* rotate pitch (German: Nick, turn head down) */
510 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
511 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
516 /* rotate roll (tilt head to the right) */
517 out_x = (*x) * cos(roll) - (*y) * sin(roll);
518 out_y = (*x) * sin(roll) + (*y) * cos(roll);
523 /* clear screen color (sky / universe) */
524 static void clear_screen(int index)
527 printf("clear screen:\n");
530 /* allocate render item */
531 render_item_add(RENDER_ITEM_SKY);
534 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
536 /* store for later use after planets have been rendered */
537 ground_index = index;
541 static void draw_ground(void)
543 /* no ground in space :) */
544 if (ground_index < 0)
548 printf("add ground plane:\n");
551 /* allocate render item */
552 render_item_add(RENDER_ITEM_GROUND);
555 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
559 static void info_object(int moving)
562 printf("add object's info:\n");
565 /* allocate render item */
566 render_item_add(RENDER_ITEM_OBJECT_INFO);
569 render_item->u.info.moving = moving;
571 mercenary_get_object_info(&render_item->u.info.id, &render_item->u.info.east, &render_item->u.info.height, &render_item->u.info.north);
574 /* coordinates ready for an object */
575 static void coord_object(void)
579 x = (int16_t)REG_D[3];
580 x += (int32_t)REG_A[1];
581 y = (int16_t)REG_D[4];
582 y += (int32_t)REG_A[2];
583 z = (int16_t)REG_D[5];
584 z += (int32_t)REG_A[3];
585 store_coord("object", REG_A[0], x, y, z);
588 /* polygon of object */
589 static void poly_object(int mercenary)
591 uint32_t vertex_address = REG_A[0];
596 printf("add object's polygon:\n");
599 /* allocate render item */
600 render_item_add(RENDER_ITEM_OBJECT_POLYGON);
604 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
607 color = m68k_read_memory_8(vertex_address++) << 8;
608 color |= m68k_read_memory_8(vertex_address++);
609 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
612 /* the vertex list is zero-terminated */
613 for (i = 0; i < MAX_POLYGON; i++) {
614 vertex = m68k_read_memory_8(vertex_address++);
615 if (vertex == 0 && i)
617 render_item->u.polygon.vertex[i] = vertex;
619 render_item->u.polygon.vertices = i;
623 static void line_object(void)
625 uint32_t vertex_address = REG_A[0];
629 printf("add object's line:\n");
632 /* allocate render item */
633 render_item_add(RENDER_ITEM_OBJECT_LINE);
636 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
639 vertex = m68k_read_memory_8(vertex_address++);
640 render_item->u.line.vertex[0] = vertex;
641 vertex = m68k_read_memory_8(vertex_address++);
642 render_item->u.line.vertex[1] = vertex;
645 /* coordinates ready for a beacon */
646 static void coord_beacon(void)
650 /* only 28 bits seem to be a correct signed int value */
651 x = (int32_t)(REG_D[3] << 4) / 16;
652 y = (int32_t)(REG_D[4] << 4) / 16;
653 z = (int32_t)(REG_D[5] << 4) / 16;
654 store_coord("beacon", 0, x, y, z);
657 /* point of beacon */
658 static void point_beacon(void)
661 printf("add beacon's point:\n");
664 /* allocate render item */
665 render_item_add(RENDER_ITEM_BEACON_POINT);
668 gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
671 render_item->u.point.vertex = 0;
674 /* coordinates ready for a building (exterior) */
675 static void coord_building_exterior(void)
679 x = (int32_t)REG_D[3];
680 y = (int32_t)REG_D[4];
681 z = (int32_t)REG_D[5];
682 store_coord("building exterior", REG_A[0], x, y, z);
685 /* polygon of building (exterior) */
686 static void poly_building_exterior(void)
689 uint32_t vertex_address = REG_A[0];
694 printf("add building's polygon:\n");
697 /* allocate render item */
698 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
701 color = m68k_read_memory_8(vertex_address++) << 8;
702 color |= m68k_read_memory_8(vertex_address++);
703 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
705 /* the vertex list is zero-terminated */
706 for (i = 0; i < MAX_POLYGON; i++) {
707 vertex = m68k_read_memory_8(vertex_address++);
708 if (vertex == 0 && i)
710 render_item->u.polygon.vertex[i] = vertex | 0x100;
712 render_item->u.polygon.vertices = i;
715 /* line of building (exterior) */
716 static void line_building_exterior(void)
718 uint32_t vertex_address = REG_A[0];
722 printf("add building's line:\n");
725 /* allocate render item */
726 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
729 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
732 vertex = m68k_read_memory_8(vertex_address++);
733 render_item->u.line.vertex[0] = vertex | 0x100;
734 vertex = m68k_read_memory_8(vertex_address++);
735 render_item->u.line.vertex[1] = vertex | 0x100;
738 /* coordinates ready for a building (interior) */
739 static void coord_building_interior(void)
742 int32_t height1, height2, height3, height4;
744 mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
745 store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
748 /* polygon of building (interior) */
749 static void poly_building_interior1to4(int level)
756 printf("add roof/floor's polygon at level %d:\n", level);
759 /* allocate render item */
760 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
763 color = m68k_read_memory_8(REG_A[0]) << 8;
764 color |= m68k_read_memory_8(REG_A[0] + 1);
765 gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
767 /* four vertices, one level */
768 for (i = 0; i < 4; i++) {
769 vertex = REG_A[(2 + i)];
770 render_item->u.interior14.vertex[i] = vertex;
772 render_item->u.interior14.level = level;
775 /* polygon of building (interior) */
776 static void poly_building_interior5to6(int level12, int level34)
781 printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
784 /* allocate render item */
785 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
788 color = m68k_read_memory_8(REG_A[0]) << 8;
789 color |= m68k_read_memory_8(REG_A[0] + 1);
790 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
792 /* two vertices, two levels */
793 render_item->u.interior56.vertex14 = REG_A[2];
794 render_item->u.interior56.vertex23 = REG_A[3];
795 render_item->u.interior56.level12 = level12;
796 render_item->u.interior56.level34 = level34;
799 /* wall part of a building */
800 static void wall_building(void)
803 printf("add wall:\n");
806 /* allocate render item */
807 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
810 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
812 /* two vertices, two levels */
813 render_item->u.interior56.vertex14 = REG_A[1];
814 render_item->u.interior56.vertex23 = REG_A[2];
815 /* get top level according to bit 12 in D3 */
816 render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
817 render_item->u.interior56.level34 = 1;
820 /* coordinates ready for comet tail */
821 static void coord_comet(void)
825 x = (int32_t)REG_D[3];
826 y = (int32_t)REG_D[4];
827 z = (int32_t)REG_D[5];
828 store_coord("comet tail", REG_A[0], x, y, z);
831 /* polygon of comet tail */
832 static void poly_comet(void)
835 uint32_t vertex_address = REG_A[0];
840 printf("add comet's polygon:\n");
843 /* allocate render item */
844 render_item_add(RENDER_ITEM_COMET_POLYGON);
847 color = m68k_read_memory_8(vertex_address++) << 8;
848 color |= m68k_read_memory_8(vertex_address++);
849 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
851 /* the vertex list is zero-terminated */
852 for (i = 0; i < MAX_POLYGON; i++) {
853 vertex = m68k_read_memory_8(vertex_address++);
854 if (vertex == 0 && i)
856 render_item->u.polygon.vertex[i] = vertex;
858 render_item->u.polygon.vertices = i;
861 /* coordinates ready for lines of a road / ground surface */
862 static void coord_line_road(void)
867 y = -motion_new.position_height;
869 store_coord("road", REG_A[0], x, y, z);
873 static void line_road(void)
878 printf("add road's line:\n");
881 /* allocate render item */
882 render_item_add(RENDER_ITEM_ROAD_LINE);
885 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
889 render_item->u.line.vertex[0] = vertex;
891 render_item->u.line.vertex[1] = vertex;
894 /* coordinates ready for polygons of a road / ground surface */
895 static void coord_poly_road(void)
899 x = m68k_read_memory_32(320 + REG_A[0]);
901 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
902 y = -motion_new.position_height;
903 z = m68k_read_memory_32(576 + REG_A[0]);
905 store_coord("road/place", REG_A[0], x, y, z);
908 /* polygon of road */
909 static void poly_road()
912 uint32_t vertex_address = REG_A[0];
917 printf("add road/place's polygon:\n");
920 /* allocate render item */
921 render_item_add(RENDER_ITEM_ROAD_POLYGON);
924 color = m68k_read_memory_8(vertex_address++) << 8;
925 color |= m68k_read_memory_8(vertex_address++);
926 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
928 /* the vertex list is zero-terminated */
929 for (i = 0; i < MAX_POLYGON; i++) {
930 vertex = m68k_read_memory_8(vertex_address++);
931 if (vertex == 0 && i)
933 render_item->u.polygon.vertex[i] = vertex;
935 render_item->u.polygon.vertices = i;
938 /* coordinates ready for tags */
939 static void coord_tags(void)
943 x = (int16_t)REG_D[3];
944 x += (int32_t)REG_A[1];
945 y = (int16_t)REG_D[4];
946 y += (int32_t)REG_A[2];
947 z = (int16_t)REG_D[5];
948 z += (int32_t)REG_A[3];
949 store_coord("tags", REG_A[0], x, y, z);
952 /* coordinates ready for large tags */
953 static void coord_tags2(void)
957 x = (int16_t)REG_D[3];
958 x += 2 * (int32_t)REG_A[1];
959 y = (int16_t)REG_D[4];
960 y += 2 * (int32_t)REG_A[2];
961 z = (int16_t)REG_D[5];
962 z += 2 * (int32_t)REG_A[3];
963 store_coord("large tags", REG_A[0], x, y, z);
967 static void line_tags(int last_color)
969 uint32_t vertex_address = REG_A[0];
973 printf("add tag's line:\n");
976 /* allocate render item */
977 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_LINE_OBJECT : RENDER_ITEM_TAG_LINE_OTHER);
981 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
983 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
986 vertex = m68k_read_memory_8(vertex_address++);
987 render_item->u.line.vertex[0] = vertex | 0x200;
988 vertex = m68k_read_memory_8(vertex_address++);
989 render_item->u.line.vertex[1] = vertex | 0x200;
992 /* polygon of tags */
993 static void poly_tags(int last_color)
995 uint32_t vertex_address = REG_A[0];
1000 printf("add tag's polygon:\n");
1003 /* allocate render item */
1004 render_item_add((tag_is_object) ? RENDER_ITEM_TAG_POLYGON_OBJECT : RENDER_ITEM_TAG_POLYGON_OTHER);
1008 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
1010 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
1011 /* the vertex list is zero-terminated */
1012 for (i = 0; i < MAX_POLYGON; i++) {
1013 vertex = m68k_read_memory_8(vertex_address++);
1014 if (vertex == 0 && i)
1016 render_item->u.polygon.vertex[i] = vertex | 0x200;
1018 render_item->u.polygon.vertices = i;
1021 /* coordinates ready for planet */
1022 static void coord_planet(void)
1026 x = (int32_t)REG_D[3];
1027 y = (int32_t)REG_D[4];
1028 z = (int32_t)REG_D[5];
1029 store_coord("planet", REG_A[0], x, y, z);
1033 static void draw_planet(int comet)
1036 uint32_t scale_index;
1037 double scale1, scale2;
1041 /* fixing (not noticable) bug in game: don't render comet twice */
1042 if (!comet && vertex == 116)
1046 printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
1049 /* allocate render item */
1050 render_item_add(RENDER_ITEM_PLANET);
1054 /* make comet black on front side and bright on back */
1055 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
1056 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
1059 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
1060 /* use background color for dark side */
1061 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
1065 render_item->u.planet.vertex = vertex;
1067 /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
1068 * the long word 21584(A0) contains two scales
1069 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
1070 * the upper word defines how much this scale is shifted to the left.
1072 scale_index = mercenary_planet_scale_index();
1073 scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
1074 scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
1075 render_item->u.planet.size = scale1 * scale2 / 128.0;
1079 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
1082 printf("add stars\n");
1085 /* allocate render item */
1086 render_item_add(RENDER_ITEM_STARS);
1088 /* vertical offset */
1089 render_item->u.stars.v_offset = v_offset;
1091 /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
1092 render_item->u.stars.tilt = tilt;
1094 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
1096 /* stars above zenith */
1097 render_item->u.stars.above_zenith = above_zenith;
1100 /* stars of interstellar flight */
1101 static void draw_stars_interstellar(void)
1107 printf("add interstellar stars\n");
1110 /* allocate render item */
1111 render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
1114 count = REG_D[5] + 1;
1115 if (count > MAX_INTERSTARS) {
1116 print_info("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
1119 for (i = 0; i < count; i++) {
1122 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
1124 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
1126 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
1129 render_item->u.interstars.count = count;
1132 /* sun of interstellar flight (center dot) */
1133 static void draw_sun_interstellar(void)
1136 printf("add interstellar sun\n");
1139 /* allocate render item */
1140 render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
1143 /* coordinates ready for polygons of islands */
1144 static void coord_islands(void)
1148 x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1149 x += (int32_t)REG_A[1];
1150 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1151 y = -motion_new.position_height;
1152 z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1153 z += (int32_t)REG_A[3];
1154 store_coord("island", REG_A[0], x, y, z);
1157 /* polygon of island */
1158 static void poly_island()
1161 uint32_t vertex_address = REG_A[0];
1166 printf("add island:\n");
1169 /* allocate render item */
1170 render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1173 color = m68k_read_memory_8(vertex_address++) << 8;
1174 color |= m68k_read_memory_8(vertex_address++);
1175 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1177 /* the vertex list is zero-terminated */
1179 while (i < MAX_POLYGON) {
1180 vertex = m68k_read_memory_8(vertex_address++);
1181 if (vertex == 0 && i)
1183 /* skip mysterious points when rendering island */
1186 render_item->u.polygon.vertex[i] = vertex;
1189 render_item->u.polygon.vertices = i;
1193 static void draw_sights(void)
1196 printf("add sights:\n");
1199 /* allocate render item */
1200 render_item_add(RENDER_ITEM_SIGHTS);
1203 static void draw_explosion(void)
1208 printf("add explosion:\n");
1211 /* allocate render item */
1212 if (!render_item || render_item->type != RENDER_ITEM_EXPLOSION) {
1213 render_item_add(RENDER_ITEM_EXPLOSION);
1214 /* get color from render palette */
1215 color = (m68k_read_memory_16(mercenary_palette_view() + 13*2) & 0xfff) >> 1;
1216 gamecolor2gl(&render_item->u.explosion.red, &render_item->u.explosion.green, &render_item->u.explosion.blue, color);
1217 render_item->u.explosion.count = 0;
1219 if (render_item->u.explosion.count == MAX_EXPLOSION)
1221 render_item->u.explosion.x[render_item->u.explosion.count] = REG_D[3];
1222 render_item->u.explosion.y[render_item->u.explosion.count] = REG_D[4];
1223 render_item->u.explosion.z[render_item->u.explosion.count] = REG_D[5];
1224 render_item->u.explosion.count++;
1227 /* stop event from CPU received */
1228 void render_capture_event(int event)
1231 case STOP_AT_CLEAR_SCREEN1:
1232 clear_screen(16); /* color 16 is raster split */
1233 /* in case of screen clearing on the ground, there is no roll */
1234 motion_new.orientation_roll = 0;
1236 case STOP_AT_CLEAR_SCREEN2:
1239 case STOP_AT_CLEAR_SCREEN3:
1240 clear_screen(-1); /* no ground (in universe) */
1242 case STOP_AT_DRAW_GROUND:
1245 case STOP_AT_INFO_OBJECT_MOVING:
1248 case STOP_AT_INFO_OBJECT_FIX:
1251 case STOP_AT_TAG_IS_OBJECT_1:
1254 case STOP_AT_TAG_IS_OBJECT_0:
1257 case STOP_AT_COORD_OBJECT:
1260 case STOP_AT_POLY_OBJECT_M3:
1263 case STOP_AT_POLY_OBJECT_M2:
1266 case STOP_AT_LINE_OBJECT:
1269 case STOP_AT_COORD_BEACON:
1272 case STOP_AT_POINT_BEACON:
1275 case STOP_AT_COORD_BUILDING_EXTERIOR:
1276 coord_building_exterior();
1278 case STOP_AT_POLY_BUILDING_EXTERIOR:
1279 poly_building_exterior();
1281 case STOP_AT_LINE_BUILDING_EXTERIOR:
1282 line_building_exterior();
1284 case STOP_AT_COORD_BUILDING_INTERIOR:
1285 coord_building_interior();
1287 case STOP_AT_POLY_BUILDING_INTERIOR1:
1289 interior_level12 = 1;
1290 interior_level34 = 1;
1292 case STOP_AT_POLY_BUILDING_INTERIOR2:
1294 interior_level12 = 2;
1295 interior_level34 = 2;
1297 case STOP_AT_POLY_BUILDING_INTERIOR3:
1298 /* door/window top */
1299 interior_level12 = 3;
1300 interior_level34 = 3;
1302 case STOP_AT_POLY_BUILDING_INTERIOR4:
1304 interior_level12 = 4;
1305 interior_level34 = 4;
1307 case STOP_AT_POLY_BUILDING_INTERIOR5:
1308 /* door/window top */
1309 interior_level12 = 2;
1310 interior_level34 = 3;
1312 case STOP_AT_POLY_BUILDING_INTERIOR6:
1314 interior_level12 = 1;
1315 interior_level34 = 4;
1317 case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1318 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1319 if (interior_level12 == 0) {
1320 print_info("Interior level is not set, please fix!\n");
1323 poly_building_interior1to4(interior_level12);
1324 interior_level12 = 0;
1326 case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1327 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1328 if (interior_level12 == 0) {
1329 print_info("Interior level is not set, please fix!\n");
1332 poly_building_interior5to6(interior_level12, interior_level34);
1333 interior_level12 = 0;
1335 case STOP_AT_WALL_BUILDING:
1338 case STOP_AT_COORD_COMET:
1341 case STOP_AT_MATRIX_COMET:
1342 case STOP_AT_MATRIX_PLANET:
1343 /* track the rotation matrix
1344 * if we have 0x42c44 matrix, we must add extra rotation to planet.
1345 * the rotation will change the view from the planet's surface */
1346 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1347 motion_new.planet_rotation = 1;
1349 motion_new.planet_rotation = 0;
1351 case STOP_AT_POLY_COMET:
1354 case STOP_AT_COORD_LINE_ROADS:
1357 case STOP_AT_LINE_ROADS:
1360 case STOP_AT_COORD_POLY_ROADS:
1363 case STOP_AT_LINE_ROADS_CENTER:
1364 /* we don't need to render center lines of roads, because there are polygons already
1365 * it does not make sense, since OpenGL has much higher resolution.
1368 case STOP_AT_POLY_ROADS:
1371 case STOP_AT_COORD_TAGS:
1374 case STOP_AT_COORD_TAGS2:
1377 case STOP_AT_LINE_TAGS1:
1380 case STOP_AT_LINE_TAGS2:
1383 case STOP_AT_POLY_TAGS1:
1386 case STOP_AT_POLY_TAGS2:
1389 case STOP_AT_COORD_PLANET:
1392 case STOP_AT_DRAW_PLANET:
1395 case STOP_AT_DRAW_COMET:
1398 case STOP_AT_DRAW_STARS_SPACE:
1399 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1400 draw_stars(0x1c0, 0, 0);
1402 case STOP_AT_DRAW_STARS_GROUND:
1403 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1404 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1406 case STOP_AT_DRAW_STARS_FLYING:
1407 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1408 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1410 case STOP_AT_DRAW_STARS_FLYING2:
1411 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1412 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1414 case STOP_AT_DRAW_STARS_INTERSTELLAR:
1415 draw_stars_interstellar();
1417 case STOP_AT_DRAW_SUN_INTERSTELLAR:
1418 draw_sun_interstellar();
1420 case STOP_AT_COORD_ISLANDS:
1423 case STOP_AT_POLY_ISLANDS:
1426 case STOP_AT_LINE_ISLANDS:
1427 /* this is not used, as i had noticed so far */
1428 puts("line island");
1430 case STOP_AT_DRAW_SIGHTS:
1433 case STOP_AT_POLY_UKN2:
1436 case STOP_AT_EXPLOSION:
1446 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z, int fix)
1448 render_item_t *ri = NULL;
1451 print_info("Vertex %d is not a multiple of four!\n", vertex);
1454 if (vertex < 0x100) {
1455 if (!render_item_vertices_0) {
1456 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1459 ri = render_item_vertices_0;
1461 if (vertex < 0x200) {
1462 if (!render_item_vertices_1) {
1463 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1466 ri = render_item_vertices_1;
1469 if (vertex < 0x300) {
1470 if (!render_item_vertices_2) {
1471 print_info("Vertices item for vertex %d not yet set!\n", vertex);
1474 ri = render_item_vertices_2;
1477 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1481 /* translate to original position */
1482 *x = ri->u.vertices.x[vertex] - motion_new.position_east;
1483 *y = ri->u.vertices.y[vertex] - motion_new.position_height;
1484 *z = ri->u.vertices.z[vertex] - motion_new.position_north;
1486 /* translate to floating (interpolated) position offset */
1487 *x -= interpolation.offset_east;
1488 *y -= interpolation.offset_height;
1489 *z -= interpolation.offset_north;
1492 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1498 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1501 print_info("Vertex is not a multiple of four!\n");
1504 if (vertex >= MAX_INTERIOR_VERTEX) {
1505 print_info("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1508 if (level < 1 || level > 4) {
1509 print_info("Level %d is out of range (1..4)!\n", level);
1512 if (!render_item_vertices_interior) {
1513 print_info("Vertices item for interior verticies not yet set!\n");
1517 *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1518 *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1519 *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1520 /* translate to position back to original */
1521 *x -= motion_new.position_east;
1522 *y -= motion_new.position_height;
1523 *z -= motion_new.position_north;
1524 /* translate to floating (interpolated) position offset */
1525 *x -= interpolation.offset_east;
1526 *y -= interpolation.offset_height;
1527 *z -= interpolation.offset_north;
1530 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1536 /* renders one item from render list */
1537 void render_one_item(render_item_t *render_item)
1539 switch (render_item->type) {
1540 case RENDER_ITEM_OBJECT_INFO:
1543 printf("RENDER_ITEM_OBJECT_INFO object-id=%d\n", render_item->u.info.id);
1545 render_item_object_info = render_item;
1548 case RENDER_ITEM_VERTICES_0:
1551 printf("RENDER_ITEM_VERTICES_0\n");
1553 render_item_vertices_0 = render_item;
1556 case RENDER_ITEM_VERTICES_1:
1559 printf("RENDER_ITEM_VERTICES_1\n");
1561 render_item_vertices_1 = render_item;
1564 case RENDER_ITEM_VERTICES_2:
1567 printf("RENDER_ITEM_VERTICES_2\n");
1569 render_item_vertices_2 = render_item;
1572 case RENDER_ITEM_VERTICES_INTERIOR:
1575 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1577 if (interpolation.interior)
1578 render_item_vertices_interior = interpolation.interior;
1580 render_item_vertices_interior = render_item;
1583 case RENDER_ITEM_SKY:
1585 double x[4], y[4], z[4];
1588 printf("RENDER_ITEM_SKY\n");
1591 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1592 /* create plane to fill view */
1593 x[0] = x[1] = y[1] = y[2] = -1000000;
1594 x[2] = x[3] = y[0] = y[3] = 1000000;
1595 z[0] = z[1] = z[2] = z[3] = 10;
1597 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sky (background) is always visible! */
1600 case RENDER_ITEM_GROUND:
1603 double x[4], y[4], z[4];
1607 printf("RENDER_ITEM_GROUND\n");
1610 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1611 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1612 /* create huge square */
1613 x[0] = x[1] = z[1] = z[2] = -1000000;
1614 x[2] = x[3] = z[0] = z[3] = 1000000;
1615 y[0] = y[1] = y[2] = y[3] = -10;
1617 for (i = 0; i < 4; i++)
1618 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1620 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1623 case RENDER_ITEM_OBJECT_POLYGON:
1624 case RENDER_ITEM_TAG_POLYGON_OBJECT:
1625 case RENDER_ITEM_TAG_POLYGON_OTHER:
1626 case RENDER_ITEM_ISLAND_POLYGON:
1630 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1635 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1636 printf("RENDER_ITEM_OBJECT_POLYGON\n");
1637 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OBJECT)
1638 printf("RENDER_ITEM_TAG_POLYGON_OBJECT\n");
1639 if (render_item->type == RENDER_ITEM_TAG_POLYGON_OTHER)
1640 printf("RENDER_ITEM_TAG_POLYGON_OTHER\n");
1641 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1642 printf("RENDER_ITEM_ISLAND_POLYGON\n");
1645 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1646 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON && render_item_object_info && !render_item_object_info->u.info.moving) {
1647 // GET_ORIENTATION_FIX;
1652 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1653 /* get and rotate vertex */
1654 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1656 rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], fix);
1659 /* interpolate motion, if object is moving */
1660 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) {
1661 for (o = 0; o < interpolation.object_count; o++) {
1662 if (interpolation.object_id[o] == render_item_object_info->u.info.id)
1665 if (o < interpolation.object_count) {
1666 x[i] += interpolation.object_offset_east[o];
1667 y[i] += interpolation.object_offset_height[o];
1668 z[i] += interpolation.object_offset_north[o];
1672 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1675 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1678 case RENDER_ITEM_OBJECT_LINE:
1679 case RENDER_ITEM_TAG_LINE_OBJECT:
1680 case RENDER_ITEM_TAG_LINE_OTHER:
1684 double x[2], y[2], z[2];
1689 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1690 printf("RENDER_ITEM_OBJECT_LINE\n");
1691 if (render_item->type == RENDER_ITEM_TAG_LINE_OBJECT)
1692 printf("RENDER_ITEM_TAG_LINE_OBJECT\n");
1693 if (render_item->type == RENDER_ITEM_TAG_LINE_OTHER)
1694 printf("RENDER_ITEM_TAG_LINE_OTHER\n");
1697 /* special case where we don't want to interpolate motion (taxi/busses/intercity) */
1698 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) {
1699 // GET_ORIENTATION_FIX;
1704 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1705 /* get and rotate vertex */
1706 for (i = 0; i < 2; i++) {
1708 rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], fix);
1712 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1715 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1718 case RENDER_ITEM_BEACON_POINT:
1725 printf("RENDER_ITEM_BEACON_POINT\n");
1728 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1730 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z, 0);
1734 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1736 opengl_render_point(x, y, z, 0.0);
1739 case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1742 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1747 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1750 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1751 /* get and rotate vertex */
1752 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1754 rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], 0);
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_BUILDING_EXTERIOR_LINE:
1767 double x[2], y[2], z[2];
1772 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1775 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1776 /* get and rotate vertex */
1777 for (i = 0; i < 2; i++) {
1779 rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
1783 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1786 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1789 case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1792 double x[4], y[4], z[4];
1797 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1800 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1801 /* get and rotate vertex */
1802 for (i = 0; i < 4; i++) {
1804 rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1808 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1811 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1814 case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1817 double x[4], y[4], z[4];
1823 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1826 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1827 /* get and rotate vertex */
1828 for (i = 0; i < 4; i++) {
1830 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1831 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1832 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1836 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1839 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1842 case RENDER_ITEM_BUILDING_INTERIOR_WALL:
1845 double x[4], y[4], z[4];
1851 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
1854 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1855 /* chedck if wall is a rectangle or a line */
1856 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
1857 /* get and rotate vertex */
1858 for (i = 0; i < 4; i++) {
1860 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1861 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1862 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1866 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1869 opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
1871 /* get and rotate vertex */
1872 for (i = 0; i < 2; i++) {
1874 vertex = render_item->u.interior56.vertex14;
1875 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1876 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1880 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1883 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1887 case RENDER_ITEM_COMET_POLYGON:
1890 double inclination = motion_new.planet_inclination, azimuth = motion_new.planet_azimuth;
1891 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1896 printf("RENDER_ITEM_COMET_POLYGON\n");
1899 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1900 /* get and rotate vertex */
1901 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1903 rc = use_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i], motion_new.planet_rotation);
1907 if (motion_new.planet_rotation)
1908 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
1909 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1912 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
1915 case RENDER_ITEM_ROAD_LINE:
1918 double x[2], y[2], z[2];
1923 printf("RENDER_ITEM_ROAD_LINE\n");
1926 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1927 /* get and rotate vertex */
1928 for (i = 0; i < 2; i++) {
1930 rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i], 0);
1934 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1937 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1940 case RENDER_ITEM_ROAD_POLYGON:
1943 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1945 uint32_t vertex, vertex_prev, vertex_next;
1946 double x_current, y_current, z_current;
1947 double x_prev, y_prev, z_prev;
1948 double x_next, y_next, z_next;
1953 printf("RENDER_ITEM_ROAD_POLYGON\n");
1956 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1957 /* get and rotate vertex */
1959 vertices_num = render_item->u.polygon.vertices;
1960 for (v = 0; v < vertices_num; v++) {
1962 vertex = render_item->u.polygon.vertex[v];
1963 rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current, 0);
1966 /* check for road extension, so we extend the road to the given end point */
1967 if (extend_roads && vertex >= 0xf0) {
1968 /* previous vertex */
1969 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
1970 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev, 0);
1974 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
1975 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next, 0);
1978 /* extend vertices to end point position
1979 * change x or z coordinate, whatever is greater
1981 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
1982 x_prev = x_next = x_current;
1984 z_prev = z_next = z_current;
1985 /* store vertices */
1990 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1991 if (i++ == MAX_POLYGON)
1997 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1998 if (i++ == MAX_POLYGON)
2002 /* no extension, just keep the current point as is */
2007 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
2008 if (i++ == MAX_POLYGON)
2013 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
2016 case RENDER_ITEM_PLANET:
2019 double inclination = motion_new.planet_inclination, azimuth = motion_new.planet_azimuth;
2020 double sun_x, sun_y, sun_z, angle_sun;
2021 double loc_x, loc_y, loc_z, angle_loc;
2022 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
2028 printf("RENDER_ITEM_PLANET\n");
2031 rc = use_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z, motion_new.planet_rotation);
2034 rc = use_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z, motion_new.planet_rotation);
2038 size = render_item->u.planet.size;
2040 if (motion_new.planet_rotation) {
2041 rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
2042 rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
2044 rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
2045 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2047 /* calculate direction of the sun */
2048 angle_sun = atan2(sun_x, sun_z);
2049 angle_loc = atan2(loc_x, loc_z);
2050 angle = angle_sun - angle_loc;
2052 angle -= 2.0 * M_PI;
2054 angle += 2.0 * M_PI;
2056 /* on which side are we (sun is always bright, vertex == 0) */
2057 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
2058 /* get front side color */
2059 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2061 /* get back side color */
2062 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2065 /* create and render cicle */
2066 for (i = 0; i < PLANET_VERTICES; i++) {
2067 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
2068 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
2071 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2073 if (render_item->u.planet.vertex == 0) {
2074 /* sun has no crescent */
2078 /* on which side are we */
2079 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
2080 /* get back side color */
2081 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
2083 /* get front side color */
2084 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
2087 /* create and render crescent */
2088 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
2089 angle = fabs(angle);
2090 if (angle > M_PI / 2.0)
2091 angle = M_PI - angle;
2093 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2094 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
2095 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
2098 for (; i < PLANET_VERTICES; i++) {
2099 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2100 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
2104 angle = fabs(angle);
2105 if (angle > M_PI / 2.0)
2106 angle = M_PI - angle;
2108 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
2109 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
2110 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
2113 for (; i < PLANET_VERTICES; i++) {
2114 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
2115 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
2119 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
2120 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
2123 case RENDER_ITEM_STARS:
2125 double tilt_offset = 0;
2126 double x_offset = 0;
2128 double view_width, yaw = interpolation.orientation_raw_yaw;
2129 double pitch = interpolation.orientation_raw_pitch;
2130 uint32_t table, table_start;
2134 double red, green, blue;
2137 printf("RENDER_ITEM_STARS\n");
2139 /* use default fov of 64 to calculate z distance */
2140 z = 160.0 / frustum_slope_64;
2142 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
2145 for (i = 0; i < 16; i++)
2146 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2148 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
2149 * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
2150 * then we half it, so we get to the center via 91
2153 if (render_item->u.stars.above_zenith)
2155 yaw = fmod(yaw + 91.0 - (91.0 * (frustum_slope_fov / frustum_slope_64)) + 65536.0, 0x400);
2157 table = mercenary_star_table();
2158 table_start = table + m68k_read_memory_16(table);
2159 table += m68k_read_memory_16(table + ((uint32_t)yaw & 0x7fe));
2160 yaw = yaw / (double)0x800 * 1800.0;
2162 if (render_item->u.stars.above_zenith)
2163 pitch = 0x200 - pitch;
2164 pitch = fmod(pitch + 65536.0, 0x400);
2165 pitch -= render_item->u.stars.v_offset;
2167 pitch = pitch * (double)0x6ccc / 65536.0;
2170 x = m68k_read_memory_16(table);
2173 table = table_start;
2175 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
2179 /* special case where we tilt the view when flying on the planet */
2180 if (render_item->u.stars.tilt) {
2181 /* use offset as given by game: 160 is half of the screen width
2182 * we extend the width to the actual FOV, so it fits
2184 tilt_offset = ((x - (160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) / 65536.0;
2186 y = (double)((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
2188 if (render_item->u.stars.above_zenith) {
2189 x = (double)(view_width - 1) - x;
2193 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
2194 opengl_render_color(red, green, blue, debug_opacity);
2196 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - x, 68.0 - y, z, 0.0);
2200 case RENDER_ITEM_INTERSTELLAR_STARS:
2205 double red, green, blue;
2208 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
2210 /* use default fov of 64 to calculate z distance */
2211 z = 160.0 / frustum_slope_64;
2214 for (i = 0; i < 16; i++)
2215 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
2217 for (i = 0; i < render_item->u.interstars.count; i++) {
2218 gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
2219 opengl_render_color(red, green, blue, debug_opacity);
2221 opengl_render_point(160.0 - (double)render_item->u.interstars.x[i], 68.0 - (double)render_item->u.interstars.y[i], z, 0.0);
2225 case RENDER_ITEM_INTERSTELLAR_SUN:
2227 double red, green, blue;
2230 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
2233 gamecolor2gl(&red, &green, &blue, 0x777);
2234 opengl_render_color(red, green, blue, debug_opacity);
2236 opengl_render_point(0.0, 0.0, 100.0, 0.0);
2239 case RENDER_ITEM_SIGHTS:
2241 double x[4], y[4], z[4];
2242 double red, green, blue;
2245 printf("RENDER_ITEM_SIGHTS\n");
2247 /* use default fov of 64 to calculate z distance */
2248 z[0] = z[1] = z[2] = z[3] = 160.0 / frustum_slope_64;
2251 gamecolor2gl(&red, &green, &blue, 0x777);
2252 opengl_render_color(red, green, blue, debug_opacity);
2256 x[0] = x[1] = -16.0;
2258 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2261 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2264 case RENDER_ITEM_EXPLOSION:
2267 double loc_x, loc_y, loc_z, size;
2268 double x[EXPLOSION_VERTICES], y[EXPLOSION_VERTICES], z[EXPLOSION_VERTICES];
2272 printf("RENDER_ITEM_EXPLOSION\n");
2274 opengl_render_color(render_item->u.explosion.red, render_item->u.explosion.green, render_item->u.explosion.blue, debug_opacity);
2276 for (e = 0; e < render_item->u.explosion.count; e++) {
2277 loc_x = render_item->u.explosion.x[e];
2278 loc_y = render_item->u.explosion.y[e];
2279 loc_z = render_item->u.explosion.z[e];
2280 size = 20; /* round about.... */
2282 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
2283 /* create and render cicle */
2284 for (i = 0; i < EXPLOSION_VERTICES; i++) {
2285 x[i] = loc_x + size * sin(2 * M_PI * (double)i / EXPLOSION_VERTICES) * EXPLOSION_ELIPSE;
2286 y[i] = loc_y + size * cos(2 * M_PI * (double)i / EXPLOSION_VERTICES);
2289 opengl_render_polygon_and_line(x, y, z, EXPLOSION_VERTICES); /* no culling, its a debris! */
2290 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* debris is visible at any distance - at least as a point */
2295 print_info("Unknown render item type, please fix!\n");
2303 static double interpolate_orientation(double old, double new, double inter)
2305 double turn = new - old;
2312 /* don't interpolate, if our rotation was too fast.
2313 * e.g: taxi drive around corder, load/quit game, ...
2315 if (turn > M_PI / 8.0 || turn < -M_PI / 8.0)
2318 new = old + turn * inter;
2328 static double interpolate_raw_orientation(uint16_t old, uint16_t new, double inter)
2330 int16_t turn = (new - old) & 0x3ff;
2335 /* don't interpolate, if our rotation was too fast.
2336 * e.g: taxi drive around corder, load/quit game, ...
2338 if (turn > 0x200 / 8 || turn < -0x200 / 8)
2341 /* don't do modulo 0x400, since the user of this data does it */
2342 return (double)old + (double)turn * inter;
2345 static double interpolate_offset(int32_t old, int32_t new, double inter, int32_t limit)
2349 /* be sure to look only at the lower 28 bits, because on planet these bits are used only */
2350 if (ground_index >= 0)
2351 offset = wrap_int28(old - new);
2353 offset = (int32_t)(old - new);
2355 if (limit > 0 && (offset > limit || offset < -limit))
2358 return offset * (1.0 - inter);
2361 static render_item_t *interpolate_door(double inter)
2363 static render_item_t interpolated;
2364 render_item_t *old_vertices = render_list_old, *new_vertices = render_list_new;
2365 int nomatch_x_count = 0;
2366 int nomatch_z_count = 0;
2367 int nomatch_x[4], nomatch_z[4];
2370 /* find old and new vertices */
2371 while (old_vertices && old_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2372 old_vertices = old_vertices->next;
2373 while (new_vertices && new_vertices->type != RENDER_ITEM_VERTICES_INTERIOR)
2374 new_vertices = new_vertices->next;
2376 /* building does not exist in old or new render */
2377 if (!old_vertices || !new_vertices)
2380 /* all verices must match except four */
2381 ii = MAX_INTERIOR_VERTEX >> 2;
2382 for (i = 0; i < ii; i++) {
2383 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2385 if (old_vertices->u.vertices_interior.x[i] != new_vertices->u.vertices_interior.x[i]) {
2386 if (nomatch_x_count == 4)
2388 nomatch_x[nomatch_x_count++] = i;
2391 for (i = 0; i < 4; i++) {
2392 if (old_vertices->u.vertices_interior.y[i] != new_vertices->u.vertices_interior.y[i])
2395 for (i = 0; i < ii; i++) {
2396 if (!old_vertices->u.vertices_interior.set[i] || !new_vertices->u.vertices_interior.set[i])
2398 if (old_vertices->u.vertices_interior.z[i] != new_vertices->u.vertices_interior.z[i]) {
2399 if (nomatch_z_count == 4)
2401 nomatch_z[nomatch_z_count++] = i;
2405 /* copy, even if not interpolated */
2406 memcpy(&interpolated, new_vertices, sizeof(interpolated));
2408 /* only four x missmatch */
2409 if (nomatch_x_count == 4 || nomatch_x_count == 2) {
2410 for (i = 0; i < nomatch_x_count; i++) {
2411 interpolated.u.vertices_interior.x[nomatch_x[i]] =
2412 (double)old_vertices->u.vertices_interior.x[nomatch_x[i]] * (1.0 - inter) +
2413 (double)new_vertices->u.vertices_interior.x[nomatch_x[i]] * inter;
2417 /* only four z missmatch */
2418 if (nomatch_z_count == 4 || nomatch_z_count == 2) {
2419 for (i = 0; i < nomatch_z_count; i++) {
2420 interpolated.u.vertices_interior.z[nomatch_z[i]] =
2421 (double)old_vertices->u.vertices_interior.z[nomatch_z[i]] * (1.0 - inter) +
2422 (double)new_vertices->u.vertices_interior.z[nomatch_z[i]] * inter;
2426 return &interpolated;
2429 /* make a list of objects that moved and store their displacement */
2430 static void interpolate_objects(double inter)
2432 render_item_t *old_info, *new_info;
2435 /* hunt for objects that exist in both (old and new) lists and moved */
2437 for (new_info = render_list_new; new_info; new_info = new_info -> next) {
2439 if (new_info->type != RENDER_ITEM_OBJECT_INFO)
2442 if (!new_info->u.info.moving)
2444 /* interiors don't move */
2445 if (new_info->u.info.id < 0)
2447 /* check matching object with same ID */
2448 for (old_info = render_list_old; old_info; old_info = old_info -> next) {
2450 if (old_info->type != RENDER_ITEM_OBJECT_INFO)
2453 if (!old_info->u.info.moving)
2456 if (old_info->u.info.id == new_info->u.info.id)
2459 /* no matching object found */
2463 if (old_info->u.info.east == new_info->u.info.east
2464 && old_info->u.info.height == new_info->u.info.height
2465 && old_info->u.info.north == new_info->u.info.north)
2467 /* interpolate and store */
2468 interpolation.object_id[count] = new_info->u.info.id;
2469 interpolation.object_offset_east[count] = interpolate_offset(old_info->u.info.east, new_info->u.info.east, inter, 4096);
2470 interpolation.object_offset_height[count] = interpolate_offset(old_info->u.info.height, new_info->u.info.height, inter, 4096);
2471 interpolation.object_offset_north[count] = interpolate_offset(old_info->u.info.north, new_info->u.info.north, inter, 4096);
2472 if (count++ == MAX_MOVING_OBJECTS)
2475 interpolation.object_count = count;
2478 /* always renders NEW! items
2479 * use inter == 1.0 to render motion to vertices of NEW items
2480 * use inter 0.0 .. 1.0 to interpolate motion between OLD and NEW items
2481 * return 0, if the scene was rendered, returns < 0, if there is no scene
2483 int render_all_items(double inter)
2485 render_item_object_info = NULL;
2486 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2487 render_item_vertices_interior = NULL;
2489 /* no interpolation when leaving or entering planet to/from space */
2490 if ((last_ground_index < 0 && ground_index >= 0)
2491 || (last_ground_index >= 0 && ground_index < 0)) {
2495 /* reset interpolation */
2496 memset(&interpolation, 0, sizeof(interpolation));
2497 interpolation.orientation_roll = motion_new.orientation_roll;
2498 interpolation.orientation_pitch = motion_new.orientation_pitch;
2499 interpolation.orientation_yaw = motion_new.orientation_yaw;
2500 interpolation.orientation_raw_pitch = motion_new.orientation_raw_pitch;
2501 interpolation.orientation_raw_yaw = motion_new.orientation_raw_yaw;
2502 //printf("we are at %08x %08x %08x\n", motion_new.position_east, motion_new.position_height, motion_new.position_north);
2504 /* do interpolation */
2505 if (inter != 1.0 && render_list_old) {
2506 /* interpolate orientation */
2507 interpolation.orientation_roll = interpolate_orientation(motion_old.orientation_roll, motion_new.orientation_roll, inter);
2508 interpolation.orientation_pitch = interpolate_orientation(motion_old.orientation_pitch, motion_new.orientation_pitch, inter);
2509 interpolation.orientation_yaw = interpolate_orientation(motion_old.orientation_yaw, motion_new.orientation_yaw, inter);
2510 interpolation.orientation_raw_pitch = interpolate_raw_orientation(motion_old.orientation_raw_pitch, motion_new.orientation_raw_pitch, inter);
2511 interpolation.orientation_raw_yaw = interpolate_raw_orientation(motion_old.orientation_raw_yaw, motion_new.orientation_raw_yaw, inter);
2513 /* interpolate position */
2514 interpolation.offset_east = interpolate_offset(motion_old.position_east, motion_new.position_east, inter, 0);
2515 interpolation.offset_height = interpolate_offset(motion_old.position_height, motion_new.position_height, inter, 0);
2516 interpolation.offset_north = interpolate_offset(motion_old.position_north, motion_new.position_north, inter, 0);
2517 /* prevent glitch when using elevators: a sudden vertical move is ignored
2518 * this is not the best solution, because fast vertical flying (from 0) will also be detected */
2519 if (old_height_offset == 0
2520 && (new_height_offset >= 150 || new_height_offset <= -150)) {
2521 interpolation.offset_east = 0.0;
2522 interpolation.offset_height = 0.0;
2523 interpolation.offset_north = 0.0;
2526 /* interpolate doors of building (if any) */
2527 interpolation.interior = interpolate_door(inter);
2529 /* interpolate objects */
2530 interpolate_objects(inter);
2533 /* return failure, if nothing can be rendered */
2534 if (!render_list_new)
2537 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2538 render_one_item(render_item);
2544 void render_capture_reset(void)
2546 /* flush old list, if exists */
2548 /* flush new list, if exists */
2549 render_list_old = render_list_new;
2551 /* reset list pointers */
2552 render_list_old = NULL;
2553 render_list_new = NULL;
2554 render_list_end = &render_list_new;
2558 int render_capture_is_interstellar(void)
2560 if (!render_list_new)
2562 for (render_item = render_list_new; render_item; render_item = render_item->next) {
2563 if (render_item->type == RENDER_ITEM_INTERSTELLAR_STARS)