Source to src/od-dos/video/video.c


Enter a symbol's name here to quickly find it.

 /*
  * UAE - The Un*x Amiga Emulator
  *
  * DOS video interface.
  *
  * (c) 1997 Gustavo Goedert
  *
  * Originaly based on svga.c -- (c) 1995 Bernd Schmidt
  */

#include "sysconfig.h"
#include "sysdeps.h"

#include <dos.h>
#include <go32.h>
#include <dpmi.h>
#include <sys/exceptn.h>
#include <crt0.h>
#include <signal.h>

#include "config.h"
#include "options.h"
#include "threaddep/thread.h"
#include "memory.h"
#include "custom.h"
#include "xwin.h"
#include "disk.h"
#include "uae.h"
#include "debug.h"
#include "picasso96.h"
#include "misc/handlers.h"
#include "misc/misc.h"
#include "video/vbe.h"

int GetColor(int r, int g, int b, xcolnr *cnp);
void InitColors(void);
void SetWindowForPicasso(void);
void SetWindowForAmiga(void);
uae_u8 *lockscr (void);
void unlockscr (void);

extern int debugging;

xcolnr xcolors[4096];
struct vidbuf_description gfxvidinfo;
int NeedDither;
UBYTE DitherBuf[1000];
int ColorsAllocated;
char *LinearMem = NULL;
int ModeNumber = -1, UseLinear = 0;
int PicassoModeNumber = -1, PicassoUseLinear = 0;
int ScreenIsPicasso = 0;
char PicassoInvalidLines[1200];

struct bstring *video_mode_menu = NULL;

void setup_brkhandler(void) {
}

void flush_line(int y) {
    int target_y = y;
    char *addr;

    if (debugging)
	return;
    if (LinearMem == NULL) {
	addr = gfxvidinfo.bufmem + y*gfxvidinfo.rowbytes;
	if (target_y < CurrentMode.ModeHeight && target_y >= 0) {
	    if (NeedDither) {
		DitherLine(DitherBuf, (UWORD *)addr, 0, y, gfxvidinfo.width, CurrentMode.BitsPerPixel);
		addr = DitherBuf;
	    }
	    CurrentMode.PutLine(addr, target_y);
	}
    } else if (NeedDither && target_y >= 0) {
	addr = gfxvidinfo.bufmem + y*gfxvidinfo.rowbytes;
	DitherLine(LinearMem + CurrentMode.LogicalLineLength * target_y, (UWORD *)addr, 0, y, gfxvidinfo.width, CurrentMode.BitsPerPixel);
    }
}

void flush_block(int a, int b) {
    abort();
}

void flush_screen(int a, int b) {
}

int GetColor(int r, int g, int b, xcolnr *cnp) {
    if ((CurrentMode.ModeType == T16) && (ColorsAllocated == 16))
	return -1;
    else if (ColorsAllocated == 256)
	return -1;
    *cnp = ColorsAllocated;
    DelayedSetPalette(ColorsAllocated, doMask(r, 6, 0), doMask(g, 6, 0), doMask(b, 6, 0));
    ColorsAllocated++;
    return 1;
}

void InitColors(void) {
    int i;

    gfxvidinfo.can_double = 0;
    if (NeedDither)
	setup_dither(CurrentMode.BitsPerColor, GetColor);
    else {
	ColorsAllocated = 0;
	if (gfxvidinfo.pixbytes == 1)
	    alloc_colors256(GetColor);
	else
	    alloc_colors64k(CurrentMode.RedSize,
			    CurrentMode.GreenSize,
			    CurrentMode.BlueSize,
			    CurrentMode.RedPosition,
			    CurrentMode.GreenPosition,
			    CurrentMode.BluePosition);
	if (gfxvidinfo.pixbytes == 1) {
	    for (i = 0; i < 4096; i++)
		xcolors[i] = xcolors[i] * 0x01010101;
	    gfxvidinfo.can_double = 1;
	} else if (gfxvidinfo.pixbytes == 2) {
	    for (i = 0; i < 4096; i++)
		xcolors[i] = xcolors[i] * 0x00010001;
	    gfxvidinfo.can_double = 1;
	}
   }
}

struct gfxstring *gfxmenu;
int numgfxitems = 0;

struct gfxstring{
    char data[32];
    int val;
};

