A switch (command line and keyboard) can be used to toggle rendering.
A special swith (-o) can be used to render both legacy and improved
view top/bottom. This way it is easier to debug the expected result.
+Prerequisites:
+
+Install autoconf and libtool, so you can generate the configure scripts.
+Install SDL2 and GLEW, because this software requires SDL and OpenGL.
+
To build:
$ autoreconf -if
$ make
$ make install
+Problems:
+
+$ libtoolize
+$ automake --add-missing
+./configure: line 15095: syntax error near unexpected token `sdl2,'
+./configure: line 15095: ` PKG_CHECK_MODULES(sdl2, sdl2 >= 2.0, with_sdl2=yes, with_sdl2=no)'
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
+#include <math.h>
#include <errno.h>
#include "print.h"
#include "opengl.h"
#include <GL/glew.h>
-static uint8_t *text_rgb = NULL;
-static GLuint text_name;
+static uint8_t *legacy_rgb = NULL;
+static uint8_t *benson_rgb = NULL;
+static GLuint legacy_name;
+static GLuint benson_name;
static int screen_width, screen_height;
static int image_width, image_height;
static int texture_size;
/* generate texture */
for (texture_size = 1; texture_size <= image_width || texture_size <= image_height; texture_size *= 2)
;
- text_rgb = calloc(texture_size * texture_size * 10, 3);
- if (!text_rgb) {
+
+ legacy_rgb = calloc(texture_size * texture_size, 3);
+ if (!legacy_rgb) {
print_error("Failed to allocate texture\n");
rc = -ENOMEM;
goto error;
}
- glClearColor(0.0, 0.0, 0.0, 1.0);
glShadeModel(GL_FLAT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
- glGenTextures(1, &text_name);
- glBindTexture(GL_TEXTURE_2D, text_name);
+ glGenTextures(1, &legacy_name);
+ glBindTexture(GL_TEXTURE_2D, legacy_name);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, legacy_rgb);
+
+ benson_rgb = calloc(texture_size * texture_size, 3);
+ if (!benson_rgb) {
+ print_error("Failed to allocate texture\n");
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ glShadeModel(GL_FLAT);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* bytes */
+ glGenTextures(1, &benson_name);
+ glBindTexture(GL_TEXTURE_2D, benson_name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, text_rgb);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture_size, texture_size, 0, GL_RGB, GL_UNSIGNED_BYTE, benson_rgb);
return 0;
error:
+ exit_opengl();
return rc;
}
/* set clip planes so that the image portion of the image texture is centered and pixels are rectengular */
void resize_opengl(int _screen_width, int _screen_height)
{
- double width_border = 1.0;
- double height_border = 1.0;
-
- if (_screen_width < 1 || _screen_height < 1)
- return;
screen_width = _screen_width;
screen_height = _screen_height;
+}
+
- if (image_width * screen_height > screen_width * image_height) {
- height_border = (double)(image_width * screen_height) / (double)(screen_width * image_height);
+void opengl_clear(void)
+{
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+/* set viewport for legacy image */
+void opengl_viewport_legacy(int split)
+{
+ int view_x, view_y;
+ int view_width, view_height;
+ int new_width, new_height;
+
+ if (!split) {
+ view_x = 0;
+ view_y = 0;
+ view_width = screen_width;
+ view_height = screen_height;
+ } else {
+ view_x = 0;
+ view_y = screen_height / 2;
+ view_width = screen_width;
+ view_height = screen_height / 2;
}
- if (image_width * screen_height < screen_width * image_height) {
- width_border = (double)(screen_width * image_height / (double)(image_width * screen_height));
+
+ /* avoid division by zero, if one dimension is too small */
+ if (view_width < 1 || view_height < 1)
+ return;
+
+ /* calculate a viewport that has apect of image_width:image_height */
+ if (view_height * image_width > view_width * image_height) {
+ new_height = view_width * image_height / image_width;
+ view_y = view_y + view_height / 2 - new_height / 2;
+ view_height = new_height;
+ } else if (view_height * image_width < view_width * image_height) {
+ new_width = view_height * image_width / image_height;
+ view_x = view_x + view_width / 2 - new_width / 2;
+ view_width = new_width;
}
+ /* avoid views that are too small */
+ if (view_width < 1 || view_height < 1)
+ return;
+
/* viewport and projection matrix */
- glViewport(0, 0, (GLsizei)screen_width, (GLsizei)screen_height);
+ glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
-
- double width = (double)image_width / (double)texture_size;
- double height = (double)image_height / (double)texture_size;
- glOrtho(
- -width * (width_border - 1.0) / 2,
- width / 2 + width * width_border / 2,
- height / 2 + height * height_border / 2,
- -height * (height_border - 1.0) / 2,
- -1.0, 1.0);
+ glOrtho(0.0, 1.0, 1.0, 0.0, -1.0, 1.0);
glMatrixMode(GL_MODELVIEW);
}
-/* render image texture */
-void render_opengl(uint8_t *rgb, int filter)
+/* render legacy image texture */
+void opengl_render_legacy(uint8_t *rgb, int filter)
{
- glClear(GL_COLOR_BUFFER_BIT);
+ double width = (double)image_width / (double)texture_size;
+ double height = (double)image_height / (double)texture_size;
+
glEnable(GL_TEXTURE_2D);
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
- glBindTexture(GL_TEXTURE_2D, text_name);
+ glBindTexture(GL_TEXTURE_2D, legacy_name);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, image_width, image_height, GL_RGB, GL_UNSIGNED_BYTE, rgb);
glBegin(GL_QUADS);
glTexCoord2f(0.0, 0.0);
glVertex3f(0.0, 0.0, 0.0);
- glTexCoord2f(1.0, 0.0);
+ glTexCoord2f(width, 0.0);
glVertex3f(1.0, 0.0, 0.0);
- glTexCoord2f(1.0, 1.0);
+ glTexCoord2f(width, height);
glVertex3f(1.0, 1.0, 0.0);
- glTexCoord2f(0.0, 1.0);
+ glTexCoord2f(0.0, height);
glVertex3f(0.0, 1.0, 0.0);
glEnd();
glDisable(GL_TEXTURE_2D);
}
+static double fov = 64.0;
+
+/* set viewport for improved rendering */
+void opengl_viewport_improved(int split, int benson_at_line)
+{
+ int view_x, view_y;
+ int view_width, view_height;
+ int new_width, new_height;
+
+ /* center view, or put it in the top half of the window */
+ if (!split) {
+ view_x = 0;
+ view_y = 0;
+ view_width = screen_width;
+ view_height = screen_height;
+ } else {
+ view_x = 0;
+ view_y = 0;
+ view_width = screen_width;
+ view_height = screen_height / 2;
+ }
+
+ /* avoid division by zero, if one dimension is too small */
+ if (view_width < 1 || view_height < 1)
+ return;
+
+ /* calculate a viewport that has apect of image_width:image_height */
+ if (view_height * image_width > view_width * image_height) {
+ new_height = view_width * image_height / image_width;
+ view_y = view_y + view_height / 2 - new_height / 2;
+ view_height = new_height;
+ } else if (view_height * image_width < view_width * image_height) {
+ new_width = view_height * image_width / image_height;
+ view_x = view_x + view_width / 2 - new_width / 2;
+ view_width = new_width;
+ }
+
+ /* avoid views that are too small */
+ if (view_width < 1 || view_height < 1)
+ return;
+
+ /* viewport and projection matrix */
+ glViewport((GLsizei)view_x, (GLsizei)view_y, (GLsizei)view_width, (GLsizei)view_height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ /* calculate field-of-view */
+ double slope = tan(fov / 360 * M_PI);
+ /* make frustum to center the view in the game view above benson */
+ double left = -slope;
+ double right = slope;
+ double top = slope * (double)benson_at_line / (double)image_width;
+ double bottom = -slope * ((double)image_height * 2.0 - (double)benson_at_line) / (double)image_width;
+ glFrustum(left, right, bottom, top, 1.0, 5000000000.0);
+ glMatrixMode(GL_MODELVIEW);
+
+#if 1
+ /* test rectangle */
+ glColor3d(0.5, 0.4, 0.4);
+ glBegin(GL_QUADS);
+ glVertex3f(-1.0, -1.0, -1.0);
+ glVertex3f(1.0, -1.0, -1.0);
+ glVertex3f(1.0, 1.0, -1.0);
+ glVertex3f(-1.0, 1.0, -1.0);
+ glEnd();
+#endif
+}
+
+/* render only benson */
+void opengl_render_benson(uint8_t *rgb, int filter, int benson_at_line)
+{
+ double texture_left = 0.0;
+ double texture_right = (double)image_width / (double)texture_size;
+ double texture_top = (double)benson_at_line / (double)texture_size;
+ double texture_bottom = (double)image_height / (double)texture_size;
+ double benson_top = -(double)benson_at_line / (double)image_width;
+ double benson_bottom = -((double)image_height * 2.0 - (double)benson_at_line) / (double)image_width;
+
+ /* calculate field-of-view */
+ double slope = tan(fov / 360 * M_PI);
+
+ /* render benson */
+ rgb += image_width * benson_at_line * 3;
+ glEnable(GL_TEXTURE_2D);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL); /* no modulation with color */
+ glBindTexture(GL_TEXTURE_2D, benson_name);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (filter) ? GL_LINEAR : GL_NEAREST);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, benson_at_line, image_width, image_height - benson_at_line, GL_RGB, GL_UNSIGNED_BYTE, rgb);
+ glBegin(GL_QUADS);
+ glTexCoord2f(texture_left, texture_bottom);
+ glVertex3f(-2.0, 2.0 * benson_bottom, -2.0 / slope);
+ glTexCoord2f(texture_right, texture_bottom);
+ glVertex3f(2.0, 2.0 * benson_bottom, -2.0 / slope);
+ glTexCoord2f(texture_right, texture_top);
+ glVertex3f(2.0, 2.0 * benson_top, -2.0 / slope);
+ glTexCoord2f(texture_left, texture_top);
+ glVertex3f(-2.0, 2.0 * benson_top, -2.0 / slope);
+ glEnd();
+ glDisable(GL_TEXTURE_2D);
+}
+
/* free image texture */
void exit_opengl(void)
{
- if (text_rgb) {
- free(text_rgb);
- text_rgb = NULL;
+ if (legacy_rgb) {
+ free(legacy_rgb);
+ legacy_rgb = NULL;
+ }
+ if (benson_rgb) {
+ free(benson_rgb);
+ benson_rgb = NULL;
}
}
int init_opengl(int _image_width, int _image_height);
void resize_opengl(int _screen_width, int _screen_height);
-void render_opengl(uint8_t *rgb, int filter);
+void opengl_clear(void);
+void opengl_viewport_legacy(int top);
+void opengl_render_legacy(uint8_t *rgb, int filter);
+void opengl_viewport_improved(int bottom, int benson_at_line);
+void opengl_render_benson(uint8_t *rgb, int filter, int benson_at_line);
void exit_opengl(void);
noinst_LIBRARIES = libmain.a
libmain_a_SOURCES = \
+ render.c \
main.c
bin_PROGRAMS = mercenary3 mercenary2
#include "../libkeyboard/keyboard.h"
#include "../libdisk/disk.h"
#include "mercenary.h"
+#include "render.h"
static int config_amiga_speed = 1;
static const char *config_gamesave_dir = ".mercenary";
static int config_video_filter = 1;
static int config_audio_filter = 1;
+static int config_render = 0;
+static int config_debug_opengl = 0;
#define CPU_SPEED 7093790.0;
#define MEMORY_SIZE 0x80000
static uint8_t *memory = NULL;
static uint8_t *image = NULL;
-#define SCREEN_WIDTH (320*3)
-#define SCREEN_HEIGHT (200*3)
+#define SCREEN_WIDTH 320
+#define SCREEN_HEIGHT 200
#define IMAGE_WIDTH 320
#define IMAGE_HEIGHT 200
#define BENSON_AT_LINE 136
static int sound_buffer_writep; /* write pointer at buffer */
static int sound_buffer_readp; /* read pointer at buffer */
static int double_size = 1; /* render in double size, so each pixle is 2*2 pixles wide */
+static int render_legacy = 0; /* render original amiga screen, if set */
+static int render_improved = 0; /* render improved image, if set */
+static int render_debug = 0; /* render both, amiga screen and improved image, if set */
static const char *home_dir;
print_info(" Set video filter.\n");
print_info(" -a --audio-filter on | off\n");
print_info(" Set audio filter.\n");
+ print_info(" -r --render original | opegl\n");
+ print_info(" Set speed of rendering to original Amiga or full speed.\n");
+ print_info(" -o --debug-opengl\n");
+ print_info(" Use split screen to debug opengl rendering vs. amiga rendering.\n");
return -1;
} else
if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--amiga-speed")) {
config_audio_filter = 0;
else
goto illegal_parameter;
+ } else
+ if (!strcmp(argv[i], "-r") || !strcmp(argv[i], "--render")) {
+ i++;
+ if (argc == i)
+ goto missing_parameter;
+ if (!strcmp(argv[i], "original"))
+ config_render = 0;
+ else
+ if (!strcmp(argv[i], "opengl"))
+ config_render = 1;
+ else
+ goto illegal_parameter;
+ } else
+ if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--debug-opengl")) {
+ config_debug_opengl = 1;
} else {
print_info("Illegal option '%s', use '--help'!\n", argv[i]);
return -1;
static void special_event(int event)
{
+ if (render_improved)
+ render_improved_event(event);
}
static void main_loop(void)
/* render result on window */
while (!quit) {
+ /* handle SDL events */
+ rc = event_sdl();
+ if (rc)
+ break;
+
+ /* clear screen */
+ opengl_clear();
+
+ /* initialize rendering */
+ render_debug = config_debug_opengl;
+ render_legacy = (!config_render) || render_debug;
+ render_improved = config_render || render_debug;
+ /* start rendering for improved graphics */
+ if (render_improved)
+ opengl_viewport_improved(render_debug, (double_size) ? BENSON_AT_LINE * 2 : BENSON_AT_LINE);
+
/* STEP 1: let the CPU render/process the game */
/* don't render if we still delay */
if (!render_delay) {
render_delay = (double)cycle_count / CPU_SPEED;
}
- /* STEP 2: render image in memory via OpenGL */
+ /* STEP 2: transfer legacy image in memory to OpenGL texture */
if (had_first_irq) {
/* render game view without benson
* because benson is not updated before VBL IRQ, we don't want old image from double buffer
*/
- emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, 0, BENSON_AT_LINE, double_size);
+ if (render_legacy)
+ emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, 0, BENSON_AT_LINE, double_size);
+ }
+ /* render benson on improved rendering, if enabled */
+ if (render_improved)
+ opengl_render_benson(image, config_video_filter, (double_size) ? BENSON_AT_LINE * 2 : BENSON_AT_LINE);
+ /* setup viewport for legacy image and render image, if enabled */
+ if (render_legacy) {
+ opengl_viewport_legacy(render_debug);
+ opengl_render_legacy(image, config_video_filter);
}
- rc = event_sdl();
- if (rc)
- break;
- render_opengl(image, config_video_filter);
swap_sdl();
/* STEP 3: execute interrupt at rate of 50Hz, render sound */
print_info("amiga speed: %s\n", (config_amiga_speed) ? "original" : "full");
}
break;
+ case SDLK_r:
+ if (down && ctrl) {
+ config_render ^= 1;
+ printf("render: %s\n", (config_render) ? "opengl" : "original");
+ }
+ break;
case SDLK_c:
if (down)
quit = 1;
mercenary_patch();
/* init SDL and OpenGL */
- rc = init_sdl(argv[0], SCREEN_WIDTH, SCREEN_HEIGHT, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, audio_sdl);
+ rc = init_sdl(argv[0], (config_debug_opengl) ? SCREEN_WIDTH * 2 : SCREEN_WIDTH * 3, (config_debug_opengl) ? SCREEN_HEIGHT * 4 : SCREEN_HEIGHT * 3, SOUND_SAMPLERATE, sdl_sound_chunk, keyboard_sdl, audio_sdl);
if (rc < 0)
goto done;
rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
if (rc < 0)
goto done;
- resize_opengl(SCREEN_WIDTH, SCREEN_HEIGHT);
+ resize_opengl((config_debug_opengl) ? SCREEN_WIDTH * 2 : SCREEN_WIDTH * 3, (config_debug_opengl) ? SCREEN_HEIGHT * 4 : SCREEN_HEIGHT * 3);
/* init audio filter */
sound_init_filter(SOUND_SAMPLERATE);
print_info("Press CTRL + s to toggle rendering speed.\n");
print_info("Press CTRL + v to toggle video filter.\n");
print_info("Press CTRL + a to toggle audio filter.\n");
+ print_info("Press CTRL + r to toggle rendering with opengl or orignal code.\n");
print_info("Press CTRL + c to exit game.\n\n");
print_info("Use '--help' as command line option for configuration settings.\n\n");
#define STOP_AT_END 0
#define STOP_AT_WAIT_VBL 1
+#define STOP_AT_PARSE_OBJECT 2
+#define STOP_AT_RENDER_POLYGONS 3
extern const struct cpu_stop mercenary_stop_at[];
void mercenary_load(void);
/* interrupt CPU execution at special break points and tell emulation what to do */
const struct cpu_stop mercenary_stop_at[] = {
- { 0x5a826, STOP_AT_WAIT_VBL }, /* done with rendering, waiting for VBL */
- { 0x55d8c, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key before showing menu line on benson */
- { 0x56398, STOP_AT_WAIT_VBL }, /* waiting for menu command */
- { 0x55d94, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key while showing menu line on benson */
- { 0x563a6, STOP_AT_WAIT_VBL }, /* after pressing 'RETURN' while game waits for other key to resume */
- { 0x52946, STOP_AT_WAIT_VBL }, /* after dying, waiting for VBL to fade out palette */
- { 0x0, STOP_AT_END }, /* end */
+ { 0x5a826, STOP_AT_WAIT_VBL }, /* done with rendering, waiting for VBL */
+ { 0x55d8c, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key before showing menu line on benson */
+ { 0x56398, STOP_AT_WAIT_VBL }, /* waiting for menu command */
+ { 0x55d94, STOP_AT_WAIT_VBL }, /* after pressing 'HELP' key while showing menu line on benson */
+ { 0x563a6, STOP_AT_WAIT_VBL }, /* after pressing 'RETURN' while game waits for other key to resume */
+ { 0x52946, STOP_AT_WAIT_VBL }, /* after dying, waiting for VBL to fade out palette */
+ { 0x5408E, STOP_AT_PARSE_OBJECT }, /* an object is about to be rendered, process vertex data */
+ { 0x0, STOP_AT_END }, /* end */
};
extern const uint32_t mercenary3_hex[];
--- /dev/null
+/* render routines that replaces the game rendering with modern rendering
+ *
+ * (C) 2018 by Andreas Eversberg <jolly@eversberg.eu>
+ * All Rights Reserved
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <math.h>
+#include "../libcpu/m68k.h"
+#include "../libcpu/execute.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];
+
+/* rendering starts, initialize variables */
+void render_start(void)
+{
+ object_coord_valid = 0;
+}
+
+/* parse object's coordinates, rotate them and store them */
+static void parse_object(void)
+{
+#if 0
+#warning tbd: handling in 540D2
+ int16_t r;
+ 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;
+ } 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)
+ break;
+ word_y = (int16_t)m68k_read_memory_16(address);
+ address += 2;
+ word_z = (int16_t)m68k_read_memory_16(address);
+ address += 2;
+ }
+
+ /* check if too many coordinates */
+ if (object_coord_num == OBJECT_COORD_MAX) {
+ fprintf(stderr, "object has too many coordinates, please fix!\n");
+ return;
+ }
+
+ /* convert to double */
+ x1 = (double)word_x;
+ y1 = (double)word_y;
+ z1 = (double)word_z;
+
+ /* rotate roll (tilt head to the right) */
+ x2 = x1 * cos(roll) - y1 * sin(roll);
+ y2 = x1 * sin(roll) + y1 * cos(roll);
+ z2 = z1;
+
+ /* rotate head (pitch down) */
+ y3 = y2 * cos(pitch) - z2 * sin(pitch);
+ z3 = y2 * sin(pitch) + z2 * cos(pitch);
+ x3 = x2;
+
+ /* rotate yaw (turn right) */
+ z4 = z3 * cos(yaw) - x3 * sin(yaw);
+ x4 = z3 * sin(yaw) + x3 * cos(yaw);
+ y4 = y3;
+
+ /* 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;
+ }
+
+ /* we are done, coordinates are valid */
+ object_coord_valid = 1;
+#endif
+}
+
+void render_polygons(void)
+{
+#if 0
+#warning beim polygon auf object_coord_num checken
+ if (!object_coord_valid) {
+ print failure, if coords not valid!!
+ return;
+ }
+
+
+ render..
+
+
+
+ /* done with rendering, mark coordinates as beeing invalid */
+ object_coord_valid = 0;
+#endif
+}
+
+/* stop event from CPU received */
+void render_improved_event(int event)
+{
+ switch (event) {
+ case STOP_AT_PARSE_OBJECT:
+ parse_object();
+ break;
+ case STOP_AT_RENDER_POLYGONS:
+ render_polygons();
+ break;
+ }
+}
--- /dev/null
+
+void render_start(void);
+void render_improved_event(int event);
+