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/>.
26 #include "../libsdl/print.h"
27 #include "../libcpu/m68k.h"
28 #include "../libcpu/m68kcpu.h"
29 #include "../libcpu/execute.h"
30 #include "../libsdl/opengl.h"
31 #include "mercenary.h"
34 //#define DEBUG_VERTEX
37 #define MAX_POLYGON 16 /* number of polygon complexity (vertices) */
38 #define MAX_VERTEX 0x100 /* this is the value range, these are 64 vertices */
39 #define MAX_INTERIOR_VERTEX 0x400 /* do we need that much? */
40 #define MAX_INTERSTARS 80 /* always 80 stars */
41 #define PLANET_VERTICES 128
42 #define PLANET_ELIPSE 1.17
45 static int extend_roads; /* extend roads in its original width, rather than just using a single point */
47 static double debug_opacity;
48 static double frustum_slope_64, frustum_slope_fov;
49 static double orientation_roll, orientation_pitch, orientation_yaw;
50 static uint16_t orientation_raw_yaw;
51 static int16_t orientation_raw_pitch;
52 static double planet_inclination, planet_azimuth;
54 enum render_item_type {
55 RENDER_ITEM_VERTICES_0,
56 RENDER_ITEM_VERTICES_1,
57 RENDER_ITEM_VERTICES_2,
58 RENDER_ITEM_VERTICES_INTERIOR,
61 RENDER_ITEM_OBJECT_POLYGON,
62 RENDER_ITEM_OBJECT_LINE,
63 RENDER_ITEM_BEACON_POINT,
64 RENDER_ITEM_BUILDING_EXTERIOR_POLYGON,
65 RENDER_ITEM_BUILDING_EXTERIOR_LINE,
66 RENDER_ITEM_BUILDING_INTERIOR_1TO4,
67 RENDER_ITEM_BUILDING_INTERIOR_5TO6,
68 RENDER_ITEM_BUILDING_INTERIOR_WALL,
69 RENDER_ITEM_COMET_POLYGON,
70 RENDER_ITEM_ROAD_LINE,
71 RENDER_ITEM_ROAD_POLYGON,
73 RENDER_ITEM_TAG_POLYGON,
76 RENDER_ITEM_INTERSTELLAR_STARS,
77 RENDER_ITEM_INTERSTELLAR_SUN,
78 RENDER_ITEM_ISLAND_POLYGON,
82 struct render_item_vertices {
83 int32_t x[MAX_VERTEX >> 2], y[MAX_VERTEX >> 2], z[MAX_VERTEX >> 2];
86 struct render_item_vertices_interior {
87 int32_t x[MAX_INTERIOR_VERTEX >> 2], y[4], z[MAX_INTERIOR_VERTEX >> 2];
90 struct render_item_sky {
91 double red, green, blue;
94 struct render_item_ground {
95 double red, green, blue;
98 struct render_item_polygon {
99 double red, green, blue;
101 int vertex[MAX_POLYGON];
104 struct render_item_interior14 {
105 double red, green, blue;
110 struct render_item_interior56 {
111 double red, green, blue;
118 struct render_item_line {
119 double red, green, blue;
123 struct render_item_point {
124 double red, green, blue;
128 struct render_item_planet {
129 double front_red, front_green, front_blue;
130 double back_red, back_green, back_blue;
135 struct render_item_stars {
142 struct render_item_interstars {
143 uint8_t color[MAX_INTERSTARS];
144 int16_t x[MAX_INTERSTARS], y[MAX_INTERSTARS];
148 typedef struct render_item {
149 struct render_item *next;
150 enum render_item_type type;
152 struct render_item_vertices vertices;
153 struct render_item_vertices_interior vertices_interior;
154 struct render_item_sky sky;
155 struct render_item_ground ground;
156 struct render_item_polygon polygon;
157 struct render_item_line line;
158 struct render_item_point point;
159 struct render_item_interior14 interior14;
160 struct render_item_interior56 interior56;
161 struct render_item_planet planet;
162 struct render_item_stars stars;
163 struct render_item_interstars interstars;
167 static render_item_t *render_list_start = NULL, **render_list_end = &render_list_start;
168 static render_item_t *render_item;
169 static render_item_t *render_item_vertices_0, *render_item_vertices_1, *render_item_vertices_2;
170 static render_item_t *render_item_vertices_interior;
172 void render_item_add(enum render_item_type type)
174 render_item = calloc(1, sizeof(render_item_t));
176 print_error("No memory, must abort!\n");
179 render_item->type = type;
180 *render_list_end = render_item;
181 render_list_end = &render_item->next;
184 /* rendering starts, initialize variables */
185 void render_capture_start(double _fov, int _extend_roads, int debug)
187 #if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
188 printf("start rendering a new frame...\n");
191 /* flush render list */
192 while (render_list_start) {
193 render_item = render_list_start;
194 render_list_start = render_list_start->next;
197 render_list_end = &render_list_start;
200 /* set rendering options */
202 extend_roads = _extend_roads;
203 /* set some transpareny, if debugging is enabled */
204 debug_opacity = (debug) ? 0.5 : 1.0;
206 /* calculate slope of 64 degree frustum and current FOV's frustum */
207 frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
208 frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
210 /* get orientation */
211 mercenary_get_orientation(&orientation_roll, &orientation_pitch, &orientation_yaw);
212 mercenary_get_orientation_raw(&orientation_raw_pitch, &orientation_raw_yaw);
213 mercenary_get_orientation_planet(&planet_inclination, &planet_azimuth);
215 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
216 render_item_vertices_interior = NULL;
219 void render_capture_stop(void)
223 static void gamecolor2gl_index(double *red, double *green, double *blue, uint16_t index)
228 /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
230 palette = mercenary_palette_render();
231 color = m68k_read_memory_16(palette + index);
233 printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
235 if (color >= 0x8000) {
237 print_error("Use of color index from current palette, but index is not defined as being set!\n");
240 *red = (double)((color >> 8) & 0xf) / 15.0;
241 *green = (double)((color >> 4) & 0xf) / 15.0;
242 *blue = (double)(color & 0xf) / 15.0;
245 static void gamecolor2gl(double *red, double *green, double *blue, uint16_t color)
252 printf("color is given as 0x%04x\n", color);
255 /* color conversion: see for example M3: 0x4f830 */
256 if (color < 0x8000) {
257 /* use given color but shift it left by 1 */
260 printf("using given color, color is now 0x%04x\n", color);
262 } else if ((color & 0xff) < 0x80) {
263 gamecolor2gl_index(red, green, blue, color & 0xf);
266 /* use given index from pre-defined palette */
267 index = color & 0x7e;
268 palette = mercenary_palette_predefined();
269 color = m68k_read_memory_16(palette + index);
271 printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
273 /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
274 if (nesting++ == 8) {
275 print_error("Color lookup from pre-defined palette is nesting too much, please fix!\n");
280 *red = (double)((color >> 8) & 0xf) / 15.0;
281 *green = (double)((color >> 4) & 0xf) / 15.0;
282 *blue = (double)(color & 0xf) / 15.0;
285 static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y, int32_t z)
288 print_error("Vertex %d is not a multiple of four!\n", vertex);
291 /* create new vertices item, if there was no vertex before, or if the vertex has different offet */
292 if (vertex < 0x100) {
293 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_0) {
294 render_item_add(RENDER_ITEM_VERTICES_0);
295 /* copy vertices that have been captured already */
296 if (render_item_vertices_0)
297 memcpy(&render_item->u.vertices, &render_item_vertices_0->u.vertices, sizeof(render_item->u.vertices));
298 render_item_vertices_0 = render_item;
301 if (vertex < 0x200) {
302 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_1) {
303 render_item_add(RENDER_ITEM_VERTICES_1);
304 /* copy vertices that have been captured already */
305 if (render_item_vertices_1)
306 memcpy(&render_item->u.vertices, &render_item_vertices_1->u.vertices, sizeof(render_item->u.vertices));
307 render_item_vertices_1 = render_item;
311 if (vertex < 0x300) {
312 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_2) {
313 render_item_add(RENDER_ITEM_VERTICES_2);
314 /* copy vertices that have been captured already */
315 if (render_item_vertices_2)
316 memcpy(&render_item->u.vertices, &render_item_vertices_2->u.vertices, sizeof(render_item->u.vertices));
317 render_item_vertices_2 = render_item;
321 print_error("Vertex %d exceeds maximum vertex number, please fix!\n", vertex);
326 printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, x, y, z);
328 render_item->u.vertices.x[vertex] = x;
329 render_item->u.vertices.y[vertex] = y;
330 render_item->u.vertices.z[vertex] = z;
333 static void store_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int32_t x, int32_t y1, int32_t y2, int32_t y3, int32_t y4, int32_t z)
336 print_error("Vertex is not a multiple of four!\n");
339 if (vertex >= MAX_INTERIOR_VERTEX) {
340 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
343 if (!render_item || render_item->type != RENDER_ITEM_VERTICES_INTERIOR)
344 render_item_add(RENDER_ITEM_VERTICES_INTERIOR);
347 printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f;%.0f;%.0f;%.0F, Z=%.0F\n", what, vertex, x, y1, y2, y3, y4, z);
349 render_item->u.vertices_interior.x[vertex] = x;
350 render_item->u.vertices_interior.y[0] = y1;
351 render_item->u.vertices_interior.y[1] = y2;
352 render_item->u.vertices_interior.y[2] = y3;
353 render_item->u.vertices_interior.y[3] = y4;
354 render_item->u.vertices_interior.z[vertex] = z;
357 static int planet_rotation = 0;
359 static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
361 double out_x, out_y, out_z;
363 /* rotate yaw (German: Gier, turn view to the right) */
364 out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
365 out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
368 /* rotate pitch (German: Nick, turn head down) */
369 out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
370 out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
375 /* rotate roll (tilt head to the right) */
376 out_x = (*x) * cos(roll) - (*y) * sin(roll);
377 out_y = (*x) * sin(roll) + (*y) * cos(roll);
382 static int ground_index;
384 /* clear screen color (sky / universe) */
385 static void clear_screen(int index)
388 printf("clear screen:\n");
391 /* allocate render item */
392 render_item_add(RENDER_ITEM_SKY);
395 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, 8);
397 /* store for later use after planets have been rendered */
398 ground_index = index;
402 static void draw_ground(void)
404 /* no ground in space :) */
405 if (ground_index < 0)
409 printf("add ground plane:\n");
412 /* allocate render item */
413 render_item_add(RENDER_ITEM_GROUND);
416 gamecolor2gl_index(&render_item->u.ground.red, &render_item->u.ground.green, &render_item->u.ground.blue, ground_index);
419 /* coordinates ready for an object */
420 static void coord_object(void)
424 x = (int16_t)REG_D[3];
425 x += (int32_t)REG_A[1];
426 y = (int16_t)REG_D[4];
427 y += (int32_t)REG_A[2];
428 z = (int16_t)REG_D[5];
429 z += (int32_t)REG_A[3];
430 store_coord("object", REG_A[0], x, y, z);
433 /* polygon of object */
434 static void poly_object(int mercenary)
436 uint32_t vertex_address = REG_A[0];
441 printf("add object's polygon:\n");
444 /* allocate render item */
445 render_item_add(RENDER_ITEM_OBJECT_POLYGON);
449 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
452 color = m68k_read_memory_8(vertex_address++) << 8;
453 color |= m68k_read_memory_8(vertex_address++);
454 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
457 /* the vertex list is zero-terminated */
458 for (i = 0; i < MAX_POLYGON; i++) {
459 vertex = m68k_read_memory_8(vertex_address++);
460 if (vertex == 0 && i)
462 render_item->u.polygon.vertex[i] = vertex;
464 render_item->u.polygon.vertices = i;
468 static void line_object(void)
470 uint32_t vertex_address = REG_A[0];
474 printf("add object's line:\n");
477 /* allocate render item */
478 render_item_add(RENDER_ITEM_OBJECT_LINE);
481 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
484 vertex = m68k_read_memory_8(vertex_address++);
485 render_item->u.line.vertex[0] = vertex;
486 vertex = m68k_read_memory_8(vertex_address++);
487 render_item->u.line.vertex[1] = vertex;
490 /* coordinates ready for a beacon */
491 static void coord_beacon(void)
495 /* only 28 bits seem to be a correct signed int value */
496 x = ((int32_t)REG_D[3] << 4) / 16;
497 y = ((int32_t)REG_D[4] << 4) / 16;
498 z = ((int32_t)REG_D[5] << 4) / 16;
499 store_coord("beacon", 0, x, y, z);
502 /* point of beacon */
503 static void point_beacon(void)
506 printf("add beacon's point:\n");
509 /* allocate render item */
510 render_item_add(RENDER_ITEM_BEACON_POINT);
513 gamecolor2gl(&render_item->u.point.red, &render_item->u.point.green, &render_item->u.point.blue, REG_D[2]);
516 render_item->u.point.vertex = 0;
519 /* coordinates ready for a building (exterior) */
520 static void coord_building_exterior(void)
524 x = (int32_t)REG_D[3];
525 y = (int32_t)REG_D[4];
526 z = (int32_t)REG_D[5];
527 store_coord("building exterior", REG_A[0], x, y, z);
530 /* polygon of building (exterior) */
531 static void poly_building_exterior(void)
534 uint32_t vertex_address = REG_A[0];
539 printf("add building's polygon:\n");
542 /* allocate render item */
543 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_POLYGON);
546 color = m68k_read_memory_8(vertex_address++) << 8;
547 color |= m68k_read_memory_8(vertex_address++);
548 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
550 /* the vertex list is zero-terminated */
551 for (i = 0; i < MAX_POLYGON; i++) {
552 vertex = m68k_read_memory_8(vertex_address++);
553 if (vertex == 0 && i)
555 render_item->u.polygon.vertex[i] = vertex | 0x100;
557 render_item->u.polygon.vertices = i;
560 /* line of building (exterior) */
561 static void line_building_exterior(void)
563 uint32_t vertex_address = REG_A[0];
567 printf("add building's line:\n");
570 /* allocate render item */
571 render_item_add(RENDER_ITEM_BUILDING_EXTERIOR_LINE);
574 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
577 vertex = m68k_read_memory_8(vertex_address++);
578 render_item->u.line.vertex[0] = vertex | 0x100;
579 vertex = m68k_read_memory_8(vertex_address++);
580 render_item->u.line.vertex[1] = vertex | 0x100;
583 static int interior_level12 = 0;
584 static int interior_level34 = 0;
586 /* coordinates ready for a building (interior) */
587 static void coord_building_interior(void)
590 int32_t height1, height2, height3, height4;
592 mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
593 store_interior_coord("interior", REG_A[0], east, height1, height2, height3, height4, north);
596 /* polygon of building (interior) */
597 static void poly_building_interior1to4(int level)
604 printf("add roof/floor's polygon at level %d:\n", level);
607 /* allocate render item */
608 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_1TO4);
611 color = m68k_read_memory_8(REG_A[0]) << 8;
612 color |= m68k_read_memory_8(REG_A[0] + 1);
613 gamecolor2gl(&render_item->u.interior14.red, &render_item->u.interior14.green, &render_item->u.interior14.blue, color);
615 /* four vertices, one level */
616 for (i = 0; i < 4; i++) {
617 vertex = REG_A[(2 + i)];
618 render_item->u.interior14.vertex[i] = vertex;
620 render_item->u.interior14.level = level;
623 /* polygon of building (interior) */
624 static void poly_building_interior5to6(int level12, int level34)
629 printf("add polygon above/below window/door at level %d/%d:\n", level12, level34);
632 /* allocate render item */
633 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_5TO6);
636 color = m68k_read_memory_8(REG_A[0]) << 8;
637 color |= m68k_read_memory_8(REG_A[0] + 1);
638 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, color);
640 /* two vertices, two levels */
641 render_item->u.interior56.vertex14 = REG_A[2];
642 render_item->u.interior56.vertex23 = REG_A[3];
643 render_item->u.interior56.level12 = level12;
644 render_item->u.interior56.level34 = level34;
647 /* wall part of a building */
648 static void wall_building(void)
651 printf("add wall:\n");
654 /* allocate render item */
655 render_item_add(RENDER_ITEM_BUILDING_INTERIOR_WALL);
658 gamecolor2gl(&render_item->u.interior56.red, &render_item->u.interior56.green, &render_item->u.interior56.blue, REG_D[3]);
660 /* two vertices, two levels */
661 render_item->u.interior56.vertex14 = REG_A[1];
662 render_item->u.interior56.vertex23 = REG_A[2];
663 /* get top level according to bit 12 in D3 */
664 render_item->u.interior56.level12 = (REG_D[3] & (1 << 12)) ? 3 : 2;
665 render_item->u.interior56.level34 = 1;
668 /* coordinates ready for comet tail */
669 static void coord_comet(void)
673 x = (int32_t)REG_D[3];
674 y = (int32_t)REG_D[4];
675 z = (int32_t)REG_D[5];
676 store_coord("comet tail", REG_A[0], x, y, z);
679 /* polygon of comet tail */
680 static void poly_comet(void)
683 uint32_t vertex_address = REG_A[0];
688 printf("add comet's polygon:\n");
691 /* allocate render item */
692 render_item_add(RENDER_ITEM_COMET_POLYGON);
695 color = m68k_read_memory_8(vertex_address++) << 8;
696 color |= m68k_read_memory_8(vertex_address++);
697 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
699 /* the vertex list is zero-terminated */
700 for (i = 0; i < MAX_POLYGON; i++) {
701 vertex = m68k_read_memory_8(vertex_address++);
702 if (vertex == 0 && i)
704 render_item->u.polygon.vertex[i] = vertex;
706 render_item->u.polygon.vertices = i;
709 /* coordinates ready for lines of a road / ground surface */
710 static void coord_line_road(void)
715 mercenary_get_height(&y);
718 store_coord("road", REG_A[0], x, y, z);
722 static void line_road(void)
727 printf("add road's line:\n");
730 /* allocate render item */
731 render_item_add(RENDER_ITEM_ROAD_LINE);
734 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_street_color_index());
738 render_item->u.line.vertex[0] = vertex;
740 render_item->u.line.vertex[1] = vertex;
743 /* coordinates ready for polygons of a road / ground surface */
744 static void coord_poly_road(void)
749 x = m68k_read_memory_32(320 + REG_A[0]);
751 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
752 mercenary_get_height(&y);
754 z = m68k_read_memory_32(576 + REG_A[0]);
756 store_coord("road/place", REG_A[0], x, y, z);
759 /* polygon of road */
760 static void poly_road()
763 uint32_t vertex_address = REG_A[0];
768 printf("add road/place's polygon:\n");
771 /* allocate render item */
772 render_item_add(RENDER_ITEM_ROAD_POLYGON);
775 color = m68k_read_memory_8(vertex_address++) << 8;
776 color |= m68k_read_memory_8(vertex_address++);
777 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
779 /* the vertex list is zero-terminated */
780 for (i = 0; i < MAX_POLYGON; i++) {
781 vertex = m68k_read_memory_8(vertex_address++);
782 if (vertex == 0 && i)
784 render_item->u.polygon.vertex[i] = vertex;
786 render_item->u.polygon.vertices = i;
789 /* coordinates ready for tags */
790 static void coord_tags(void)
794 x = (int16_t)REG_D[3];
795 x += (int32_t)REG_A[1];
796 y = (int16_t)REG_D[4];
797 y += (int32_t)REG_A[2];
798 z = (int16_t)REG_D[5];
799 z += (int32_t)REG_A[3];
800 store_coord("tags", REG_A[0], x, y, z);
803 /* coordinates ready for large tags */
804 static void coord_tags2(void)
808 x = (int16_t)REG_D[3];
809 x += 2 * (int32_t)REG_A[1];
810 y = (int16_t)REG_D[4];
811 y += 2 * (int32_t)REG_A[2];
812 z = (int16_t)REG_D[5];
813 z += 2 * (int32_t)REG_A[3];
814 store_coord("large tags", REG_A[0], x, y, z);
818 static void line_tags(int last_color)
820 uint32_t vertex_address = REG_A[0];
824 printf("add tag's line:\n");
827 /* allocate render item */
828 render_item_add(RENDER_ITEM_TAG_LINE);
832 gamecolor2gl(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, REG_D[0]);
834 gamecolor2gl_index(&render_item->u.line.red, &render_item->u.line.green, &render_item->u.line.blue, mercenary_line_tags_index());
837 vertex = m68k_read_memory_8(vertex_address++);
838 render_item->u.line.vertex[0] = vertex | 0x200;
839 vertex = m68k_read_memory_8(vertex_address++);
840 render_item->u.line.vertex[1] = vertex | 0x200;
843 /* polygon of tags */
844 static void poly_tags(int last_color)
846 uint32_t vertex_address = REG_A[0];
851 printf("add tag's polygon:\n");
854 /* allocate render item */
855 render_item_add(RENDER_ITEM_TAG_POLYGON);
859 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, REG_D[0]);
861 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, mercenary_poly_tags_color());
862 /* the vertex list is zero-terminated */
863 for (i = 0; i < MAX_POLYGON; i++) {
864 vertex = m68k_read_memory_8(vertex_address++);
865 if (vertex == 0 && i)
867 render_item->u.polygon.vertex[i] = vertex | 0x200;
869 render_item->u.polygon.vertices = i;
872 /* coordinates ready for planet */
873 static void coord_planet(void)
877 x = (int32_t)REG_D[3];
878 y = (int32_t)REG_D[4];
879 z = (int32_t)REG_D[5];
880 store_coord("planet", REG_A[0], x, y, z);
884 static void draw_planet(int comet)
887 uint32_t scale_index;
888 double scale1, scale2;
892 /* fixing (not noticable) bug in game: don't render comet twice */
893 if (!comet && vertex == 116)
897 printf("add planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
900 /* allocate render item */
901 render_item_add(RENDER_ITEM_PLANET);
905 /* make comet black on front side and bright on back */
906 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, 0x000);
907 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, 0x777);
910 gamecolor2gl(&render_item->u.planet.front_red, &render_item->u.planet.front_green, &render_item->u.planet.front_blue, REG_D[0]);
911 /* use background color for dark side */
912 gamecolor2gl(&render_item->u.planet.back_red, &render_item->u.planet.back_green, &render_item->u.planet.back_blue, mercenary_background_index() | 0x8000);
916 render_item->u.planet.vertex = vertex;
918 /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
919 * the long word 21584(A0) contains two scales
920 * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
921 * the upper word defines how much this scale is shifted to the left.
923 scale_index = mercenary_planet_scale_index();
924 scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
925 scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
926 render_item->u.planet.size = scale1 * scale2 / 128.0;
930 static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
933 printf("add stars\n");
936 /* allocate render item */
937 render_item_add(RENDER_ITEM_STARS);
939 /* vertical offset */
940 render_item->u.stars.v_offset = v_offset;
942 /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
943 render_item->u.stars.tilt = tilt;
945 render_item->u.stars.tilt_value = (int32_t)REG_A[4];
947 /* stars above zenith */
948 render_item->u.stars.above_zenith = above_zenith;
951 /* stars of interstellar flight */
952 static void draw_stars_interstellar(void)
958 printf("add interstellar stars\n");
961 /* allocate render item */
962 render_item_add(RENDER_ITEM_INTERSTELLAR_STARS);
965 count = REG_D[5] + 1;
966 if (count > MAX_INTERSTARS) {
967 print_error("Expecting maximum of %d stars here, plese fix!\n", MAX_INTERSTARS);
970 for (i = 0; i < count; i++) {
973 render_item->u.interstars.color[i] = (m68k_read_memory_16(table) >> 5) & 0xf;
975 render_item->u.interstars.x[i] = m68k_read_memory_16(table);
977 render_item->u.interstars.y[i] = m68k_read_memory_16(table);
980 render_item->u.interstars.count = count;
983 /* sun of interstellar flight (center dot) */
984 static void draw_sun_interstellar(void)
987 printf("add interstellar sun\n");
990 /* allocate render item */
991 render_item_add(RENDER_ITEM_INTERSTELLAR_SUN);
994 /* coordinates ready for polygons of islands */
995 static void coord_islands(void)
999 x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
1000 x += (int32_t)REG_A[1];
1001 /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
1002 mercenary_get_height(&y);
1004 z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
1005 z += (int32_t)REG_A[3];
1006 store_coord("island", REG_A[0], x, y, z);
1009 /* polygon of island */
1010 static void poly_island()
1013 uint32_t vertex_address = REG_A[0];
1018 printf("add island:\n");
1021 /* allocate render item */
1022 render_item_add(RENDER_ITEM_ISLAND_POLYGON);
1025 color = m68k_read_memory_8(vertex_address++) << 8;
1026 color |= m68k_read_memory_8(vertex_address++);
1027 gamecolor2gl(&render_item->u.polygon.red, &render_item->u.polygon.green, &render_item->u.polygon.blue, color);
1029 /* the vertex list is zero-terminated */
1031 while (i < MAX_POLYGON) {
1032 vertex = m68k_read_memory_8(vertex_address++);
1033 if (vertex == 0 && i)
1035 /* skip mysterious points when rendering island */
1038 render_item->u.polygon.vertex[i] = vertex;
1041 render_item->u.polygon.vertices = i;
1045 static void draw_sights(void)
1048 printf("add sights:\n");
1051 /* allocate render item */
1052 render_item_add(RENDER_ITEM_SIGHTS);
1055 /* stop event from CPU received */
1056 void render_capture_event(int event)
1059 case STOP_AT_CLEAR_SCREEN1:
1060 clear_screen(16); /* color 16 is raster split */
1062 case STOP_AT_CLEAR_SCREEN2:
1065 case STOP_AT_CLEAR_SCREEN3:
1066 clear_screen(-1); /* no ground (in universe) */
1068 case STOP_AT_DRAW_GROUND:
1071 case STOP_AT_COORD_OBJECT:
1074 case STOP_AT_POLY_OBJECT_M3:
1077 case STOP_AT_POLY_OBJECT_M2:
1080 case STOP_AT_LINE_OBJECT:
1083 case STOP_AT_COORD_BEACON:
1086 case STOP_AT_POINT_BEACON:
1089 case STOP_AT_COORD_BUILDING_EXTERIOR:
1090 coord_building_exterior();
1092 case STOP_AT_POLY_BUILDING_EXTERIOR:
1093 poly_building_exterior();
1095 case STOP_AT_LINE_BUILDING_EXTERIOR:
1096 line_building_exterior();
1098 case STOP_AT_COORD_BUILDING_INTERIOR:
1099 coord_building_interior();
1101 case STOP_AT_POLY_BUILDING_INTERIOR1:
1103 interior_level12 = 1;
1104 interior_level34 = 1;
1106 case STOP_AT_POLY_BUILDING_INTERIOR2:
1108 interior_level12 = 2;
1109 interior_level34 = 2;
1111 case STOP_AT_POLY_BUILDING_INTERIOR3:
1112 /* door/window top */
1113 interior_level12 = 3;
1114 interior_level34 = 3;
1116 case STOP_AT_POLY_BUILDING_INTERIOR4:
1118 interior_level12 = 4;
1119 interior_level34 = 4;
1121 case STOP_AT_POLY_BUILDING_INTERIOR5:
1122 /* door/window top */
1123 interior_level12 = 2;
1124 interior_level34 = 3;
1126 case STOP_AT_POLY_BUILDING_INTERIOR6:
1128 interior_level12 = 1;
1129 interior_level34 = 4;
1131 case STOP_AT_POLY_BUILDING_INTERIOR1to4:
1132 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1133 if (interior_level12 == 0) {
1134 print_error("Interior level is not set, please fix!\n");
1137 poly_building_interior1to4(interior_level12);
1138 interior_level12 = 0;
1140 case STOP_AT_POLY_BUILDING_INTERIOR5to6:
1141 /* before we come here, we must already passed the break points above, so we know the level to be rendered */
1142 if (interior_level12 == 0) {
1143 print_error("Interior level is not set, please fix!\n");
1146 poly_building_interior5to6(interior_level12, interior_level34);
1147 interior_level12 = 0;
1149 case STOP_AT_WALL_BUILDING:
1152 case STOP_AT_COORD_COMET:
1155 case STOP_AT_MATRIX_COMET:
1156 case STOP_AT_MATRIX_PLANET:
1157 /* track the rotation matrix
1158 * if we have 0x42c44 matrix, we must add extra rotation to planet.
1159 * the rotation will change the view from the planet's surface */
1160 if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
1161 planet_rotation = 1;
1163 planet_rotation = 0;
1165 case STOP_AT_POLY_COMET:
1168 case STOP_AT_COORD_LINE_ROADS:
1171 case STOP_AT_LINE_ROADS:
1174 case STOP_AT_COORD_POLY_ROADS:
1177 case STOP_AT_LINE_ROADS_CENTER:
1178 /* we don't need to render center lines of roads, because there are polygons already
1179 * it does not make sense, since OpenGL has much higher resolution.
1182 case STOP_AT_POLY_ROADS:
1185 case STOP_AT_COORD_TAGS:
1188 case STOP_AT_COORD_TAGS2:
1191 case STOP_AT_LINE_TAGS1:
1194 case STOP_AT_LINE_TAGS2:
1197 case STOP_AT_POLY_TAGS1:
1200 case STOP_AT_POLY_TAGS2:
1203 case STOP_AT_COORD_PLANET:
1206 case STOP_AT_DRAW_PLANET:
1209 case STOP_AT_DRAW_COMET:
1212 case STOP_AT_DRAW_STARS_SPACE:
1213 /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
1214 draw_stars(0x1c0, 0, 0);
1216 case STOP_AT_DRAW_STARS_GROUND:
1217 /* render stars with vertical offset 0x128, no tilt, not above zenith */
1218 draw_stars(0x128, 0, 0); /* yet it's hex 128! */
1220 case STOP_AT_DRAW_STARS_FLYING:
1221 /* render stars with vertical offset 0x128, with tilt, not above zenith */
1222 draw_stars(0x128, 1, 0); /* yet it's hex 128! */
1224 case STOP_AT_DRAW_STARS_FLYING2:
1225 /* render stars with vertical offset 0x128, with tilt, and above zenith */
1226 draw_stars(0x128, 1, 1); /* yet it's hex 128! */
1228 case STOP_AT_DRAW_STARS_INTERSTELLAR:
1229 draw_stars_interstellar();
1231 case STOP_AT_DRAW_SUN_INTERSTELLAR:
1232 draw_sun_interstellar();
1234 case STOP_AT_COORD_ISLANDS:
1237 case STOP_AT_POLY_ISLANDS:
1240 case STOP_AT_LINE_ISLANDS:
1241 /* this is not used, as i had noticed so far */
1242 puts("line island");
1244 case STOP_AT_DRAW_SIGHTS:
1247 case STOP_AT_POLY_UKN2:
1250 case STOP_AT_PLANET_UKN1:
1251 puts("planet ukn1");
1253 case STOP_AT_PLANET_UKN2:
1254 puts("planet ukn2");
1259 static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
1261 render_item_t *ri = NULL;
1264 print_error("Vertex %d is not a multiple of four!\n", vertex);
1267 if (vertex < 0x100) {
1268 if (!render_item_vertices_0) {
1269 print_error("Vertices item for vertex %d not yet set!\n", vertex);
1272 ri = render_item_vertices_0;
1274 if (vertex < 0x200) {
1275 if (!render_item_vertices_1) {
1276 print_error("Vertices item for vertex %d not yet set!\n", vertex);
1279 ri = render_item_vertices_1;
1282 if (vertex < 0x300) {
1283 if (!render_item_vertices_2) {
1284 print_error("Vertices item for vertex %d not yet set!\n", vertex);
1287 ri = render_item_vertices_2;
1290 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1294 *x = ri->u.vertices.x[vertex];
1295 *y = ri->u.vertices.y[vertex];
1296 *z = ri->u.vertices.z[vertex];
1298 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1304 static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
1307 print_error("Vertex is not a multiple of four!\n");
1310 if (vertex >= MAX_VERTEX) {
1311 print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
1314 if (level < 1 || level > 4) {
1315 print_error("Level %d is out of range (1..4)!\n", level);
1318 if (!render_item_vertices_interior) {
1319 print_error("Vertices item for interior verticies not yet set!\n");
1323 *x = render_item_vertices_interior->u.vertices_interior.x[vertex];
1324 *y = render_item_vertices_interior->u.vertices_interior.y[level - 1];
1325 *z = render_item_vertices_interior->u.vertices_interior.z[vertex];
1327 printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
1333 /* renders one item from render list */
1334 void render_one_item(render_item_t *render_item)
1336 switch (render_item->type) {
1337 case RENDER_ITEM_VERTICES_0:
1340 printf("RENDER_ITEM_VERTICES_0\n");
1342 render_item_vertices_0 = render_item;
1345 case RENDER_ITEM_VERTICES_1:
1348 printf("RENDER_ITEM_VERTICES_1\n");
1350 render_item_vertices_1 = render_item;
1353 case RENDER_ITEM_VERTICES_2:
1356 printf("RENDER_ITEM_VERTICES_2\n");
1358 render_item_vertices_2 = render_item;
1361 case RENDER_ITEM_VERTICES_INTERIOR:
1364 printf("RENDER_ITEM_VERTICES_INTERIOR\n");
1366 render_item_vertices_interior = render_item;
1369 case RENDER_ITEM_SKY:
1371 double x[4], y[4], z[4];
1374 printf("RENDER_ITEM_SKY\n");
1377 opengl_render_color(render_item->u.sky.red, render_item->u.sky.green, render_item->u.sky.blue, 1.0);
1378 /* create plane to fill view */
1379 x[0] = x[1] = y[1] = y[2] = -1000000;
1380 x[2] = x[3] = y[0] = y[3] = 1000000;
1381 z[0] = z[1] = z[2] = z[3] = 10;
1383 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sky (background) is always visible! */
1386 case RENDER_ITEM_GROUND:
1388 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1389 double x[4], y[4], z[4];
1393 printf("RENDER_ITEM_GROUND\n");
1396 opengl_render_color(render_item->u.ground.red, render_item->u.ground.green, render_item->u.ground.blue, 1.0);
1397 yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
1398 /* create huge square */
1399 x[0] = x[1] = z[1] = z[2] = -1000000;
1400 x[2] = x[3] = z[0] = z[3] = 1000000;
1401 y[0] = y[1] = y[2] = y[3] = -10;
1403 for (i = 0; i < 4; i++)
1404 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1406 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because gound is always visible! */
1409 case RENDER_ITEM_OBJECT_POLYGON:
1410 case RENDER_ITEM_TAG_POLYGON:
1411 case RENDER_ITEM_ISLAND_POLYGON:
1413 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1414 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1419 if (render_item->type == RENDER_ITEM_OBJECT_POLYGON)
1420 printf("RENDER_ITEM_OBJECT_POLYGON\n");
1421 if (render_item->type == RENDER_ITEM_TAG_POLYGON)
1422 printf("RENDER_ITEM_TAG_POLYGON\n");
1423 if (render_item->type == RENDER_ITEM_ISLAND_POLYGON)
1424 printf("RENDER_ITEM_ISLAND_POLYGON\n");
1427 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1428 /* get and rotate vertex */
1429 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1431 rc = use_coord("object", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1435 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1438 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1441 case RENDER_ITEM_OBJECT_LINE:
1442 case RENDER_ITEM_TAG_LINE:
1444 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1445 double x[2], y[2], z[2];
1450 if (render_item->type == RENDER_ITEM_OBJECT_LINE)
1451 printf("RENDER_ITEM_OBJECT_LINE\n");
1452 if (render_item->type == RENDER_ITEM_TAG_LINE)
1453 printf("RENDER_ITEM_TAG_LINE\n");
1456 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1457 /* get and rotate vertex */
1458 for (i = 0; i < 2; i++) {
1460 rc = use_coord("object", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1464 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1467 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1470 case RENDER_ITEM_BEACON_POINT:
1472 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1477 printf("RENDER_ITEM_BEACON_POINT\n");
1480 opengl_render_color(render_item->u.point.red, render_item->u.point.green, render_item->u.point.blue, debug_opacity);
1482 rc = use_coord("beacon", render_item->u.point.vertex, &x, &y, &z);
1486 rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
1488 opengl_render_point(x, y, z, 0.0);
1491 case RENDER_ITEM_BUILDING_EXTERIOR_POLYGON:
1493 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1494 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1499 printf("RENDER_ITEM_BUILDING_EXTERIOR_POLYGON\n");
1502 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1503 /* get and rotate vertex */
1504 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1506 rc = use_coord("building exterior", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1510 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1513 opengl_render_polygon(x, y, z, render_item->u.polygon.vertices, 1); /* back face culling */
1516 case RENDER_ITEM_BUILDING_EXTERIOR_LINE:
1518 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1519 double x[2], y[2], z[2];
1524 printf("RENDER_ITEM_BUILDING_EXTERIOR_LINE\n");
1527 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1528 /* get and rotate vertex */
1529 for (i = 0; i < 2; i++) {
1531 rc = use_coord("building exterior", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1535 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1538 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1541 case RENDER_ITEM_BUILDING_INTERIOR_1TO4:
1543 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1544 double x[4], y[4], z[4];
1549 printf("RENDER_ITEM_BUILDING_INTERIOR_1TO4\n");
1552 opengl_render_color(render_item->u.interior14.red, render_item->u.interior14.green, render_item->u.interior14.blue, debug_opacity);
1553 /* get and rotate vertex */
1554 for (i = 0; i < 4; i++) {
1556 rc = use_interior_coord("building exterior", render_item->u.interior14.vertex[i], render_item->u.interior14.level, &x[i], &y[i], &z[i]);
1560 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1563 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1566 case RENDER_ITEM_BUILDING_INTERIOR_5TO6:
1568 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1569 double x[4], y[4], z[4];
1575 printf("RENDER_ITEM_BUILDING_INTERIOR_5TO6\n");
1578 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1579 /* get and rotate vertex */
1580 for (i = 0; i < 4; i++) {
1582 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1583 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1584 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1588 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1591 opengl_render_polygon(x, y, z, 4, 1); /* back face culling */
1594 case RENDER_ITEM_BUILDING_INTERIOR_WALL:
1596 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1597 double x[4], y[4], z[4];
1603 printf("RENDER_ITEM_BUILDING_INTERIOR_WALL\n");
1606 opengl_render_color(render_item->u.interior56.red, render_item->u.interior56.green, render_item->u.interior56.blue, debug_opacity);
1607 /* chedck if wall is a rectangle or a line */
1608 if (render_item->u.interior56.vertex14 != render_item->u.interior56.vertex23) {
1609 /* get and rotate vertex */
1610 for (i = 0; i < 4; i++) {
1612 vertex = (i == 0 || i == 3) ? render_item->u.interior56.vertex14 : render_item->u.interior56.vertex23;
1613 level = (i == 0 || i == 1) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1614 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1618 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1621 opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
1623 /* get and rotate vertex */
1624 for (i = 0; i < 2; i++) {
1626 vertex = render_item->u.interior56.vertex14;
1627 level = (i == 0) ? render_item->u.interior56.level12 : render_item->u.interior56.level34;
1628 rc = use_interior_coord("building interior", vertex, level, &x[i], &y[i], &z[i]);
1632 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1635 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1639 case RENDER_ITEM_COMET_POLYGON:
1641 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1642 double inclination = planet_inclination, azimuth = planet_azimuth;
1643 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1648 printf("RENDER_ITEM_COMET_POLYGON\n");
1651 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1652 /* get and rotate vertex */
1653 for (i = 0; i < render_item->u.polygon.vertices; i++) {
1655 rc = use_coord("comet tail", render_item->u.polygon.vertex[i], &x[i], &y[i], &z[i]);
1659 if (planet_rotation)
1660 rotate_coordinate(0.0, inclination, azimuth, &x[i], &y[i], &z[i]);
1661 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1664 opengl_render_polygon_and_line(x, y, z, render_item->u.polygon.vertices); /* no culling, because we render only two (out of four) planes! */
1667 case RENDER_ITEM_ROAD_LINE:
1669 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1670 double x[2], y[2], z[2];
1675 printf("RENDER_ITEM_ROAD_LINE\n");
1678 opengl_render_color(render_item->u.line.red, render_item->u.line.green, render_item->u.line.blue, debug_opacity);
1679 /* get and rotate vertex */
1680 for (i = 0; i < 2; i++) {
1682 rc = use_coord("road", render_item->u.line.vertex[i], &x[i], &y[i], &z[i]);
1686 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1689 opengl_render_line(x[0], y[0], z[0], x[1], y[1], z[1], 0.0);
1692 case RENDER_ITEM_ROAD_POLYGON:
1694 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1695 double x[MAX_POLYGON], y[MAX_POLYGON], z[MAX_POLYGON];
1697 uint32_t vertex, vertex_prev, vertex_next;
1698 double x_current, y_current, z_current;
1699 double x_prev, y_prev, z_prev;
1700 double x_next, y_next, z_next;
1705 printf("RENDER_ITEM_ROAD_POLYGON\n");
1708 opengl_render_color(render_item->u.polygon.red, render_item->u.polygon.green, render_item->u.polygon.blue, debug_opacity);
1709 /* get and rotate vertex */
1711 vertices_num = render_item->u.polygon.vertices;
1712 for (v = 0; v < vertices_num; v++) {
1714 vertex = render_item->u.polygon.vertex[v];
1715 rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current);
1718 /* check for road extension, so we extend the road to the given end point */
1719 if (extend_roads && vertex >= 0xf0) {
1720 /* previous vertex */
1721 vertex_prev = render_item->u.polygon.vertex[(v + vertices_num - 1) % vertices_num];
1722 rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev);
1726 vertex_next = render_item->u.polygon.vertex[(v + 1) % vertices_num];
1727 rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next);
1730 /* extend vertices to end point position
1731 * change x or z coordinate, whatever is greater
1733 if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
1734 x_prev = x_next = x_current;
1736 z_prev = z_next = z_current;
1737 /* store vertices */
1742 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1743 if (i++ == MAX_POLYGON)
1749 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1750 if (i++ == MAX_POLYGON)
1754 /* no extension, just keep the current point as is */
1759 rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
1760 if (i++ == MAX_POLYGON)
1765 opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
1768 case RENDER_ITEM_PLANET:
1770 double roll = orientation_roll, pitch = orientation_pitch, yaw = orientation_yaw;
1771 double inclination = planet_inclination, azimuth = planet_azimuth;
1772 double sun_x, sun_y, sun_z, angle_sun;
1773 double loc_x, loc_y, loc_z, angle_loc;
1774 double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
1780 printf("RENDER_ITEM_PLANET\n");
1783 rc = use_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
1786 rc = use_coord("planet", render_item->u.planet.vertex, &loc_x, &loc_y, &loc_z);
1790 size = render_item->u.planet.size;
1792 if (planet_rotation) {
1793 rotate_coordinate(0.0, inclination, azimuth, &sun_x, &sun_y, &sun_z);
1794 rotate_coordinate(0.0, inclination, azimuth, &loc_x, &loc_y, &loc_z);
1796 rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
1797 rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
1799 /* calculate direction of the sun */
1800 angle_sun = atan2(sun_x, sun_z);
1801 angle_loc = atan2(loc_x, loc_z);
1802 angle = angle_sun - angle_loc;
1804 angle -= 2.0 * M_PI;
1806 angle += 2.0 * M_PI;
1808 /* on which side are we (sun is always bright, vertex == 0) */
1809 if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || render_item->u.planet.vertex == 0) {
1810 /* get front side color */
1811 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
1813 /* get back side color */
1814 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
1817 /* create and render cicle */
1818 for (i = 0; i < PLANET_VERTICES; i++) {
1819 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1820 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1823 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
1825 if (render_item->u.planet.vertex == 0) {
1826 /* sun has no crescent */
1830 /* on which side are we */
1831 if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
1832 /* get back side color */
1833 opengl_render_color(render_item->u.planet.back_red, render_item->u.planet.back_green, render_item->u.planet.back_blue, debug_opacity);
1835 /* get front side color */
1836 opengl_render_color(render_item->u.planet.front_red, render_item->u.planet.front_green, render_item->u.planet.front_blue, debug_opacity);
1839 /* create and render crescent */
1840 if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
1841 angle = fabs(angle);
1842 if (angle > M_PI / 2.0)
1843 angle = M_PI - angle;
1845 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
1846 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1847 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1850 for (; i < PLANET_VERTICES; i++) {
1851 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
1852 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1856 angle = fabs(angle);
1857 if (angle > M_PI / 2.0)
1858 angle = M_PI - angle;
1860 for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
1861 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE * sin((1.0 - angle / (M_PI / 2)) * (M_PI / 2.0));
1862 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1865 for (; i < PLANET_VERTICES; i++) {
1866 x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
1867 y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
1871 opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
1872 opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
1875 case RENDER_ITEM_STARS:
1877 int16_t tilt_offset = 0;
1880 uint16_t view_width, yaw = orientation_raw_yaw;
1881 int16_t pitch = orientation_raw_pitch;
1882 uint32_t table, table_start;
1886 double red, green, blue;
1889 printf("RENDER_ITEM_STARS\n");
1891 /* use default fov of 64 to calculate z distance */
1892 z = 160.0 / frustum_slope_64;
1894 view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
1897 for (i = 0; i < 16; i++)
1898 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
1900 /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
1901 * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
1902 * then we half it, so we get to the center via 91
1905 if (render_item->u.stars.above_zenith)
1907 yaw = (yaw + 91 - (int)(91.0 * (frustum_slope_fov / frustum_slope_64))) & 0x3ff;
1909 table = mercenary_star_table();
1910 table_start = table + m68k_read_memory_16(table);
1911 table += m68k_read_memory_16(table + yaw);
1912 yaw = ((uint32_t)yaw * 0xe10e) >> 16;
1914 if (render_item->u.stars.above_zenith)
1915 pitch = 0x200 - pitch;
1916 pitch = pitch & 0x3ff;
1917 pitch -= render_item->u.stars.v_offset;
1919 pitch = (pitch * 0x6ccc) >> 16;
1922 x = m68k_read_memory_16(table);
1925 table = table_start;
1927 x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
1931 /* special case where we tilt the view when flying on the planet */
1932 if (render_item->u.stars.tilt) {
1933 /* use offset as given by game: 160 is half of the screen width
1934 * we extend the width to the actual FOV, so it fits
1936 tilt_offset = (int32_t)((x - (int16_t)(160.0 / frustum_slope_64 * frustum_slope_fov)) * render_item->u.stars.tilt_value) >> 16;
1938 y = ((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
1940 if (render_item->u.stars.above_zenith) {
1941 x = (view_width - 1) - x;
1945 gamecolor2gl(&red, &green, &blue, color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
1946 opengl_render_color(red, green, blue, debug_opacity);
1948 opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - (double)x, 68.0 - (double)y, z, 0.0);
1952 case RENDER_ITEM_INTERSTELLAR_STARS:
1957 double red, green, blue;
1960 printf("RENDER_ITEM_INTERSTELLAR_STARS\n");
1962 /* use default fov of 64 to calculate z distance */
1963 z = 160.0 / frustum_slope_64;
1966 for (i = 0; i < 16; i++)
1967 color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
1969 for (i = 0; i < render_item->u.interstars.count; i++) {
1970 gamecolor2gl(&red, &green, &blue, color[render_item->u.interstars.color[i]]);
1971 opengl_render_color(red, green, blue, debug_opacity);
1973 opengl_render_point(160.0 - (double)render_item->u.interstars.x[i], 68.0 - (double)render_item->u.interstars.y[i], z, 0.0);
1977 case RENDER_ITEM_INTERSTELLAR_SUN:
1979 double red, green, blue;
1982 printf("RENDER_ITEM_INTERSTELLAR_SUN\n");
1985 gamecolor2gl(&red, &green, &blue, 0x777);
1986 opengl_render_color(red, green, blue, debug_opacity);
1988 opengl_render_point(0.0, 0.0, 100.0, 0.0);
1991 case RENDER_ITEM_SIGHTS:
1993 double x[4], y[4], z[4];
1994 double red, green, blue;
1997 printf("RENDER_ITEM_SIGHTS\n");
1999 /* use default fov of 64 to calculate z distance */
2000 z[0] = z[1] = z[2] = z[3] = 160.0 / frustum_slope_64;
2003 gamecolor2gl(&red, &green, &blue, 0x777);
2004 opengl_render_color(red, green, blue, debug_opacity);
2008 x[0] = x[1] = -16.0;
2010 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2013 opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
2017 print_error("Unknown type, please fix!\n");
2021 void render_all_items()
2023 render_item_vertices_0 = render_item_vertices_1 = render_item_vertices_2 = NULL;
2024 render_item_vertices_interior = NULL;
2026 for (render_item = render_list_start; render_item; render_item = render_item->next) {
2027 render_one_item(render_item);