Render game graphics using OpenGL
[mercenary-reloaded.git] / src / mercenary / main.c
index f6a640e..d762ef4 100644 (file)
 #include "mercenary.h"
 #include "render.h"
 
+#define FOV_MIN                10.0
+#define FOV_NOVAGEN    64.0
+#define FOV_JOLLY      80.0
+#define FOV_MAX                170.0
+
+static int config_ctrl_c = 0;
 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_skip_intro = 0;
+static int config_multisampling = 16;
+static double config_fov = FOV_NOVAGEN;
+static double config_benson_size = 1.0;
+static int config_debug_transparent = 0;
 static int config_debug_opengl = 0;
+/* render improvements */
+static int config_improve_extend_roads = 0;    /* set to 1 to extend roads */
 
 #define CPU_SPEED      7093790.0;
 
@@ -77,10 +89,11 @@ static stereo_t *sound_buffer = NULL; /* sound buffer memory */
 static int sound_buffer_size; /* buffer sample size */
 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 double_pixel_size = 1; /* render in double size, so each pixle is 2*2 pixles wide */
+static double benson_size; /* render size of benson */
 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 int debug_opengl = 0; /* render both, amiga screen and  improved image, if set */
 
 static const char *home_dir;
 
@@ -101,11 +114,21 @@ int parse_args(int argc, char *argv[])
                        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(" -b --benson normal | half\n");
+                       print_info("        Size of 'Benson' (control panel).\n");
+                       print_info(" -m --multisampling <samples>\n");
+                       print_info("        Use multisampling (default = %d) to render the scene.\n", config_multisampling);
+                       print_info(" -f --fov <%.0f..%.0f..%.0f>\n", FOV_MIN, FOV_NOVAGEN, FOV_MAX);
+                       print_info("        Set field-of-view. Default is %.0f.\n", FOV_NOVAGEN);
                        print_info(" -i --skip-intro\n");
                        print_info("        Skip intro sequence approaching to Eris space port.\n");
                        print_info("Debug options:\n");
                        print_info(" -o --debug-opengl\n");
-                       print_info("        Use split screen to debug opengl rendering vs. amiga rendering.\n");
+                       print_info("        Use split screen to display both Amiga and OpenGL rendering.\n");
+                       print_info("    --debug-transparent\n");
+                       print_info("        Draw all things half transparent.\n");
+                       print_info("    --ctrl-c\n");
+                       print_info("        Use CTRL+C to exit game (used for development)\n");
                        return -1;
                } else
                if (!strcmp(argv[i], "-s") || !strcmp(argv[i], "--amiga-speed")) {
@@ -162,11 +185,45 @@ illegal_parameter:
                        else
                                goto illegal_parameter;
                } else
