ftp.nice.ch/pub/next/tools/emulators/vice.0.15.0.NeXT.sd.tgz#/vice-0.15.0/src/arch/msdos/video.c

This is video.c in view mode; [Download] [Up]

/*
 * video.c - MS-DOS graphics handling, based on the Allegro library by Shawn
 * Hargreaves (http://www.talula.demon.co.uk/allegro).
 *
 * Written by
 *  Ettore Perazzoli (ettore@comm2000.it)
 *
 * This file is part of VICE, the Versatile Commodore Emulator.
 * See README for copyright notice.
 *
 *  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 2 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, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 *  02111-1307  USA.
 *
 */

#include "vice.h"

#include <stdio.h>
#include <string.h>

#include "video.h"

#include "cmdline.h"
#include "kbd.h"
#include "resources.h"
#include "tui.h"

/* #define DEBUG_VIDEO */

vga_mode_t vga_modes[] = {
    /* VGA_320x200 */ {	320, 200, "320x200" },
    /* VGA_360x240 */ { 360, 240, "360x240" },
    /* VGA_360x270 */ { 360, 270, "360x270" },
    /* VGA_376x282 */ { 376, 282, "376x282" },
    /* VGA_400x300 */ { 400, 300, "400x300" },
    /* VGA_640x480 */ { 640, 480, "640x480" }
};

canvas_t last_canvas;

#ifdef DEBUG_VIDEO
#define DEBUG(x)					\
    do {						\
        printf("%s, %d: ", __FUNCTION__, __LINE__);	\
        printf x;					\
        putchar('\n');					\
    } while (0)
#else
#define DEBUG(x)
#endif

/* Flag: are we in graphics mode?  */
static int in_gfx_mode;

/* ------------------------------------------------------------------------- */

/* Video-related resources.  */

/* VGA Video mode to use.  */
static int vga_mode;

static int set_vga_mode(resource_value_t v)
{
    /* FIXME: Sanity check!  */
    vga_mode = (int) v;
    return 0;
}

#ifndef USE_MIDAS_SOUND

/* Flag: do we try to use triple buffering if possible?  */
static int try_triple_buffering;

static int set_try_triple_buffering(resource_value_t v)
{
    /* FIXME: this has only effect when we switch to gfx mode.  This is OK
       for now, but is not the correct behavior.  */
    try_triple_buffering = (int) v;
    return 0;
}

#endif

static resource_t resources[] = {
    { "VGAMode", RES_INTEGER, (resource_value_t) VGA_320x200,
      (resource_value_t *) &vga_mode, set_vga_mode },
#ifndef USE_MIDAS_SOUND
    { "TripleBuffering", RES_INTEGER, (resource_value_t) 0,
      (resource_value_t *) &try_triple_buffering, set_try_triple_buffering },
#endif
    { NULL }
};

int video_init_resources(void)
{
    return resources_register(resources);
}

/* ------------------------------------------------------------------------- */

/* Video-specific command-line options.  */

static cmdline_option_t cmdline_options[] = {
    { "-vgamode", SET_RESOURCE, 1, NULL, NULL,
      "VGAMode", NULL,
      "<mode>", "Set VGA mode to <mode>" },
#ifndef USE_MIDAS_SOUND
    { "-triplebuf", SET_RESOURCE, 0, NULL, NULL,
      "TripleBuffering", (resource_value_t) 1,
      NULL, "Try to use triple buffering when possible" },
    { "+triplebuf", SET_RESOURCE, 0, NULL, NULL,
      "TripleBuffering", (resource_value_t) 1,
      NULL, "Disable usage of triple buffering" },
#endif
    { NULL }
};

int video_init_cmdline_options(void)
{
    return cmdline_register_options(cmdline_options);
}

/* ------------------------------------------------------------------------- */

int video_init(void)
{
    if (allegro_init()) {
	fprintf(stderr, "??? Cannot initialize the Allegro library ???\n");
	exit(-1);
    }
    printf("Allegro initialized.\n");
    in_gfx_mode = 0;

    return 0;
}

int frame_buffer_alloc(frame_buffer_t *i, unsigned int width,
		       unsigned int height)
{
    DEBUG(("Allocating bitmap width=%d, height=%d", width, height));
    *i = create_bitmap(width, height);
    if (*i == NULL) {
	DEBUG(("Bitmap allocation failed"));
	return -1;
    } else {
	DEBUG(("Bitmap allocation successful"));
	return 0;
    }
}

void frame_buffer_free(frame_buffer_t *i)
{
    DEBUG(("Freeing frame buffer 0x%x", (unsigned int)i));
    destroy_bitmap(*i);
}

void frame_buffer_clear(frame_buffer_t * f, BYTE value)
{
    int i;

    DEBUG(("Clearing frame buffer 0x%x with value 0x%x",
	   (unsigned int)f, value));
    for (i = 0; i < (*f)->h; i++)
	memset((*f)->line[i], value, (*f)->w);
}