int gfxmenusort(const void *a, const void *b) {
   struct gfxstring *ga, *gb;

   ga = (struct gfxstring *) a;
   gb = (struct gfxstring *) b;
   if (ModeList[ga->val].ModeWidth < ModeList[gb->val].ModeWidth)
      return(-1);
   else if (ModeList[ga->val].ModeWidth > ModeList[gb->val].ModeWidth)
      return(1);
   else if (ModeList[ga->val].ModeHeight < ModeList[gb->val].ModeHeight)
      return(-1);
   else if (ModeList[ga->val].ModeHeight > ModeList[gb->val].ModeHeight)
      return(1);
   else if (ModeList[ga->val].ModeType < ModeList[gb->val].ModeType)
      return(-1);
   else if (ModeList[ga->val].ModeType > ModeList[gb->val].ModeType)
      return(1);
   return(0);
}

int graphics_setup(void) {
    int i, j, hasres;
    struct gfxstring gfxmenuitem;

    gfxmenu = (struct gfxstring *)calloc(NumberOfModes, sizeof(struct gfxstring));

    for (i = 0; i < NumberOfModes; i++) {
	hasres = 0;
	for (j = 0; j < numgfxitems; j++)
	    if ((ModeList[gfxmenu[j].val].ModeType == ModeList[i].ModeType) &&
		(ModeList[gfxmenu[j].val].ModeWidth == ModeList[i].ModeWidth) &&
		(ModeList[gfxmenu[j].val].ModeHeight == ModeList[i].ModeHeight))
		hasres = 1;
	if (!hasres) {
	    sprintf(gfxmenu[numgfxitems].data, "%dx%d ", ModeList[i].ModeWidth, ModeList[i].ModeHeight);
	    switch (ModeList[i].ModeType) {
		case T16:
		    strcat(gfxmenu[numgfxitems].data, "16 colors");
		    break;
		case T256:
		    strcat(gfxmenu[numgfxitems].data, "256 colors");
		    break;
		case T32K:
		    strcat(gfxmenu[numgfxitems].data, "32k colors");
		    break;
		case T64K:
		    strcat(gfxmenu[numgfxitems].data, "64k colors");
		    break;
		case T16M:
		    strcat(gfxmenu[numgfxitems].data, "16M colors");
		    break;
	    }
	    gfxmenu[numgfxitems].val = i;
	    numgfxitems++;
	}
    }
    qsort((void *)gfxmenu, numgfxitems, sizeof(struct gfxstring), gfxmenusort);

    video_mode_menu = (struct bstring *)malloc(sizeof (struct bstring)*(numgfxitems+1));
    for (i = 0; i < numgfxitems; i++) {
	video_mode_menu[i].val = -1;
	video_mode_menu[i].data = strdup(gfxmenu[i].data);
    }
    video_mode_menu[numgfxitems].val = -3;
    video_mode_menu[numgfxitems].data = NULL;

    return 1;
}

void vidmode_menu_selected(int a) {
    currprefs.gfx_width = ModeList[gfxmenu[a].val].ModeWidth;
    currprefs.gfx_height = ModeList[gfxmenu[a].val].ModeHeight;
    switch (ModeList[gfxmenu[a].val].ModeType) {
	case T16:
	    currprefs.color_mode = 4;
	    break;
	case T256:
	    currprefs.color_mode = 0;
	    break;
	case T32K:
	    currprefs.color_mode = 1;
	    break;
	case T64K:
	    currprefs.color_mode = 2;
	    break;
	case T16M:
	    currprefs.color_mode = 5;
	    break;
    }
    currprefs.gfx_lores=currprefs.gfx_width<640;
    currprefs.gfx_xcenter=2;
    currprefs.gfx_ycenter=2;
    currprefs.gfx_linedbl=0;
    if (currprefs.gfx_height > 285)
	currprefs.gfx_linedbl = 1;
    currprefs.gfx_correct_aspect = 1;
    if (currprefs.gfx_height > 570)
	currprefs.gfx_correct_aspect = 0;
}