+               if (!strcmp(argv[i], "-b") || !strcmp(argv[i], "--benson")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       if (!strcmp(argv[i], "normal"))
+                               config_benson_size = 1.0;
+                       else
+                       if (!strcmp(argv[i], "half")) {
+                               config_benson_size = 0.5;
+                               if (config_fov == FOV_NOVAGEN)
+                                       config_fov = FOV_JOLLY;
+                       } else
+                               goto illegal_parameter;
+               } else
+               if (!strcmp(argv[i], "-m") || !strcmp(argv[i], "--multisampling")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       config_multisampling = atoi(argv[i]);
+               } else
+               if (!strcmp(argv[i], "-f") || !strcmp(argv[i], "--fov")) {
+                       i++;
+                       if (argc == i)
+                               goto missing_parameter;
+                       config_fov = atof(argv[i]);
+                       if (config_fov < 1.0 || config_fov > 179.0)
+                               goto illegal_parameter;
+               } else
                if (!strcmp(argv[i], "-i") || !strcmp(argv[i], "--skip-intro")) {
                        config_skip_intro = 1;
                } else
                if (!strcmp(argv[i], "-o") || !strcmp(argv[i], "--debug-opengl")) {
                        config_debug_opengl = 1;
+               } else
+               if (!strcmp(argv[i], "--debug-transparent")) {
+                       config_debug_transparent = 1;
+               } else
+               if (!strcmp(argv[i], "--ctrl-c")) {
+                       config_ctrl_c = 1;
                } else {
                        print_info("Illegal option '%s', use '--help'!\n", argv[i]);
                        return -1;
@@ -207,16 +264,21 @@ static void main_loop(void)
                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 */
+               debug_opengl = config_debug_opengl;
+               benson_size = config_benson_size;
+               render_legacy = (!config_render) || debug_opengl;
+               render_improved = config_render || debug_opengl;
+               if (render_improved) {
+                       opengl_viewport_improved(debug_opengl, (double_pixel_size) ? BENSON_AT_LINE * 2 : BENSON_AT_LINE, config_fov, benson_size);
+                       opengl_copy_last();
+               }
+               /* STEP 1: let the CPU render/process the game, also improve rendering via OpenGL, if enabled */
                /* don't render if we still delay */
                if (!render_delay) {
+                       /* start rendering for improved graphics */
+                       if (render_improved)
+                               render_start(config_fov, config_improve_extend_roads, config_debug_transparent);
+
                        /* execute until the rendered image is ready (wait for VBL) */
                        cycle_count = 0;
                        do {
@@ -226,7 +288,7 @@ static void main_loop(void)
                                        special_event(event);
                        } while (event != STOP_AT_WAIT_VBL);
                        /* copy palette */
-                       palette_address = mercenary_palette();
+                       palette_address = mercenary_palette_view();
                        for (i = 0; i < 16; i++)
                                palette[i] = m68k_read_memory_16(palette_address + i*2);
                        /* for amiga speed: set delay by the number of cycles */
@@ -234,21 +296,23 @@ static void main_loop(void)
                                render_delay = (double)cycle_count / CPU_SPEED;
                }
 
-               /* STEP 2: transfer legacy image in memory to OpenGL texture */
+               /* STEP 2: transfer legacy image (or just benson) 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
                         */
                        if (render_legacy)
-                               emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, 0, BENSON_AT_LINE, double_size);
+                               emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, 0, BENSON_AT_LINE, double_pixel_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);
+               if (render_improved) {
+                       render_finish();
+                       opengl_blit_benson(image, config_video_filter, (double_pixel_size) ? BENSON_AT_LINE * 2 : BENSON_AT_LINE, config_fov, benson_size, (double_pixel_size) ? 2 : 1);
+               }
                /* 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);
+                       opengl_viewport_legacy(debug_opengl);
+                       opengl_blit_legacy(image, config_video_filter);
                }
                swap_sdl();
 
@@ -264,10 +328,10 @@ static void main_loop(void)
                        execute_cpu(3, NULL);
                        execute_cpu(4, NULL);
                        had_first_irq = 1;
-                       /* render benson without game view
+                       /* transfer benson without game view
                         * because we only got benson refreshed during VBL IRQ
                         */
-                       emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, BENSON_AT_LINE, IMAGE_HEIGHT, double_size);
+                       emul_video(image, memory, palette, IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_DIWSTART, chipreg, BENSON_AT_LINE, IMAGE_HEIGHT, double_pixel_size);
                        /* render sound to sound buffer
                         * buffer pointer read and write is atomic, so no locking required!
                         */
@@ -439,34 +503,69 @@ static void keyboard_sdl(int down, SDL_Keycode sym)
        case SDLK_RCTRL:
                ctrl = down;
                break;
