/* * VGA hardware emulation * * Copyright 1998 Ove Kåven (with some help from Marcus Meissner) * */ #include #include "windows.h" #include "winbase.h" #include "miscemu.h" #include "vga.h" #include "ddraw.h" #include "debug.h" static IDirectDraw *lpddraw = NULL; static IDirectDrawSurface *lpddsurf; static IDirectDrawPalette *lpddpal; static DDSURFACEDESC sdesc; static WORD poll_timer; static CRITICAL_SECTION vga_crit; static int vga_polling,vga_refresh; int VGA_SetMode(unsigned Xres,unsigned Yres,unsigned Depth) { if (lpddraw) VGA_Exit(); if (!lpddraw) { DirectDrawCreate(NULL,&lpddraw,NULL); if (!lpddraw) { ERR(ddraw,"DirectDraw is not available\n"); return 1; } if (lpddraw->lpvtbl->fnSetDisplayMode(lpddraw,Xres,Yres,Depth)) { ERR(ddraw,"DirectDraw does not support requested display mode\n"); lpddraw->lpvtbl->fnRelease(lpddraw); lpddraw=NULL; return 1; } lpddraw->lpvtbl->fnCreatePalette(lpddraw,0,NULL,&lpddpal,NULL); memset(&sdesc,0,sizeof(sdesc)); sdesc.dwSize=sizeof(sdesc); sdesc.dwFlags = DDSD_CAPS; sdesc.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; if (lpddraw->lpvtbl->fnCreateSurface(lpddraw,&sdesc,&lpddsurf,NULL)||(!lpddsurf)) { ERR(ddraw,"DirectDraw surface is not available\n"); lpddraw->lpvtbl->fnRelease(lpddraw); lpddraw=NULL; return 1; } vga_refresh=0; InitializeCriticalSection(&vga_crit); MakeCriticalSectionGlobal(&vga_crit); /* poll every 20ms (50fps should provide adequate responsiveness) */ poll_timer = CreateSystemTimer( 20, VGA_Poll ); } return 0; } int VGA_GetMode(unsigned*Height,unsigned*Width,unsigned*Depth) { if (!lpddraw) return 1; if (!lpddsurf) return 1; if (Height) *Height=sdesc.dwHeight; if (Width) *Width=sdesc.dwWidth; if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount; return 0; } void VGA_Exit(void) { if (lpddraw) { SYSTEM_KillSystemTimer(poll_timer); DeleteCriticalSection(&vga_crit); lpddsurf->lpvtbl->fnRelease(lpddsurf); lpddsurf=NULL; lpddraw->lpvtbl->fnRelease(lpddraw); lpddraw=NULL; } } void VGA_SetPalette(PALETTEENTRY*pal,int start,int len) { if (!lpddraw) return; lpddpal->lpvtbl->fnSetEntries(lpddpal,0,start,len,pal); lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal); } void VGA_SetQuadPalette(RGBQUAD*color,int start,int len) { PALETTEENTRY pal[256]; int c; if (!lpddraw) return; for (c=0; clpvtbl->fnSetEntries(lpddpal,0,start,len,pal); lpddsurf->lpvtbl->fnSetPalette(lpddsurf,lpddpal); } LPSTR VGA_Lock(unsigned*Pitch,unsigned*Height,unsigned*Width,unsigned*Depth) { if (!lpddraw) return NULL; if (!lpddsurf) return NULL; if (lpddsurf->lpvtbl->fnLock(lpddsurf,NULL,&sdesc,0,0)) { ERR(ddraw,"could not lock surface!\n"); return NULL; } if (Pitch) *Pitch=sdesc.lPitch; if (Height) *Height=sdesc.dwHeight; if (Width) *Width=sdesc.dwWidth; if (Depth) *Depth=sdesc.ddpfPixelFormat.x.dwRGBBitCount; return sdesc.y.lpSurface; } void VGA_Unlock(void) { lpddsurf->lpvtbl->fnUnlock(lpddsurf,sdesc.y.lpSurface); } /* We are called from SIGALRM, aren't we? We should _NOT_ do synchronization * stuff! */ void VGA_Poll( WORD timer ) { char *dat; unsigned Pitch,Height,Width; char *surf; int Y,X; EnterCriticalSection(&vga_crit); if (!vga_polling) { vga_polling++; LeaveCriticalSection(&vga_crit); /* FIXME: optimize by doing this only if the data has actually changed * (in a way similar to DIBSection, perhaps) */ surf = VGA_Lock(&Pitch,&Height,&Width,NULL); if (!surf) return; dat = DOSMEM_MapDosToLinear(0xa0000); /* copy from virtual VGA frame buffer to DirectDraw surface */ for (Y=0; Y