static void canvas_set_vga_mode(canvas_t c)
{
    int i;

#ifndef USE_MIDAS_SOUND
    /* If the user wants triple buffering, try Mode X first of all, as that
       is (currently) the only reliable way to achieve the result.  Virtual
       height is twice visible height to allow smooth page flipping.  */
    if (try_triple_buffering
        && (set_gfx_mode(GFX_MODEX, c->width, c->height, 0, c->height * 2)
            >= 0)) {
        DEBUG(("GFX_MODEX successful with width=%d height=%d vheight=%d",
               c->width, c->height, c->height * 2));
        c->use_triple_buffering = 1;
    } else
#endif
    /* If we don't want triple buffering, try to get a VESA linear mode
       first, which might not be the default. */
    if (set_gfx_mode(GFX_VESA2L, c->width, c->height, 0, 0) >= 0) {
        DEBUG(("GFX_VESA2L successful with width=%d height=%d",
               c->width, c->height));
        c->use_triple_buffering = 0;
    } else if (set_gfx_mode(GFX_AUTODETECT, c->width, c->height, 0, 0) >= 0) {
        DEBUG(("GFX_AUTODETECT successful with width=%d height=%d",
               c->width, c->height));
        c->use_triple_buffering = 0;
    } else {
        fprintf(stderr, "Cannot enable %dx%dx256 graphics.\n",
                c->width, c->height);
        exit(-1);
    }

    printf("Using mode %dx%dx256 (%s)%s.\n",
	   c->width, c->height,
	   is_linear_bitmap(screen) ? "linear" : "planar",
           c->use_triple_buffering ? "; triple buffering possible" : "");
    in_gfx_mode = 1;

#ifndef USE_MIDAS_SOUND
    /* If using triple buffering, setup the timer used by Allegro to emulate
       vertical retrace interrupts.  Wish I had $D012/$D011 on VGA.  */
    timer_simulate_retrace(c->use_triple_buffering);
#endif

    if (c->use_triple_buffering) {
        c->pages[0] = create_sub_bitmap(screen,
                                        0, 0, c->width, c->height);
        c->pages[1] = create_sub_bitmap(screen,
                                        0, c->height, c->width, c->height);
        c->back_page = 1;
    }

    for (i = 0; i < NUM_AVAILABLE_COLORS; i++)
        set_color(i, &c->colors[i]);
}

/* Note: `mapped' is ignored.  */
canvas_t canvas_create(const char *win_name, unsigned int *width,
		       unsigned int *height, int mapped,
		       canvas_redraw_t exposure_handler,
		       const palette_t *palette, PIXEL *pixel_return)
{
    int i;
    canvas_t new_canvas;

    DEBUG(("Creating canvas width=%d height=%d", *width, *height));
    if (palette->num_entries > NUM_AVAILABLE_COLORS) {
	fprintf(stderr, "??? Too many colors requested! ???\n");
	return (canvas_t) NULL;
    }
    new_canvas = (canvas_t) malloc(sizeof(struct _canvas));
    if (!new_canvas)
	return (canvas_t) NULL;

    canvas_set_palette(new_canvas, palette, pixel_return);

    /* Set width and height.  */
    canvas_resize(new_canvas, 0, 0);
    *width = new_canvas->width;
    *height = new_canvas->height;

    DEBUG(("Setting VGA mode"));
    canvas_set_vga_mode(new_canvas);

    new_canvas->exposure_handler = exposure_handler;
    new_canvas->back_page = 1;

    last_canvas = new_canvas;
    return new_canvas;
}

int canvas_set_palette(canvas_t c, const palette_t *palette,
                       PIXEL *pixel_return)
{
    int i;

    DEBUG(("Allocating colors"));
    for (i = 0; i < palette->num_entries; i++) {
	c->colors[i].r = palette->entries[i].red >> 2;
	c->colors[i].g = palette->entries[i].green >> 2;
	c->colors[i].b = palette->entries[i].blue >> 2;
	pixel_return[i] = i;
        if (in_gfx_mode)
            set_color(i, &c->colors[i]);
    }

    return 0;
}

void canvas_map(canvas_t c)
{
    /* Not implemented. */
}

void canvas_unmap(canvas_t c)
{
    /* Not implemented. */
}

/* Warning: this does not do what you would expect from it.  It just sets the
   canvas size according to the `VGAMode' resource. */
void canvas_resize(canvas_t c, unsigned int width, unsigned int height)
{
    DEBUG(("Resizing, vga_mode=%d", vga_mode));
    c->width = vga_modes[vga_mode].width;
    c->height = vga_modes[vga_mode].height;
}

void video_ack_vga_mode(void)
{
    if (last_canvas != NULL) {
        canvas_resize(last_canvas, last_canvas->width, last_canvas->height);
        last_canvas->exposure_handler(last_canvas->width, last_canvas->height);
        DEBUG(("Acknowledged vgaMode %d", vga_mode));
    }
}

/* ------------------------------------------------------------------------- */

void enable_text(void)
{
    DEBUG(("Enabling text mode"));
    kbd_uninstall();
    set_gfx_mode(GFX_TEXT, 80, 25, 0, 0);
    _set_screen_lines(25);
    DEBUG(("Successful"));
    in_gfx_mode = 0;
}

void disable_text(void)
{
    DEBUG(("Enabling gfx mode"));
    kbd_install();
    if (last_canvas->width > 0 && last_canvas->height > 0) {
        int i;

	video_ack_vga_mode();
	canvas_set_vga_mode(last_canvas);

	for (i = 0; i < NUM_AVAILABLE_COLORS; i++)
	    set_color(i, &last_canvas->colors[i]);

	last_canvas->exposure_handler(last_canvas->width, last_canvas->height);
	in_gfx_mode = 1;
    }
    DEBUG(("Successful"));
}

int num_text_lines(void)
{
    return tui_num_lines();
}

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.