int graphics_init(void) {
    T_ModeType WantedType;
    int i;

    /* save produce_sound state */
    Original_produce_sound = currprefs.produce_sound;

    switch (currprefs.color_mode) {
	case 0: WantedType=T256; NeedDither=0; break;
	case 1: WantedType=T32K; NeedDither=0; break;
	case 2: WantedType=T64K; NeedDither=0; break;
	case 3: WantedType=T256; NeedDither=1; break;
	case 4: WantedType=T16;  NeedDither=1; break;
	case 5: WantedType=T16M; NeedDither=0; break;
	default:
	printf("Invalid color mode.\n");
	return 0;
    }

    if (!InitGfxLib()) {
	printf("Can't init GfxLib.\n");
	return 0;
    }

    if (!currprefs.no_xhair)
	for (i = 0; i < NumberOfModes; i++) {
	    if ((ModeList[i].ModeType == WantedType) &&
		(ModeList[i].ModeWidth == currprefs.gfx_width) &&
		(ModeList[i].ModeHeight == currprefs.gfx_height) &&
		 ModeList[i].HasLinear) {
		ModeNumber = i;
		UseLinear = 1;
		break;
	    }
	}
    if (ModeNumber == -1)
	for (i = 0; i < NumberOfModes; i++) {
	    if ((ModeList[i].ModeType == WantedType) &&
		(ModeList[i].ModeWidth == currprefs.gfx_width) &&
		(ModeList[i].ModeHeight == currprefs.gfx_height)) {
		if (ModeList[i].HasWindow || ((!ModeList[i].HasLinear) && (!ModeList[i].HasWindow))) {
		    ModeNumber = i;
		    break;
		}
	    }
	}

    if (ModeNumber == -1) {
	printf("Sorry, this combination of color and video mode is not supported.\n");
	return 0;
    }

    if (!SetMode(ModeNumber, UseLinear, 1)) {
	printf("Can't start graphics mode.\n");
	return 0;
    }

    if (!NeedDither)
	gfxvidinfo.pixbytes = CurrentMode.BitsPerPixel>>3;
    else
	gfxvidinfo.pixbytes = 2;

    if (UseLinear) {
	printf("Using linear framebuffer.\n");
	if (CanMapBuffer) {
	    LinearMem = CurrentMode.MappedAddress;
	    if (LinearMem != NULL)
		printf("Mapping linear framebuffer into emulator memory.\n");
	    else {
		printf("Can't map linear framebuffer.\n");
		return 0;
	    }
	}
    }

    gfxvidinfo.maxblocklines = 0;

    gfxvidinfo.width = CurrentMode.ModeWidth;
    gfxvidinfo.height = CurrentMode.ModeHeight;
    gfxvidinfo.linemem = 0;

    InitColors();
    if ((gfxvidinfo.pixbytes == 1) || NeedDither)
	LoadPalette();

    if (UseLinear && CanMapBuffer && (!NeedDither) && (LinearMem != NULL)) {
	gfxvidinfo.bufmem = LinearMem;
	gfxvidinfo.rowbytes = CurrentMode.LogicalLineLength;
    } else {
	gfxvidinfo.rowbytes = (CurrentMode.ModeWidth * gfxvidinfo.pixbytes + 3) & ~3;
	gfxvidinfo.bufmem = malloc(gfxvidinfo.rowbytes * CurrentMode.ModeHeight);
	if (gfxvidinfo.bufmem == NULL) {
	    printf("Can't allocate framebuffer.\n");
	    return 0;
	}
    }

    memset(gfxvidinfo.bufmem, 0, gfxvidinfo.rowbytes * CurrentMode.ModeHeight);
    for(i=0; i<gfxvidinfo.height; i++)
	flush_line(i);

    /* set up handlers */
    if (!InstallHandlers()) {
	printf("Can't install all handlers.\n");
	return(0);
    }

    return 1;
}

void graphics_leave(void) {
    UninstallHandlers();
    CloseGfxLib();
    dumpcustom();
    /* restore produce_sound state */
    currprefs.produce_sound = Original_produce_sound;
}

int debuggable(void) {
    return(1);
}

int needmousehack(void) {
    return(0);
}

void write_log (const char *buf) {
    printf(buf);
}

#ifdef PICASSO96

void PicassoRefresh(void) {
    if (ScreenIsPicasso && !picasso_vidinfo.extra_mem) {
	int i;
	char *addr = gfxmemory + (picasso96_state.Address - gfxmem_start);
	for (i = 0; i < picasso_vidinfo.height; i++, addr += picasso96_state.BytesPerRow) {
	    if (!PicassoInvalidLines[i])
		continue;
	    PicassoInvalidLines[i] = 0;
	    CurrentMode.PutLine(addr, i);
	}
    }
}

void DX_Invalidate (int first, int last) {
    if (!picasso_vidinfo.extra_mem) {
	do {
	    PicassoInvalidLines[first] = 1;
	    first++;
	} while (first <= last);
    }
}

int DX_BitsPerCannon (void) {
    return 8;
}

