-/* render routines that replaces the game rendering with modern rendering
+/* render routines that replaces the game rendering by OpenGL rendering
*
* (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
* All Rights Reserved
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
+#include <GL/glew.h>
+#include "../libsdl/print.h"
#include "../libcpu/m68k.h"
+#include "../libcpu/m68kcpu.h"
#include "../libcpu/execute.h"
+#include "../libsdl/opengl.h"
#include "mercenary.h"
-#define OBJECT_COORD_MAX 256
-static int object_coord_valid; /* set, if the coordinates below are valid */
-static int object_coord_num;
-static int object_coord_x[OBJECT_COORD_MAX];
-static int object_coord_y[OBJECT_COORD_MAX];
-static int object_coord_z[OBJECT_COORD_MAX];
+//#define DEBUG_COLOR
+//#define DEBUG_VERTEX
+
+#define MAX_VERTEX 0x300
+static int coord_x[MAX_VERTEX >> 2];
+static int coord_y[MAX_VERTEX >> 2];
+static int coord_z[MAX_VERTEX >> 2];
+
+#define MAX_INTERIOR_VERTEX 0x400 /* do we need that much? */
+static int interior_coord_x[MAX_INTERIOR_VERTEX >> 2];
+static int interior_coord_y[MAX_INTERIOR_VERTEX >> 2][4]; /* 4 levels (floor; ceiling; window or door top; window bottom) */
+static int interior_coord_z[MAX_INTERIOR_VERTEX >> 2];
+
+static int extend_roads; /* extend roads in its original width, rather than just using a single point */
+static double fov;
+static double transparency;
+static double frustum_slope_64, frustum_slope_fov;
/* rendering starts, initialize variables */
-void render_start(void)
+void render_start(double _fov, int _extend_roads, int debug)
+{
+#if defined(DEBUG_COLOR) || defined(DEBUG_VERTEX)
+ printf("start rendering a new frame...\n");
+#endif
+
+ fov = _fov;
+ extend_roads = _extend_roads;
+
+ transparency = (debug) ? 0.5 : 0.0;
+ opengl_transparency_set(transparency);
+
+ /* calculate slope of 64 degree frustum and current FOV's frustum */
+ frustum_slope_64 = tan(64.0 / 2.0 / 180.0 * M_PI);
+ frustum_slope_fov = tan(fov / 2.0 / 180.0 * M_PI);
+}
+
+void render_finish(void)
+{
+ opengl_transparency_set(0.0);
+}
+
+static void gamecolor2gl_index(uint16_t index)
+{
+ uint32_t palette;
+ uint16_t color;
+
+ /* use given index from current palette, so we take the palette from M3:DS_0+0x1FA8 */
+ index <<= 1;
+ palette = mercenary_palette_render();
+ color = m68k_read_memory_16(palette + index);
+#ifdef DEBUG_COLOR
+ printf("using color index (%d) from current palette, color is now 0x%04x\n", index, color);
+#endif
+ if (color >= 0x8000) {
+#ifdef DEBUG_COLOR
+ print_error("Use of color index from current palette, but index is not defined as being set!\n");
+#endif
+ }
+ opengl_render_color(
+ (double)((color >> 8) & 0xf) / 15.0,
+ (double)((color >> 4) & 0xf) / 15.0,
+ (double)(color & 0xf) / 15.0
+ );
+}
+
+static void gamecolor2gl(uint16_t color)
+{
+ uint16_t index;
+ uint32_t palette;
+ int nesting = 0;
+
+#ifdef DEBUG_COLOR
+ printf("color is given as 0x%04x\n", color);
+#endif
+again:
+ /* color conversion: see for example M3: 0x4f830 */
+ if (color < 0x8000) {
+ /* use given color but shift it left by 1 */
+ color = color << 1;
+#ifdef DEBUG_COLOR
+ printf("using given color, color is now 0x%04x\n", color);
+#endif
+ } else if ((color & 0xff) < 0x80) {
+ gamecolor2gl_index(color & 0xf);
+ return;
+ } else {
+ /* use given index from pre-defined palette */
+ index = color & 0x7e;
+ palette = mercenary_palette_predefined();
+ color = m68k_read_memory_16(palette + index);
+#ifdef DEBUG_COLOR
+ printf("offset (%d) from pre-defined palette (at 0x%x) given, color is now 0x%04x\n", index, palette, color);
+#endif
+ /* now use that color info parse again (hopefully it does not contain a "pre-defined palette" again and again! */
+ if (nesting++ == 8) {
+ print_error("Color lookup from pre-defined palette is nesting too much, please fix!\n");
+ return;
+ }
+ goto again;
+ }
+ opengl_render_color(
+ (double)((color >> 8) & 0xf) / 15.0,
+ (double)((color >> 4) & 0xf) / 15.0,
+ (double)(color & 0xf) / 15.0
+ );
+}
+
+static void store_coord(const char __attribute__((unused)) *what, uint32_t vertex, double x, double y, double z)
+{
+ if ((vertex & 3)) {
+ print_error("Vertex %d is not a multiple of four!\n", vertex);
+ return;
+ }
+ if (vertex >= MAX_VERTEX) {
+ print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+ return;
+ }
+ vertex >>= 2;
+#ifdef DEBUG_VERTEX
+ printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, x, y, z);
+#endif
+ coord_x[vertex] = x;
+ coord_y[vertex] = y;
+ coord_z[vertex] = z;
+}
+
+static int use_coord(const char __attribute__((unused)) *what, uint32_t vertex, double *x, double *y, double *z)
+{
+ if ((vertex & 3)) {
+ print_error("Vertex %d is not a multiple of four!\n", vertex);
+ return -1;
+ }
+ if (vertex >= MAX_VERTEX) {
+ print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+ return -1;
+ }
+ vertex >>= 2;
+ *x = coord_x[vertex];
+ *y = coord_y[vertex];
+ *z = coord_z[vertex];
+#ifdef DEBUG_VERTEX
+ printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
+#endif
+
+ return 0;
+}
+
+static void store_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, double x, double y1, double y2, double y3, double y4, double z)
+{
+ if ((vertex & 3)) {
+ print_error("Vertex is not a multiple of four!\n");
+ return;
+ }
+ if (vertex >= MAX_INTERIOR_VERTEX) {
+ print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_INTERIOR_VERTEX);
+ return;
+ }
+ vertex >>= 2;
+#ifdef DEBUG_VERTEX
+ printf("storing %s coordinates: vertex=%d, x=%.0f, y=%.0f;%.0f;%.0f;%.0F, Z=%.0F\n", what, vertex, x, y1, y2, y3, y4, z);
+#endif
+ interior_coord_x[vertex] = x;
+ interior_coord_y[vertex][0] = y1;
+ interior_coord_y[vertex][1] = y2;
+ interior_coord_y[vertex][2] = y3;
+ interior_coord_y[vertex][3] = y4;
+ interior_coord_z[vertex] = z;
+}
+
+static int use_interior_coord(const char __attribute__((unused)) *what, uint32_t vertex, int level, double *x, double *y, double *z)
+{
+ if ((vertex & 3)) {
+ print_error("Vertex is not a multiple of four!\n");
+ return -1;
+ }
+ if (vertex >= MAX_VERTEX) {
+ print_error("Vertex %d exceeds maximum vertex number %d!\n", vertex, MAX_VERTEX);
+ return -1;
+ }
+ if (level < 1 || level > 4) {
+ print_error("Level %d is out of range (1..4)!\n", level);
+ return -1;
+ }
+ vertex >>= 2;
+ *x = interior_coord_x[vertex];
+ *y = interior_coord_y[vertex][level - 1];
+ *z = interior_coord_z[vertex];
+#ifdef DEBUG_VERTEX
+ printf("using %s coordinates: vertex=%d, x=%.0f, y=%.0f, z=%.0f\n", what, vertex, *x, *y, *z);
+#endif
+
+ return 0;
+}
+
+static int planet_rotation = 0;
+
+static void rotate_coordinate(double roll, double pitch, double yaw, double *x, double *y, double *z)
+{
+ double out_x, out_y, out_z;
+
+ /* rotate yaw (German: Gier, turn view to the right) */
+ out_z = (*z) * cos(yaw) - (*x) * sin(yaw);
+ out_x = (*z) * sin(yaw) + (*x) * cos(yaw);
+ *z = out_z;
+ *x = out_x;
+ /* rotate pitch (German: Nick, turn head down) */
+ out_y = (*y) * cos(pitch) - (*z) * sin(pitch);
+ out_z = (*y) * sin(pitch) + (*z) * cos(pitch);
+ *y = out_y;
+ *z = out_z;
+ if (roll == 0.0)
+ return;
+ /* rotate roll (tilt head to the right) */
+ out_x = (*x) * cos(roll) - (*y) * sin(roll);
+ out_y = (*x) * sin(roll) + (*y) * cos(roll);
+ *x = out_x;
+ *y = out_y;
+}
+
+/* coordinates ready for an object */
+static void coord_object(void)
+{
+ int32_t x, y, z;
+
+ x = (int16_t)REG_D[3];
+ x += (int32_t)REG_A[1];
+ y = (int16_t)REG_D[4];
+ y += (int32_t)REG_A[2];
+ z = (int16_t)REG_D[5];
+ z += (int32_t)REG_A[3];
+ store_coord("object", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+static int ground_index;
+
+/* clear screen (sky / universe) */
+static void clear_screen(int index)
+{
+ double x[4], y[4], z[4];
+
+#ifdef DEBUG_VERTEX
+ printf("clear screen:\n");
+#endif
+
+ opengl_transparency_set(0.0);
+
+ /* create plane to fill view */
+ x[0] = x[1] = y[1] = y[2] = -1000000;
+ x[2] = x[3] = y[0] = y[3] = 1000000;
+ z[0] = z[1] = z[2] = z[3] = 10;
+ gamecolor2gl_index(8);
+ opengl_render_polygon(x, y, z, 4, 0); /* no culling, because background is always visible! */
+
+ opengl_transparency_set(transparency);
+
+ /* store for later use after planets have been rendered */
+ ground_index = index;
+}
+
+/* draw ground */
+static void draw_ground(void)
+{
+ double roll, pitch, yaw, x[4], y[4], z[4];
+
+ /* no ground in space :) */
+ if (ground_index < 0)
+ return;
+
+#ifdef DEBUG_VERTEX
+ printf("draw ground plane:\n");
+#endif
+
+ opengl_transparency_set(0.0);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+ yaw = 0.0; /* no need to rotate x-z plane, we don't want look at a corner of the 'ground-square' */
+
+ /* create huge square */
+ x[0] = x[1] = z[1] = z[2] = -1000000;
+ x[2] = x[3] = z[0] = z[3] = 1000000;
+ y[0] = y[1] = y[2] = y[3] = -10;
+
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[0], &y[0], &z[0]);
+ rotate_coordinate(roll, pitch, yaw, &x[1], &y[1], &z[1]);
+ rotate_coordinate(roll, pitch, yaw, &x[2], &y[2], &z[2]);
+ rotate_coordinate(roll, pitch, yaw, &x[3], &y[3], &z[3]);
+
+ gamecolor2gl_index(ground_index);
+ opengl_render_polygon(x, y, z, 4, 0); /* no culling, because ground is always visible! */
+
+ opengl_transparency_set(transparency);
+}
+
+/* render polygon of object */
+static void poly_object(int mercenary)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw object's polygon:\n");
+#endif
+ if (mercenary == 3)
+ gamecolor2gl(REG_D[0]);
+ else {
+ uint16_t color;
+ color = m68k_read_memory_8(vertex_address++) << 8;
+ color |= m68k_read_memory_8(vertex_address++);
+ gamecolor2gl(color);
+ }
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 16; i++) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ /* get vertex */
+ rc = use_coord("object", vertex, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 1); /* back face culling */
+}
+
+/* render line of object */
+static void line_object(void)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ double roll, pitch, yaw, x1, y1, z1, x2, y2, z2;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw object's line:\n");
+#endif
+ gamecolor2gl(REG_D[0]);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ vertex = m68k_read_memory_8(vertex_address++);
+ /* get vertex */
+ rc = use_coord("object", vertex, &x1, &y1, &z1);
+ if (rc < 0)
+ return;
+ vertex = m68k_read_memory_8(vertex_address++);
+ /* get vertex */
+ rc = use_coord("object", vertex, &x2, &y2, &z2);
+ if (rc < 0)
+ return;
+ /* rotate vertices */
+ rotate_coordinate(roll, pitch, yaw, &x1, &y1, &z1);
+ rotate_coordinate(roll, pitch, yaw, &x2, &y2, &z2);
+ /* transfer line to OpenGL */
+ opengl_render_line(x1, y1, z1, x2, y2, z2, 0.0);
+}
+
+/* coordinates ready for a beacon */
+static void coord_beacon(void)
+{
+ int32_t x, y, z;
+
+ /* only 28 bits seem to be a correct signed int value */
+ x = (double)((int32_t)REG_D[3] << 4) / 16.0;
+ y = (double)((int32_t)REG_D[4] << 4) / 16.0;
+ z = (double)((int32_t)REG_D[5] << 4) / 16.0;
+ store_coord("beacon", 0, (double)x, (double)y, (double)z);
+}
+
+/* render point of beacon */
+static void point_beacon(void)
+{
+ double roll, pitch, yaw, x, y, z;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw beacon's point:\n");
+#endif
+ gamecolor2gl(REG_D[2]);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* get vertex */
+ rc = use_coord("beacon", 0, &x, &y, &z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x, &y, &z);
+ /* transfer point to OpenGL */
+ opengl_render_point(x, y, z, 0.0);
+}
+
+/* coordinates ready for a building (exterior) */
+static void coord_building_exterior(void)
+{
+ int x, y, z;
+
+ x = (int32_t)REG_D[3];
+ y = (int32_t)REG_D[4];
+ z = (int32_t)REG_D[5];
+ store_coord("building exterior", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+/* render polygon of building (exterior) */
+static void poly_building_exterior(void)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw building's polygon:\n");
+#endif
+ uint16_t color;
+ color = m68k_read_memory_8(vertex_address++) << 8;
+ color |= m68k_read_memory_8(vertex_address++);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 16; i++) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ vertex |= 0x100;
+ /* get vertex */
+ rc = use_coord("building exterior", vertex, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 1); /* back face culling */
+}
+
+/* render line of building (exterior) */
+static void line_building_exterior(void)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ double roll, pitch, yaw, x1, y1, z1, x2, y2, z2;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw building's line:\n");
+#endif
+ gamecolor2gl(REG_D[0]);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ vertex = m68k_read_memory_8(vertex_address++);
+ vertex |= 0x100;
+ /* get vertex */
+ rc = use_coord("building line", vertex, &x1, &y1, &z1);
+ if (rc < 0)
+ return;
+ vertex = m68k_read_memory_8(vertex_address++);
+ vertex |= 0x100;
+ /* get vertex */
+ rc = use_coord("building line", vertex, &x2, &y2, &z2);
+ if (rc < 0)
+ return;
+ /* rotate vertices */
+ rotate_coordinate(roll, pitch, yaw, &x1, &y1, &z1);
+ rotate_coordinate(roll, pitch, yaw, &x2, &y2, &z2);
+ /* transfer line to OpenGL */
+ opengl_render_line(x1, y1, z1, x2, y2, z2, 0.0);
+}
+
+static int interior_level12 = 0;
+static int interior_level34 = 0;
+
+/* coordinates ready for a building (interior) */
+static void coord_building_interior(void)
+{
+ int16_t east, north;
+ int32_t height1, height2, height3, height4;
+
+ mercenary_coord_building_interior(&east, &height1, &height2, &height3, &height4, &north);
+ store_interior_coord("interior", REG_A[0], (double)east, (double)height1, (double)height2, (double)height3, (double)height4, (double)north);
+}
+
+/* render polygon of building (interior) */
+static void poly_building_interior1to4(int level)
+{
+ uint16_t color;
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw roof/floor's polygon at level %d:\n", level);
+#endif
+ color = m68k_read_memory_8(REG_A[0]) << 8;
+ color |= m68k_read_memory_8(REG_A[0] + 1);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 4; i++) {
+ vertex = REG_A[(2 + i)];
+ /* get vertex */
+ rc = use_interior_coord("interior", vertex, level, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 1); /* back face culling */
+}
+
+/* render polygon of building (interior) */
+static void poly_building_interior5to6(int level12, int level34)
+{
+ uint16_t color;
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw polygon above/below window/door at level %d/%d:\n", level12, level34);
+#endif
+ color = m68k_read_memory_8(REG_A[0]) << 8;
+ color |= m68k_read_memory_8(REG_A[0] + 1);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 4; i++) {
+ vertex = (i == 0 || i == 3) ? REG_A[2] : REG_A[3];
+ /* get vertex */
+ rc = use_interior_coord("interior", vertex, (i == 0 || i == 1) ? level12 : level34, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 1); /* back face culling */
+}
+
+static void wall_building(void)
{
- object_coord_valid = 0;
+ double roll, pitch, yaw, x[4], y[4], z[4];
+ double bottom1_x, bottom1_y, bottom1_z;
+ double bottom2_x, bottom2_y, bottom2_z;
+ double top1_x, top1_y, top1_z;
+ double top2_x, top2_y, top2_z;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw wall:\n");
+#endif
+ gamecolor2gl(REG_D[3]);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* get bottom coordinate */
+ rc = use_interior_coord("interior", REG_A[1], 1, &bottom1_x, &bottom1_y, &bottom1_z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &bottom1_x, &bottom1_y, &bottom1_z);
+ /* get top coordinate according to bit 12 in D3 */
+ rc = use_interior_coord("interior", REG_A[1], (REG_D[3] & (1 << 12)) ? 3 : 2, &top1_x, &top1_y, &top1_z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &top1_x, &top1_y, &top1_z);
+ /* if wall is not just a strait line */
+ if (REG_A[1] != REG_A[2]) {
+ /* get bottom coordinate */
+ rc = use_interior_coord("interior", REG_A[2], 1, &bottom2_x, &bottom2_y, &bottom2_z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &bottom2_x, &bottom2_y, &bottom2_z);
+ /* get top coordinate according to bit 12 in D3 */
+ rc = use_interior_coord("interior", REG_A[2], (REG_D[3] & (1 << 12)) ? 3 : 2, &top2_x, &top2_y, &top2_z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &top2_x, &top2_y, &top2_z);
+ /* transfer vertex to OpenGL */
+ x[0] = bottom1_x; y[0] = bottom1_y; z[0] = bottom1_z;
+ x[1] = top1_x; y[1] = top1_y; z[1] = top1_z;
+ x[2] = top2_x; y[2] = top2_y; z[2] = top2_z;
+ x[3] = bottom2_x; y[3] = bottom2_y; z[3] = bottom2_z;
+ /* render polygon to OpenGL */
+ opengl_render_polygon_and_line(x, y, z, 4); /* no culling, because walls are always visible! */
+ } else {
+ /* transfer vertex to OpenGL */
+ opengl_render_line(bottom1_x, bottom1_y, bottom1_z, top1_x, top1_y, top1_z, 0.0);
+ }
}
-/* parse object's coordinates, rotate them and store them */
-static void parse_object(void)
+/* coordinates ready for comet tail */
+static void coord_comet(void)
{
-#if 0
-#warning tbd: handling in 540D2
- int16_t r;
+ int32_t x, y, z;
+
+ x = (int32_t)REG_D[3];
+ y = (int32_t)REG_D[4];
+ z = (int32_t)REG_D[5];
+ store_coord("comet tail", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+/* render polygon of comet tail */
+static void poly_comet(void)
+{
+ uint16_t color;
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ int i;
double roll, pitch, yaw;
- uint32_t address;
- int16_t word_x, word_y, word_z;
- double x1, y1, z1, x2, y2, z2, x3, y3, z3, x4, y4, z4;
-
- if (object_coord_valid) {
- fprintf(stderr, "Coodinates are valid, because previous object did not render, please fix!\n");
- return;
- }
-
- /* get observer's tilt, pitch, yaw */
- r = (int16_t)(m68k_read_memory_16(0x530c+0x1E46) & 0x1ff);
- roll = (double)r / 512.0 * 2 * M_PI;
- r = (int16_t)((m68k_read_memory_16(0x530c+0x1E48) + 0x200) & 0x1ff);
- pitch = (double)r / 512.0 * 2 * M_PI;
- r = (int16_t)((m68k_read_memory_16(0x530c+0x1E4a) + 0x200) & 0x1ff);
- yaw = (double)r / 512.0 * 2 * M_PI;
-
- /* get address that points to object vertices */
- address = mercenary_object_vertex_register;
-
- /* parse object, see M3 code at 0x540a6 */
-word_x = (int8_t)0xff;
-printf("testing %x, %d (should be extended to -1 as a word)\n", word_x, word_x);
-word_x = (int8_t)0xf1;
-printf("testing %x, %d (should be extended to -15 as a word)\n", word_x, word_x);
-word_x = (int8_t)0x80;
-printf("check value: %x (should be 0x80)\n", (uint8_t)word_x);
-exit(0);
-tbd: wie werden die koordinaten mit der objektposition translatiert?:
- object_coord_num = 0;
- while(42) {
- word_x = (int8_t)m68k_read_memory_8(address);
- address += 1;
- /* check for 8 bit or 16 bit coordinate using this magic */
- if ((uint8_t)word_x != 0x80) {
- /* we have an 8 bit coordinate */
- word_y = (int8_t)m68k_read_memory_8(address);
- address += 1;
- word_z = (int8_t)m68k_read_memory_8(address);
- address += 1;
+ double inclination, rotation;
+ double x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw comet's polygon:\n");
+#endif
+ color = m68k_read_memory_8(vertex_address++) << 8;
+ color |= m68k_read_memory_8(vertex_address++);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+ if (planet_rotation)
+ mercenary_get_orientation_planet(&inclination, &rotation);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 16; i++) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ /* get vertex */
+ rc = use_coord("comet tail", vertex, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ if (planet_rotation)
+ rotate_coordinate(0.0, inclination, rotation, &x[i], &y[i], &z[i]);
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon_and_line(x, y, z, i); /* no culling, because we render only two (out of four) planes! */
+}
+
+/* coordinates ready for lines of a road / ground surface */
+static void coord_line_road(void)
+{
+ int32_t x, y, z;
+
+ x = REG_D[3];
+ mercenary_get_height(&y);
+ y = -y;
+ z = REG_D[5];
+ store_coord("road", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+/* render line of road */
+static void line_road(void)
+{
+ uint32_t vertex;
+ double roll, pitch, yaw, x1, y1, z1, x2, y2, z2;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw road's line:\n");
+#endif
+
+ gamecolor2gl_index(mercenary_street_color_index());
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ vertex = REG_A[1];
+ /* get vertex */
+ rc = use_coord("road", vertex, &x1, &y1, &z1);
+ if (rc < 0)
+ return;
+ vertex = REG_A[2];
+ /* get vertex */
+ rc = use_coord("road", vertex, &x2, &y2, &z2);
+ if (rc < 0)
+ return;
+ /* rotate vertices */
+ rotate_coordinate(roll, pitch, yaw, &x1, &y1, &z1);
+ rotate_coordinate(roll, pitch, yaw, &x2, &y2, &z2);
+ /* transfer line to OpenGL */
+ opengl_render_line(x1, y1, z1, x2, y2, z2, 0.0);
+}
+
+/* coordinates ready for polygons of a road / ground surface */
+static void coord_poly_road(void)
+{
+ int32_t x, y, z;
+
+// puts("road");
+ x = m68k_read_memory_32(320 + REG_A[0]);
+ x -= REG_A[1];
+ /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA (m3) instead */
+ mercenary_get_height(&y);
+ y = -y;
+ z = m68k_read_memory_32(576 + REG_A[0]);
+ z -= REG_A[3];
+ store_coord("road/place", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+/* render polygon of road */
+static void poly_road()
+{
+ uint16_t color;
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex, vertex_prev, vertex_next;
+ int i, v;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ double x_current, y_current, z_current;
+ double x_prev, y_prev, z_prev;
+ double x_next, y_next, z_next;
+ uint32_t vertices[16];
+ int vertices_num;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw road/place's polygon:\n");
+#endif
+ color = m68k_read_memory_8(vertex_address++) << 8;
+ color |= m68k_read_memory_8(vertex_address++);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+
+ /* count the vertex list, it is zero-terminated */
+ vertices_num = 0;
+ for (i = 0; i < 16; i++) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ vertices[i] = vertex;
+ vertices_num++;
+ }
+
+ /* the vertex list is zero-terminated */
+ i = 0;
+ for (v = 0; v < vertices_num; v++) {
+ vertex = vertices[v];
+ rc = use_coord("road/place", vertex, &x_current, &y_current, &z_current);
+ if (rc < 0)
+ break;
+ /* check for road extension, so we extend the road to the given end point */
+ if (extend_roads && vertex >= 0xf0) {
+ /* previous vertex */
+ vertex_prev = vertices[(v + vertices_num - 1) % vertices_num];
+ rc = use_coord("road/place", vertex_prev, &x_prev, &y_prev, &z_prev);
+ if (rc < 0)
+ break;
+ /* next vertex */
+ vertex_next = vertices[(v + 1) % vertices_num];
+ rc = use_coord("road/place", vertex_next, &x_next, &y_next, &z_next);
+ if (rc < 0)
+ break;
+ /* extend vertices to end point position
+ * change x or z coordinate, whatever is greater
+ */
+ if (fabs(x_prev - x_current) > fabs(z_prev - z_current))
+ x_prev = x_next = x_current;
+ else
+ z_prev = z_next = z_current;
+ /* store vertices */
+ x[i] = x_prev;
+ y[i] = y_prev;
+ z[i] = z_prev;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ if (i++ == 16)
+ break;
+ x[i] = x_next;
+ y[i] = y_next;
+ z[i] = z_next;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ if (i++ == 16)
+ break;
+ continue;
} else {
- /* we have an 16 bit coordinate, make address word align */
- if ((address & 1))
- address++;
- word_x = (int16_t)m68k_read_memory_16(address);
- address += 2;
- /* done if we get this magic */
- if ((uint16_t)word_x == 0x8000)
+ /* no extension, just keep the current point as is */
+ x[i] = x_current;
+ y[i] = y_current;
+ z[i] = z_current;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ if (i++ == 16)
break;
- word_y = (int16_t)m68k_read_memory_16(address);
- address += 2;
- word_z = (int16_t)m68k_read_memory_16(address);
- address += 2;
}
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 0); /* no culling, because polygons lay on the gound and are always visible! */
+}
- /* check if too many coordinates */
- if (object_coord_num == OBJECT_COORD_MAX) {
- fprintf(stderr, "object has too many coordinates, please fix!\n");
- return;
- }
+/* coordinates ready for tags */
+static void coord_tags(void)
+{
+ int32_t x, y, z;
- /* convert to double */
- x1 = (double)word_x;
- y1 = (double)word_y;
- z1 = (double)word_z;
+ x = (int16_t)REG_D[3];
+ x += (int32_t)REG_A[1];
+ y = (int16_t)REG_D[4];
+ y += (int32_t)REG_A[2];
+ z = (int16_t)REG_D[5];
+ z += (int32_t)REG_A[3];
+ store_coord("tags", REG_A[0], (double)x, (double)y, (double)z);
+}
- /* rotate roll (tilt head to the right) */
- x2 = x1 * cos(roll) - y1 * sin(roll);
- y2 = x1 * sin(roll) + y1 * cos(roll);
- z2 = z1;
+/* coordinates ready for large tags */
+static void coord_tags2(void)
+{
+ int32_t x, y, z;
- /* rotate head (pitch down) */
- y3 = y2 * cos(pitch) - z2 * sin(pitch);
- z3 = y2 * sin(pitch) + z2 * cos(pitch);
- x3 = x2;
+ x = (int16_t)REG_D[3];
+ x += 2 * (int32_t)REG_A[1];
+ y = (int16_t)REG_D[4];
+ y += 2 * (int32_t)REG_A[2];
+ z = (int16_t)REG_D[5];
+ z += 2 * (int32_t)REG_A[3];
+ store_coord("large tags", REG_A[0], (double)x, (double)y, (double)z);
+}
- /* rotate yaw (turn right) */
- z4 = z3 * cos(yaw) - x3 * sin(yaw);
- x4 = z3 * sin(yaw) + x3 * cos(yaw);
- y4 = y3;
+/* render line of tag */
+static void line_tags(int last_color)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ double roll, pitch, yaw, x1, y1, z1, x2, y2, z2;
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw tag's line:\n");
+#endif
- /* store vertices as float */
- object_coord_x[object_coord_num] = x4;
- object_coord_y[object_coord_num] = y4;
- object_coord_z[object_coord_num] = z4;
+ if (!last_color) {
+ gamecolor2gl(REG_D[0]);
+ } else {
+ gamecolor2gl_index(mercenary_line_tags_index());
}
- /* we are done, coordinates are valid */
- object_coord_valid = 1;
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ vertex = m68k_read_memory_8(vertex_address++);
+ vertex |= 0x200;
+ /* get vertex */
+ rc = use_coord("tag", vertex, &x1, &y1, &z1);
+ if (rc < 0)
+ return;
+ vertex = m68k_read_memory_8(vertex_address++);
+ vertex |= 0x200;
+ /* get vertex */
+ rc = use_coord("tag", vertex, &x2, &y2, &z2);
+ if (rc < 0)
+ return;
+ /* rotate vertices */
+ rotate_coordinate(roll, pitch, yaw, &x1, &y1, &z1);
+ rotate_coordinate(roll, pitch, yaw, &x2, &y2, &z2);
+ /* transfer line to OpenGL */
+ opengl_render_line(x1, y1, z1, x2, y2, z2, 0.0);
+}
+
+/* render polygon of tags */
+static void poly_tags(int last_color)
+{
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw tag's polygon:\n");
#endif
+ if (!last_color) {
+ gamecolor2gl(REG_D[0]);
+ } else {
+ gamecolor2gl(mercenary_poly_tags_color());
+ }
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+ /* the vertex list is zero-terminated */
+ for (i = 0; i < 16; i++) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ vertex |= 0x200;
+ /* get vertex */
+ rc = use_coord("tag", vertex, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon(x, y, z, i, 1); /* back face culling */
}
-void render_polygons(void)
+/* coordinates ready for planet */
+static void coord_planet(void)
{
-#if 0
-#warning beim polygon auf object_coord_num checken
- if (!object_coord_valid) {
- print failure, if coords not valid!!
+ int32_t x, y, z;
+
+ x = (int32_t)REG_D[3];
+ y = (int32_t)REG_D[4];
+ z = (int32_t)REG_D[5];
+ store_coord("planet", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+#define PLANET_VERTICES 128
+#define PLANET_ELIPSE 1.17
+
+/* render planet */
+static void draw_planet(int comet)
+{
+ uint32_t color = REG_D[0];
+ uint32_t vertex = REG_A[0];
+ uint32_t scale_index;
+ int i;
+ double scale1, scale2, size, angle;
+ double roll, pitch, yaw;
+ double inclination, rotation;
+ double sun_x, sun_y, sun_z, angle_sun;
+ double loc_x, loc_y, loc_z, angle_loc;
+ double x[PLANET_VERTICES], y[PLANET_VERTICES], z[PLANET_VERTICES];
+ int rc;
+
+ /* fixing (not noticable) bug in game: don't render comet twice */
+ if (!comet && vertex == 116)
+ return;
+
+ /* use background color for dark side */
+ color |= (mercenary_background_index() << 16) | 0x80000000; /* shifted by 2 */
+
+ /* make comet black on front side and bright on back */
+ if (comet)
+ color = 0x07770000;
+
+#ifdef DEBUG_VERTEX
+ printf("draw planet/comet/sun: vertex=%d color=%08x\n", vertex, color);
+#endif
+ /* I REVERSED THE F*CKING PLANET SIZE, took me half a day!
+ * the long word 21584(A0) contains two scales
+ * the lower word contains the scale between 4096 .. 8191, this is 1.0 .. 2.0
+ * the upper word defines how much this scale is shifted to the left.
+ */
+ scale_index = mercenary_planet_scale_index();
+ scale1 = (double)(m68k_read_memory_16(scale_index + 2 + vertex) & 0x1fff) / 8192.0;
+ scale2 = (double)(1 << (uint16_t)m68k_read_memory_16(scale_index + vertex));
+ size = scale1 * scale2 / 128.0;
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+ if (planet_rotation)
+ mercenary_get_orientation_planet(&inclination, &rotation);
+
+ /* get location */
+ rc = use_coord("planet(sun)", 0, &sun_x, &sun_y, &sun_z);
+ if (rc < 0)
return;
+ rc = use_coord("planet", vertex, &loc_x, &loc_y, &loc_z);
+ if (rc < 0)
+ return;
+ /* rotate vertex */
+ if (planet_rotation) {
+ rotate_coordinate(0.0, inclination, rotation, &sun_x, &sun_y, &sun_z);
+ rotate_coordinate(0.0, inclination, rotation, &loc_x, &loc_y, &loc_z);
}
+ rotate_coordinate(roll, pitch, yaw, &sun_x, &sun_y, &sun_z);
+ rotate_coordinate(roll, pitch, yaw, &loc_x, &loc_y, &loc_z);
+
+ /* calculate direction of the sun */
+ angle_sun = atan2(sun_x, sun_z);
+ angle_loc = atan2(loc_x, loc_z);
+ angle = angle_sun - angle_loc;
+ if (angle > M_PI)
+ angle -= 2.0 * M_PI;
+ if (angle < -M_PI)
+ angle += 2.0 * M_PI;
+ /* on which side are we (sun is always bright, vertex == 0) */
+ if ((angle < M_PI / 2.0 && angle > -M_PI / 2.0) || vertex == 0) {
+ /* set bright side */
+ gamecolor2gl(color);
+ } else {
+ /* set dark side */
+ gamecolor2gl(color >> 16);
+ }
- render..
+ /* create and render cicle */
+ for (i = 0; i < PLANET_VERTICES; i++) {
+ x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+ y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+ z[i] = loc_z;
+ }
+ opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
+ if (vertex == 0) {
+ /* sun has no crescent */
+ return;
+ }
+ /* on which side are we */
+ if (angle < M_PI / 2.0 && angle > -M_PI / 2.0) {
+ /* set dark side */
+ gamecolor2gl(color >> 16);
+ } else {
+ /* set bright side */
+ gamecolor2gl(color);
+ }
- /* done with rendering, mark coordinates as beeing invalid */
- object_coord_valid = 0;
+ /* create and render crescent */
+ if (angle > M_PI / 2.0 || (angle < 0.0 && angle > -M_PI / 2.0)) {
+ angle = fabs(angle);
+ if (angle > M_PI / 2.0)
+ angle = M_PI - angle;
+ /* to the right */
+ for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
+ x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+ y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+ z[i] = loc_z;
+ }
+ for (; i < PLANET_VERTICES; i++) {
+ 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));
+ y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+ z[i] = loc_z;
+ }
+ } else {
+ angle = fabs(angle);
+ if (angle > M_PI / 2.0)
+ angle = M_PI - angle;
+ /* to the left */
+ for (i = 0; i < PLANET_VERTICES / 2 + 1; i++) {
+ 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));
+ y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+ z[i] = loc_z;
+ }
+ for (; i < PLANET_VERTICES; i++) {
+ x[i] = loc_x + size * sin(2 * M_PI * (double)i / PLANET_VERTICES) * PLANET_ELIPSE;
+ y[i] = loc_y + size * cos(2 * M_PI * (double)i / PLANET_VERTICES);
+ z[i] = loc_z;
+ }
+ }
+ opengl_render_polygon_and_line(x, y, z, PLANET_VERTICES); /* no culling, its a planet! */
+ opengl_render_point(loc_x, loc_y, loc_z, 0.0); /* planet is visible at any distance - at least as a point */
+}
+
+/* draw stars */
+static void draw_stars(int16_t v_offset, int tilt, int above_zenith)
+{
+ int32_t tilt_value;
+ int16_t tilt_offset = 0;
+ int x_offset = 0;
+ uint16_t color[16];
+ uint16_t view_width, yaw;
+ int16_t pitch;
+ uint32_t table, table_start;
+ int16_t x, y;
+ double z;
+ int i;
+
+#ifdef DEBUG_VERTEX
+ printf("draw stars\n");
#endif
+ /* use default fov of 64 to calculate z distance */
+ z = 160.0 / frustum_slope_64;
+
+ view_width = (int)(320.0 / frustum_slope_64 * frustum_slope_fov);
+
+ /* get palette */
+ for (i = 0; i < 16; i++)
+ color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
+
+ /* if we fly over the planet, we have tilt, so we get the calculated tilt value from game */
+ if (tilt)
+ tilt_value = (int32_t)REG_A[4];
+
+ /* table offset is 91, so we substract it and add it back with different FOV, so table begins at later
+ * full turn is 1024, we have default of 64 degrees: 1024 / 360 * 64 = 182
+ * then we half it, so we get to the center via 91
+ */
+ mercenary_get_orientation_raw(&pitch, &yaw);
+
+ if (above_zenith)
+ yaw = 0x200 + yaw;
+ yaw = (yaw + 91 - (int)(91.0 * (frustum_slope_fov / frustum_slope_64))) & 0x3ff;
+ yaw <<= 1;
+ table = mercenary_star_table();
+ table_start = table + m68k_read_memory_16(table);
+ table += m68k_read_memory_16(table + yaw);
+ yaw = ((uint32_t)yaw * 0xe10e) >> 16;
+
+ if (above_zenith)
+ pitch = 0x200 - pitch;
+ pitch = pitch & 0x3ff;
+ pitch -= v_offset;
+ pitch <<= 2;
+ pitch = (pitch * 0x6ccc) >> 16;
+
+ while (1) {
+ x = m68k_read_memory_16(table);
+ if (x >= 1800) {
+ x_offset += 1800;
+ table = table_start;
+ }
+ x = (view_width - 1) - m68k_read_memory_16(table) - x_offset + yaw;
+ table += 2;
+ if (x < 0)
+ break;
+ /* special case where we tilt the view when flying on the planet */
+ if (tilt) {
+ /* use offset as given by game: 160 is half of the screen width
+ * we extend the width to the actual FOV, so it fits
+ */
+ tilt_offset = (int32_t)((x - (int16_t)(160.0 / frustum_slope_64 * frustum_slope_fov)) * tilt_value) >> 16;
+ }
+ y = ((m68k_read_memory_16(table)) & 0x1ff) - pitch + tilt_offset;
+ table += 2;
+ if (above_zenith) {
+ x = (view_width - 1) - x;
+ y = ~y + 136;
+ }
+ /* get color */
+ gamecolor2gl(color[(m68k_read_memory_8(table - 2) & 0x3c) >> 2]);
+ /* render point */
+ opengl_render_point(160.0 / frustum_slope_64 * frustum_slope_fov - (double)x, 68.0 - (double)y, z, 0.0);
+ }
+}
+
+/* draw stars of interstellar flight */
+static void draw_stars_interstellar(void)
+{
+ int i, count;
+ uint32_t table;
+ uint16_t color[16];
+ int16_t x, y;
+ double z;
+
+#ifdef DEBUG_VERTEX
+ printf("draw interstellar stars\n");
+#endif
+ /* use default fov of 64 to calculate z distance */
+ z = 160.0 / frustum_slope_64;
+
+ /* get palette */
+ for (i = 0; i < 16; i++)
+ color[i] = m68k_read_memory_16(mercenary_palette_stars() + (i << 2));
+
+ table = REG_A[0];
+ count = REG_D[5] + 1;
+ for (i = 0; i < count; i++) {
+ table += 12;
+ /* get color */
+ gamecolor2gl(color[(m68k_read_memory_16(table) >> 5) & 0xf]);
+ table += 2;
+ x = m68k_read_memory_16(table);
+ table += 2;
+ y = m68k_read_memory_16(table);
+ table += 2;
+ /* render point */
+ opengl_render_point(160.0 - (double)x, 68.0 - (double)y, z, 0.0);
+ }
+
+}
+
+/* draw sun of interstellar flight (center dot) */
+static void draw_sun_interstellar(void)
+{
+#ifdef DEBUG_VERTEX
+ printf("draw interstellar sun\n");
+#endif
+
+ /* white */
+ gamecolor2gl(0x777);
+ /* render point */
+ opengl_render_point(0.0, 0.0, 100.0, 0.0);
+}
+
+/* coordinates ready for polygons of islands */
+static void coord_islands(void)
+{
+ int32_t x, y, z;
+
+ x = ((int16_t)m68k_read_memory_16(REG_A[4] - 2) * 65536);
+ x += (int32_t)REG_A[1];
+ /* the A2 is already converted to game's coordinate, so we use the memory location DS_0+0x1DBA instead */
+ mercenary_get_height(&y);
+ y = -y;
+ z = ((int16_t)m68k_read_memory_16(REG_A[4]) * 65536);
+ z += (int32_t)REG_A[3];
+ store_coord("island", REG_A[0], (double)x, (double)y, (double)z);
+}
+
+/* render polygon of island */
+static void poly_island()
+{
+ uint16_t color;
+ uint32_t vertex_address = REG_A[0];
+ uint32_t vertex;
+ int i;
+ double roll, pitch, yaw, x[16], y[16], z[16];
+ int rc;
+
+#ifdef DEBUG_VERTEX
+ printf("draw island:\n");
+#endif
+ color = m68k_read_memory_8(vertex_address++) << 8;
+ color |= m68k_read_memory_8(vertex_address++);
+ gamecolor2gl(color);
+
+ /* get orientation */
+ mercenary_get_orientation(&roll, &pitch, &yaw);
+
+
+ /* the vertex list is zero-terminated */
+ i = 0;
+ while (1) {
+ vertex = m68k_read_memory_8(vertex_address++);
+ if (vertex == 0 && i)
+ break;
+ /* skip mysterious points when rendering island */
+ if (vertex >= 0xf0)
+ continue;
+ rc = use_coord("island", vertex, &x[i], &y[i], &z[i]);
+ if (rc < 0)
+ break;
+ /* rotate vertex */
+ rotate_coordinate(roll, pitch, yaw, &x[i], &y[i], &z[i]);
+ if (i++ == 16)
+ break;
+ }
+ /* render polygon to OpenGL */
+ opengl_render_polygon_and_line(x, y, z, i); /* no culling, because polygons lay on the gound and are always visible! */
+}
+
+/* draw sights */
+static void draw_sights(void)
+{
+ double x[4], y[4], z[4];
+
+ /* use default fov of 64 to calculate z distance */
+ z[0] = z[1] = z[2] = z[3] = 160.0 / frustum_slope_64;
+
+ /* white */
+ gamecolor2gl(0x777);
+
+ y[0] = y[3] = -1.0;
+ y[1] = y[2] = 1.0;
+ x[0] = x[1] = -16.0;
+ x[2] = x[3] = -8.0;
+ opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
+ x[0] = x[1] = 8.0;
+ x[2] = x[3] = 16.0;
+ opengl_render_polygon(x, y, z, 4, 0); /* no culling, because sights are always visible! */
}
/* stop event from CPU received */
void render_improved_event(int event)
{
switch (event) {
- case STOP_AT_PARSE_OBJECT:
- parse_object();
+ case STOP_AT_CLEAR_SCREEN1:
+ clear_screen(16); /* color 16 is raster split */
+ break;
+ case STOP_AT_CLEAR_SCREEN2:
+ clear_screen(15);
+ break;
+ case STOP_AT_CLEAR_SCREEN3:
+ clear_screen(-1); /* no ground (in universe) */
+ break;
+ case STOP_AT_DRAW_GROUND:
+ draw_ground();
+ break;
+ case STOP_AT_COORD_OBJECT:
+ coord_object();
+ break;
+ case STOP_AT_POLY_OBJECT_M3:
+ poly_object(3);
+ break;
+ case STOP_AT_POLY_OBJECT_M2:
+ poly_object(2);
+ break;
+ case STOP_AT_LINE_OBJECT:
+ line_object();
+ break;
+ case STOP_AT_COORD_BEACON:
+ coord_beacon();
+ break;
+ case STOP_AT_POINT_BEACON:
+ point_beacon();
break;
- case STOP_AT_RENDER_POLYGONS:
- render_polygons();
+ case STOP_AT_COORD_BUILDING_EXTERIOR:
+ coord_building_exterior();
+ break;
+ case STOP_AT_POLY_BUILDING_EXTERIOR:
+ poly_building_exterior();
+ break;
+ case STOP_AT_LINE_BUILDING_EXTERIOR:
+ line_building_exterior();
+ break;
+ case STOP_AT_COORD_BUILDING_INTERIOR:
+ coord_building_interior();
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR1:
+ /* floor */
+ interior_level12 = 1;
+ interior_level34 = 1;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR2:
+ /* ceiling */
+ interior_level12 = 2;
+ interior_level34 = 2;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR3:
+ /* door/window top */
+ interior_level12 = 3;
+ interior_level34 = 3;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR4:
+ /* window bottom */
+ interior_level12 = 4;
+ interior_level34 = 4;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR5:
+ /* door/window top */
+ interior_level12 = 2;
+ interior_level34 = 3;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR6:
+ /* window bottom */
+ interior_level12 = 1;
+ interior_level34 = 4;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR1to4:
+ /* before we come here, we must already passed the break points above, so we know the level to be rendered */
+ if (interior_level12 == 0) {
+ print_error("Interior level is not set, please fix!\n");
+ break;
+ }
+ poly_building_interior1to4(interior_level12);
+ interior_level12 = 0;
+ break;
+ case STOP_AT_POLY_BUILDING_INTERIOR5to6:
+ /* before we come here, we must already passed the break points above, so we know the level to be rendered */
+ if (interior_level12 == 0) {
+ print_error("Interior level is not set, please fix!\n");
+ break;
+ }
+ poly_building_interior5to6(interior_level12, interior_level34);
+ interior_level12 = 0;
+ break;
+ case STOP_AT_WALL_BUILDING:
+ wall_building();
+ break;
+ case STOP_AT_COORD_COMET:
+ coord_comet();
+ break;
+ case STOP_AT_MATRIX_COMET:
+ case STOP_AT_MATRIX_PLANET:
+ /* track the rotation matrix
+ * if we have 0x42c44 matrix, we must add extra rotation to planet.
+ * the rotation will change the view from the planet's surface */
+ if (REG_A[4] == 0x42c44) /* same with M2 and M3 */
+ planet_rotation = 1;
+ else
+ planet_rotation = 0;
+ break;
+ case STOP_AT_POLY_COMET:
+ poly_comet();
+ break;
+ case STOP_AT_COORD_LINE_ROADS:
+ coord_line_road();
+ break;
+ case STOP_AT_LINE_ROADS:
+ line_road();
+ break;
+ case STOP_AT_COORD_POLY_ROADS:
+ coord_poly_road();
+ break;
+ case STOP_AT_LINE_ROADS_CENTER:
+ /* we don't need to render center lines of roads, because there are polygons already
+ * it does not make sense, since OpenGL has much higher resolution.
+ */
+ break;
+ case STOP_AT_POLY_ROADS:
+ poly_road();
+ break;
+ case STOP_AT_COORD_TAGS:
+ coord_tags();
+ break;
+ case STOP_AT_COORD_TAGS2:
+ coord_tags2();
+ break;
+ case STOP_AT_LINE_TAGS1:
+ line_tags(0);
+ break;
+ case STOP_AT_LINE_TAGS2:
+ line_tags(1);
+ break;
+ case STOP_AT_POLY_TAGS1:
+ poly_tags(0);
+ break;
+ case STOP_AT_POLY_TAGS2:
+ poly_tags(1);
+ break;
+ case STOP_AT_COORD_PLANET:
+ coord_planet();
+ break;
+ case STOP_AT_DRAW_PLANET:
+ draw_planet(0);
+ break;
+ case STOP_AT_DRAW_COMET:
+ draw_planet(1);
+ break;
+ case STOP_AT_DRAW_STARS_SPACE:
+ /* render stars with vertical offset 0x1c0, no tilt, not above zenith */
+ draw_stars(0x1c0, 0, 0);
+ break;
+ case STOP_AT_DRAW_STARS_GROUND:
+ /* render stars with vertical offset 0x128, no tilt, not above zenith */
+ draw_stars(0x128, 0, 0); /* yet it's hex 128! */
+ break;
+ case STOP_AT_DRAW_STARS_FLYING:
+ /* render stars with vertical offset 0x128, with tilt, not above zenith */
+ draw_stars(0x128, 1, 0); /* yet it's hex 128! */
+ break;
+ case STOP_AT_DRAW_STARS_FLYING2:
+ /* render stars with vertical offset 0x128, with tilt, and above zenith */
+ draw_stars(0x128, 1, 1); /* yet it's hex 128! */
+ break;
+ case STOP_AT_DRAW_STARS_INTERSTELLAR:
+ draw_stars_interstellar();
+ break;
+ case STOP_AT_DRAW_SUN_INTERSTELLAR:
+ draw_sun_interstellar();
+ break;
+ case STOP_AT_COORD_ISLANDS:
+ coord_islands();
+ break;
+ case STOP_AT_POLY_ISLANDS:
+ poly_island();
+ break;
+ case STOP_AT_LINE_ISLANDS:
+ /* this is not used, as i had noticed so far */
+ puts("line island");
+ break;
+ case STOP_AT_DRAW_SIGHTS:
+ draw_sights();
+ break;
+ case STOP_AT_POLY_UKN2:
+ puts("poly ukn2");
+ break;
+ case STOP_AT_PLANET_UKN1:
+ puts("planet ukn1");
+ break;
+ case STOP_AT_PLANET_UKN2:
+ puts("planet ukn2");
break;
}
}
+