-       case SDLK_v:
-               if (down && ctrl) {
-                       config_video_filter ^= 1;
-                       print_info("video filter: %s\n", (config_video_filter) ? "on" : "off");
-               }
-               break;
-       case SDLK_a:
-               if (down && ctrl) {
-                       config_audio_filter ^= 1;
-                       print_info("audio filter: %s\n", (config_audio_filter) ? "on" : "off");
-               }
-               break;
-       case SDLK_s:
-               if (down && ctrl) {
-                       config_amiga_speed ^= 1;
-                       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");
+       }
+
+       if (ctrl) {
+               switch (sym) {
+               case SDLK_v:
+                       if (down) {
+                               config_video_filter ^= 1;
+                               print_info("video filter: %s\n", (config_video_filter) ? "on" : "off");
+                       }
+                       break;
+               case SDLK_a:
+                       if (down) {
+                               config_audio_filter ^= 1;
+                               print_info("audio filter: %s\n", (config_audio_filter) ? "on" : "off");
+                       }
+                       break;
+               case SDLK_s:
+                       if (down) {
+                               config_amiga_speed ^= 1;
+                               print_info("amiga speed: %s\n", (config_amiga_speed) ? "original" : "full");
+                       }
+                       break;
+               case SDLK_r:
+                       if (down) {
+                               config_render ^= 1;
+                               print_info("render: %s\n", (config_render) ? "opengl" : "original");
+                       }
+                       break;
+               case SDLK_b:
+                       if (down) {
+                               if (config_benson_size == 0.5) {
+                                       config_benson_size = 1.0;
+                                       config_fov = FOV_NOVAGEN;
+                               } else {
+                                       config_benson_size = 0.5;
+                                       config_fov = FOV_JOLLY;
+                               }
+                               print_info("benson: %s\n", (config_benson_size == 0.5) ? "half" : "normal");
+                       }
+                       break;
+               case SDLK_c:
+                       if (down) {
+                               if (config_ctrl_c)
+                                       quit = 1;
+                       }
+                       break;
+               case SDLK_KP_PLUS:
+                       if (down) {
+                               if (config_fov / 1.2 >= FOV_MIN)
+                                       config_fov /= 1.2;
+                               print_info("FOV: %.2f\n", config_fov);
+                       }
+                       break;
+               case SDLK_KP_MINUS:
+                       if (down) {
+                               if (config_fov * 1.2 <= FOV_MAX)
+                                       config_fov *= 1.2;
+                               print_info("FOV: %.2f\n", config_fov);
+                       }
+                       break;
                }
-               break;
-       case SDLK_c:
-               if (down)
-                       quit = 1;
-               break;
+               /* do not pass keys to game while holding CTRL */
+               return;
        }
 
        switch (sym) {
@@ -635,7 +734,7 @@ int main(int argc, char *argv[])
                return 0;
 
        /* allocate image */
-       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_size) ? 4 : 1), 3);
+       image = calloc(IMAGE_WIDTH * IMAGE_HEIGHT * ((double_pixel_size) ? 4 : 1), 3);
        if (!image) {
                print_error("Failed to allocate image buffer\n");
                goto done;
@@ -696,10 +795,10 @@ int main(int argc, char *argv[])
        mercenary_patch();
 
        /* init SDL and OpenGL */
-       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);
+       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, config_multisampling);
        if (rc < 0)
                goto done;
-       rc = init_opengl((double_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
+       rc = init_opengl((double_pixel_size) ? IMAGE_WIDTH * 2 : IMAGE_WIDTH, (double_pixel_size) ? IMAGE_HEIGHT * 2 : IMAGE_HEIGHT);
        if (rc < 0)
                goto done;
        resize_opengl((config_debug_opengl) ? SCREEN_WIDTH * 2 : SCREEN_WIDTH * 3, (config_debug_opengl) ? SCREEN_HEIGHT * 4 : SCREEN_HEIGHT * 3);
@@ -731,6 +830,8 @@ int main(int argc, char *argv[])
        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 + Keypad Plus to decrement FOV.\n");
+       print_info("Press CTRL + Keypad Minus to increment FOV.\n");
        print_info("Press CTRL + c to exit game.\n\n");
        print_info("Use '--help' as command line option for configuration settings.\n\n");