void DX_SetPalette(int start, int count) {
    if (!ScreenIsPicasso || picasso_vidinfo.pixbytes != 1)
	return;

    while (count-- > 0) {
	DelayedSetPalette(start, picasso96_state.CLUT[start].Red * 63 / 255,
				 picasso96_state.CLUT[start].Green * 63 / 255,
				 picasso96_state.CLUT[start].Blue * 63 / 255);
	start++;
    }
    LoadPalette();
}

int DX_FillResolutions (uae_u16 *ppixel_format) {
    int i, count = 0;
    uae_u16 format = 0;

    for (i = 0; i < NumberOfModes; i++) {
	if (ModeList[i].ModeType != T16) {
	    DisplayModes[count].res.width = ModeList[i].ModeWidth;
	    DisplayModes[count].res.height = ModeList[i].ModeHeight;
	    DisplayModes[count].depth = ModeList[i].BitsPerPixel>>3;
	    DisplayModes[count].refresh = 75;
	    switch (DisplayModes[count].depth) {
		case 1: format |= RGBFF_CHUNKY; break;
		case 2: format |= RGBFF_R5G6B5PC; break;
		case 3: format |= RGBFF_B8G8R8; break;
		case 4: format |= RGBFF_B8G8R8A8; break;
	    }
	    count++;
	}
    }

    *ppixel_format = format;
    return count;
}

void SetWindowForPicasso(void) {
    if (!SetMode(PicassoModeNumber, PicassoUseLinear, 0)) {
	printf("Can't start graphics mode.\n");
	abort();
    }
    if (PicassoUseLinear && (CurrentMode.MappedAddress != NULL)) {
	LinearMem = CurrentMode.MappedAddress;
	picasso_vidinfo.extra_mem = 1;
    } else
	picasso_vidinfo.extra_mem = 0;
    DX_SetPalette (0, 256);
}

void SetWindowForAmiga(void) {
    if (!SetMode(ModeNumber, UseLinear, 0)) {
	printf("Can't start graphics mode.\n");
	abort();
    }
    if (UseLinear && (CurrentMode.MappedAddress != NULL) && (!NeedDither)) {
	LinearMem = CurrentMode.MappedAddress;
	gfxvidinfo.bufmem = LinearMem;
    }
    if ((gfxvidinfo.pixbytes == 1) || NeedDither)
	LoadPalette();
}

void gfx_set_picasso_state (int on) {
    if (on == ScreenIsPicasso)
	return;
    ScreenIsPicasso = on;
    if (on)
	SetWindowForPicasso();
    else
	SetWindowForAmiga();
}

void gfx_set_picasso_modeinfo (int w, int h, int depth) {
    T_ModeType WantedType;
    int i;

    PicassoModeNumber = -1;
    PicassoUseLinear = 0;
    switch (depth) {
	case 8: WantedType=T256; break;
	case 16: WantedType=T64K; break;
	case 24:
	case 32: WantedType=T16M; break;
	default:
	printf("Invalid Picasso mode.\n");
	abort();
    }

    if (!currprefs.no_xhair)
	for (i = 0; i < NumberOfModes; i++) {
	    if ((ModeList[i].ModeType == WantedType) &&
		(ModeList[i].ModeWidth == w) &&
		(ModeList[i].ModeHeight == h) &&
		 ModeList[i].HasLinear) {
		PicassoModeNumber = i;
		PicassoUseLinear = 1;
		break;
	    }
	}
    if (PicassoModeNumber == -1)
	for (i = 0; i < NumberOfModes; i++) {
	    if ((ModeList[i].ModeType == WantedType) &&
		(ModeList[i].ModeWidth == w) &&
		(ModeList[i].ModeHeight == h)) {
		if (ModeList[i].HasWindow || ((!ModeList[i].HasLinear) && (!ModeList[i].HasWindow))) {
		    PicassoModeNumber = i;
		    break;
		}
	    }
	}

    if (PicassoModeNumber == -1) {
	printf("Invalid Picasso mode.\n");
	abort ();
    }

    picasso_vidinfo.width = w;
    picasso_vidinfo.height = h;
    picasso_vidinfo.depth = depth;
    picasso_vidinfo.pixbytes = depth>>3;
    picasso_vidinfo.rowbytes = ModeList[PicassoModeNumber].LogicalLineLength;
    if (ScreenIsPicasso)
	SetWindowForPicasso ();
}

uae_u8 *lockscr (void) {
    return LinearMem;
}