Support SHR video modes with a VidHD card (#997, PR #1004)

Support VidHD in slot 3 (via Config GUI or '-s3 vidhd') for SHR video modes only.
- AppleWin window is slightly enlarged when VidHD card is inserted.
Support IIgs 320x200 (and fill mode) and 640x200 video modes.
Debugger: add 'shr' command to view video
CUI: Allow user to specify width & height (for full-screen); and allow separate x,y scaling in full-screen mode.
This commit is contained in:
TomCh 2021-11-30 21:41:02 +00:00 committed by GitHub
parent 0b2104cc89
commit 443545b0f6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 653 additions and 113 deletions

View File

@ -121,6 +121,7 @@
<ClInclude Include="source\Tfe\Uilib.h" />
<ClInclude Include="source\Utilities.h" />
<ClInclude Include="source\Video.h" />
<ClInclude Include="Source\VidHD.h" />
<ClInclude Include="source\Windows\AppleWin.h" />
<ClInclude Include="source\Windows\DirectInput.h" />
<ClInclude Include="source\Windows\HookFilter.h" />
@ -247,6 +248,7 @@
</ClCompile>
<ClCompile Include="source\Utilities.cpp" />
<ClCompile Include="source\Video.cpp" />
<ClCompile Include="Source\VidHD.cpp" />
<ClCompile Include="source\Windows\AppleWin.cpp" />
<ClCompile Include="source\Windows\DirectInput.cpp" />
<ClCompile Include="source\Windows\HookFilter.cpp" />

View File

@ -241,6 +241,9 @@
<ClCompile Include="source\Card.cpp">
<Filter>Source Files\Emulator</Filter>
</ClCompile>
<ClCompile Include="Source\VidHD.cpp">
<Filter>Source Files\Video</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="source\CommonVICE\6510core.h">
@ -555,6 +558,9 @@
<ClInclude Include="source\SNESMAX.h">
<Filter>Source Files\Emulator</Filter>
</ClInclude>
<ClInclude Include="Source\VidHD.h">
<Filter>Source Files\Video</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Image Include="resource\Applewin.bmp">

View File

@ -84,7 +84,7 @@ IDB_DEBUG_FONT_7X8 BITMAP "Debug_Font.bmp"
// Dialog
//
IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 209
IDD_PROPPAGE_CONFIG DIALOGEX 0, 0, 210, 240
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
CAPTION "Configuration"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
@ -92,30 +92,32 @@ BEGIN
LTEXT "&Model:",IDC_STATIC,5,7,40,8
COMBOBOX IDC_COMPUTER,45,5,91,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
CONTROL "Confirm reboot",IDC_CHECK_CONFIRM_REBOOT,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,8,62,10
GROUPBOX "Video",IDC_STATIC,5,22,200,56
GROUPBOX "Video",IDC_STATIC,5,22,200,74
LTEXT "Mo&de:",IDC_STATIC,12,33,33,8
COMBOBOX IDC_VIDEOTYPE,33,30,103,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "Monochrome &Color...",IDC_MONOCOLOR,12,46,80,14
CONTROL "50% Scan lines",IDC_CHECK_HALF_SCAN_LINES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,33,62,10
CONTROL "Vertical blend",IDC_CHECK_VERTICAL_BLEND,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,48,62,10
CONTROL "Full-Screen: Show drive/keyboard status",IDC_CHECK_FS_SHOW_SUBUNIT_STATUS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,64,140,10
LTEXT "&Serial Port:",IDC_STATIC,5,89,40,8
COMBOBOX IDC_SERIALPORT,45,87,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Ethernet Settings...",IDC_ETHERNET,4,105,80,14
GROUPBOX "Emulation Speed Control",IDC_STATIC,5,130,200,85
CONTROL "Full-Screen: Show drive/keyboard status",IDC_CHECK_FS_SHOW_SUBUNIT_STATUS,
"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,64,140,10
CONTROL "VidHD in slot 3",IDC_CHECK_VIDHD_IN_SLOT3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,78,140,10
LTEXT "&Serial Port:",IDC_STATIC,5,108,40,8
COMBOBOX IDC_SERIALPORT,45,106,90,100,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
PUSHBUTTON "&Ethernet Settings...",IDC_ETHERNET,4,124,80,14
GROUPBOX "Emulation Speed Control",IDC_STATIC,5,149,200,85
CONTROL "Use &Authentic Machine Speed",IDC_AUTHENTIC_SPEED,
"Button",BS_AUTORADIOBUTTON,15,141,115,10
CONTROL "Select C&ustom Speed (in MHz)",IDC_CUSTOM_SPEED,"Button",BS_AUTORADIOBUTTON,15,153,115,10
CONTROL "Generic2",IDC_SLIDER_CPU_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,25,164,160,15
CTEXT "0.5",IDC_0_5_MHz,23,180,20,10
CTEXT "1.0",IDC_1_0_MHz,59,180,20,10
CTEXT "2.0",IDC_2_0_MHz,96,180,20,10
RTEXT "Fastest",IDC_MAX_MHz,150,180,29,10
PUSHBUTTON "&Benchmark Emulator",IDC_BENCHMARK,15,194,85,15
CONTROL "50Hz video",IDC_CHECK_50HZ_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,141,51,10
"Button",BS_AUTORADIOBUTTON,15,160,115,10
CONTROL "Select C&ustom Speed (in MHz)",IDC_CUSTOM_SPEED,"Button",BS_AUTORADIOBUTTON,15,172,115,10
CONTROL "Generic2",IDC_SLIDER_CPU_SPEED,"msctls_trackbar32",TBS_AUTOTICKS | WS_TABSTOP,25,183,160,15
CTEXT "0.5",IDC_0_5_MHz,23,199,20,10
CTEXT "1.0",IDC_1_0_MHz,59,199,20,10
CTEXT "2.0",IDC_2_0_MHz,96,199,20,10
RTEXT "Fastest",IDC_MAX_MHz,150,199,29,10
PUSHBUTTON "&Benchmark Emulator",IDC_BENCHMARK,15,213,85,15
CONTROL "50Hz video",IDC_CHECK_50HZ_VIDEO,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,142,160,51,10
END
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 211, 240
IDD_PROPPAGE_INPUT DIALOGEX 0, 0, 210, 240
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
CAPTION "Input"
FONT 8, "MS Shell Dlg", 0, 0, 0x0
@ -172,7 +174,7 @@ BEGIN
CONTROL "No sound cards",IDC_SOUNDCARD_DISABLE,"Button",BS_AUTORADIOBUTTON,10,175,78,10
END
IDD_PROPPAGE_DISK DIALOGEX 0, 0, 211, 188
IDD_PROPPAGE_DISK DIALOGEX 0, 0, 210, 240
STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_VISIBLE | WS_DISABLED | WS_CAPTION | WS_SYSMENU
CAPTION "Disk"
FONT 8, "MS Shell Dlg", 0, 0, 0x0

View File

@ -70,7 +70,6 @@
#define IDC_PHASOR_ENABLE 1029
#define IDC_SAM_ENABLE 1030
#define IDC_SOUNDCARD_DISABLE 1031
#define IDC_TFE_SETTINGS_ENABLE_T 1032
#define IDC_TFE_SETTINGS_ENABLE 1033
#define IDC_TFE_SETTINGS_INTERFACE_T 1034
@ -99,7 +98,6 @@
#define IDC_PRINTER_FILTER_UNPRINTABLE 1057
#define IDC_PRINTER_APPEND 1058
#define IDC_SPIN_PRINTER_IDLE 1059
#define IDC_CHECK_HALF_SCAN_LINES 1060
#define IDC_GPL_TEXT 1061
#define IDC_GPL_BORDER 1063
@ -120,6 +118,7 @@
#define IDC_COMBO_DISK2_SLOT5 1086
#define IDC_FOURPLAY_CONFIG 1087
#define IDC_SNESMAX_CONFIG 1088
#define IDC_CHECK_VIDHD_IN_SLOT3 1089
#define IDM_EXIT 40001
#define IDM_HELP 40002
#define IDM_ABOUT 40003

View File

@ -23,6 +23,7 @@ enum SS_CARDTYPE
CT_Saturn128K, // Saturn 128K (but may be populated with less RAM, in multiples of 16K)
CT_FourPlay, // 4 port Atari 2600 style digital joystick card
CT_SNESMAX, // 2 port Nintendo NES/SNES controller serial interface card
CT_VidHD,
};
enum SLOTS { SLOT0=0, SLOT1, SLOT2, SLOT3, SLOT4, SLOT5, SLOT6, SLOT7, NUM_SLOTS, SLOT_AUX };

View File

@ -40,6 +40,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "SAM.h"
#include "SerialComms.h"
#include "SNESMAX.h"
#include "VidHD.h"
void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
{
@ -96,6 +97,9 @@ void CardManager::InsertInternal(UINT slot, SS_CARDTYPE type)
case CT_SNESMAX:
m_slot[slot] = new SNESMAXCard(slot);
break;
case CT_VidHD:
m_slot[slot] = new VidHDCard(slot);
break;
case CT_LanguageCard:
case CT_Saturn128K:

View File

@ -169,6 +169,13 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
g_cmdLine.bSlotEmpty[slot] = true;
if (strcmp(lpCmdLine, "diskii") == 0)
g_cmdLine.slotInsert[slot] = CT_Disk2;
if (strcmp(lpCmdLine, "vidhd") == 0)
{
if (slot == SLOT3)
g_cmdLine.slotInsert[slot] = CT_VidHD;
else
LogFileOutput("VidHD currently only supported in slot 3\n");
}
}
else if (lpCmdLine[3] == 'd' && (lpCmdLine[4] == '1' || lpCmdLine[4] == '2')) // -s[1..7]d[1|2] <dsk-image>
{
@ -208,6 +215,19 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
{
g_cmdLine.setFullScreen = 0;
}
#define CMD_FS_WIDTH "-fs-width="
else if (strncmp(lpCmdLine, CMD_FS_WIDTH, sizeof(CMD_FS_WIDTH)-1) == 0)
{
if (g_cmdLine.setFullScreen < 0) // Not yet been specified on cmd line?
g_cmdLine.setFullScreen = 1; // Implicity set full-screen. NB. Can be overridden by "-no-full-screen"
LPSTR lpTmp = lpCmdLine + sizeof(CMD_FS_WIDTH)-1;
{
g_cmdLine.userSpecifiedWidth = atoi(lpTmp);
if (!g_cmdLine.userSpecifiedWidth)
LogFileOutput("Invalid cmd-line parameter for -fs-width=x switch\n");
}
}
#define CMD_FS_HEIGHT "-fs-height="
else if (strncmp(lpCmdLine, CMD_FS_HEIGHT, sizeof(CMD_FS_HEIGHT)-1) == 0)
{
@ -215,24 +235,16 @@ bool ProcessCmdLine(LPSTR lpCmdLine)
g_cmdLine.setFullScreen = 1; // Implicity set full-screen. NB. Can be overridden by "-no-full-screen"
LPSTR lpTmp = lpCmdLine + sizeof(CMD_FS_HEIGHT)-1;
bool bRes = false;
UINT bestWidth=0, bestHeight=0;
if (strcmp(lpTmp, "best") == 0)
{
bRes = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight);
g_cmdLine.bestFullScreenResolution = true;
}
else
{
UINT userSpecifiedHeight = atoi(lpTmp);
if (userSpecifiedHeight)
bRes = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight, userSpecifiedHeight);
else
g_cmdLine.userSpecifiedHeight = atoi(lpTmp);
if (!g_cmdLine.userSpecifiedHeight)
LogFileOutput("Invalid cmd-line parameter for -fs-height=x switch\n");
}
if (bRes)
LogFileOutput("Best resolution for -fs-height=x switch: Width=%d, Height=%d\n", bestWidth, bestHeight);
else
LogFileOutput("Failed to set parameter for -fs-height=x switch\n");
}
else if (strcmp(lpCmdLine, "-no-di") == 0)
{

View File

@ -35,6 +35,9 @@ struct CmdLine
rgbCard = RGB_Videocard_e::Apple;
rgbCardForegroundColor = 15;
rgbCardBackgroundColor = 0;
bestFullScreenResolution = false;
userSpecifiedWidth = 0;
userSpecifiedHeight = 0;
for (UINT i = 0; i < NUM_SLOTS; i++)
{
@ -74,6 +77,9 @@ struct CmdLine
int rgbCardForegroundColor;
int rgbCardBackgroundColor;
std::string strCurrentDir;
bool bestFullScreenResolution;
UINT userSpecifiedWidth;
UINT userSpecifiedHeight;
};
bool ProcessCmdLine(LPSTR lpCmdLine);

View File

@ -89,18 +89,18 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
switch (LOWORD(wparam))
{
case IDC_AUTHENTIC_SPEED: // Authentic Machine Speed
SendDlgItemMessage(hWnd,IDC_SLIDER_CPU_SPEED,TBM_SETPOS,1,SPEED_NORMAL);
EnableTrackbar(hWnd,0);
SendDlgItemMessage(hWnd, IDC_SLIDER_CPU_SPEED, TBM_SETPOS, 1, SPEED_NORMAL);
EnableTrackbar(hWnd, 0);
break;
case IDC_CUSTOM_SPEED: // Select Custom Speed
SetFocus(GetDlgItem(hWnd,IDC_SLIDER_CPU_SPEED));
EnableTrackbar(hWnd,1);
SetFocus(GetDlgItem(hWnd, IDC_SLIDER_CPU_SPEED));
EnableTrackbar(hWnd, 1);
break;
case IDC_SLIDER_CPU_SPEED: // CPU speed slider
CheckRadioButton(hWnd,IDC_AUTHENTIC_SPEED,IDC_CUSTOM_SPEED,IDC_CUSTOM_SPEED);
EnableTrackbar(hWnd,1);
CheckRadioButton(hWnd, IDC_AUTHENTIC_SPEED, IDC_CUSTOM_SPEED, IDC_CUSTOM_SPEED);
EnableTrackbar(hWnd, 1);
break;
case IDC_BENCHMARK:
@ -113,6 +113,7 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
case IDC_ETHERNET:
ui_tfe_settings_dialog(hWnd);
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = m_PageConfigTfe.m_tfe_enabled ? CT_Uthernet : CT_Empty;
InitOptions(hWnd);
break;
case IDC_MONOCOLOR:
@ -127,6 +128,14 @@ INT_PTR CPageConfig::DlgProcInternal(HWND hWnd, UINT message, WPARAM wparam, LPA
// Checked in DlgOK()
break;
case IDC_CHECK_VIDHD_IN_SLOT3:
{
const UINT newState = IsDlgButtonChecked(hWnd, IDC_CHECK_VIDHD_IN_SLOT3) ? 1 : 0;
m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3] = newState ? CT_VidHD : CT_Empty;
InitOptions(hWnd);
}
break;
case IDC_COMPUTER:
if(HIWORD(wparam) == CBN_SELCHANGE)
{
@ -374,6 +383,11 @@ void CPageConfig::InitOptions(HWND hWnd)
const SS_CARDTYPE slot3 = m_PropertySheetHelper.GetConfigNew().m_Slot[SLOT3];
const BOOL enableUthernetDialog = slot3 == CT_Empty || slot3 == CT_Uthernet;
EnableWindow(GetDlgItem(hWnd, IDC_ETHERNET), enableUthernetDialog);
const bool bIsSlot3VidHD = slot3 == CT_VidHD;
CheckDlgButton(hWnd, IDC_CHECK_VIDHD_IN_SLOT3, bIsSlot3VidHD ? BST_CHECKED : BST_UNCHECKED);
const BOOL enableVidHD = slot3 == CT_Empty || bIsSlot3VidHD;
EnableWindow(GetDlgItem(hWnd, IDC_CHECK_VIDHD_IN_SLOT3), enableVidHD);
}
// Config->Computer: Menu item to eApple2Type

View File

@ -548,6 +548,8 @@ std::string CPropertySheetHelper::GetCardName(const SS_CARDTYPE CardType)
return "4Play";
case CT_SNESMAX:
return "SNES MAX";
case CT_VidHD:
return "VidHD";
default:
return "Unknown";
}

View File

@ -6545,6 +6545,11 @@ Update_t _ViewOutput( ViewVideoPage_t iPage, int bVideoModeFlags )
{
return _ViewOutput( VIEW_PAGE_2, VF_HIRES | VF_DHIRES | VF_80COL );
}
// Super Hi-Res
Update_t CmdViewOutput_SHR(int nArgs)
{
return _ViewOutput( VIEW_PAGE_1, VF_SHR );
}
// Watches ________________________________________________________________________________________
@ -8744,6 +8749,9 @@ void DebuggerProcessKey( int keycode )
// Normally any key press takes us out of "Viewing Apple Output" g_nAppMode
// VK_F# are already processed, so we can't use them to cycle next video g_nAppMode
// if ((g_nAppMode != MODE_LOGO) && (g_nAppMode != MODE_DEBUG))
GetVideo().ClearSHRResidue(); // Clear the framebuffer to remove any SHR residue in the borders
DebugVideoMode::Instance().Reset();
UpdateDisplay( UPDATE_ALL ); // 1
return;

View File

@ -267,6 +267,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
{TEXT("DHGR") , CmdViewOutput_DHGRX , CMD_VIEW_DHGRX , "View Double Hi-res (current page)" },
{TEXT("DHGR1") , CmdViewOutput_DHGR1 , CMD_VIEW_DHGR1 , "View Double Hi-res Page 1" },
{TEXT("DHGR2") , CmdViewOutput_DHGR2 , CMD_VIEW_DHGR2 , "View Double Hi-res Page 2" },
{TEXT("SHR") , CmdViewOutput_SHR , CMD_VIEW_SHR , "View Super Hi-res" },
// Watch
{TEXT("W") , CmdWatch , CMD_WATCH , "Alias for WA (Watch Add)" },
{TEXT("WA") , CmdWatchAdd , CMD_WATCH_ADD , "Add/Update address or symbol to watch" },

View File

@ -639,8 +639,8 @@ void StretchBltMemToFrameDC(void)
int nViewportCX, nViewportCY;
win32Frame.GetViewportCXCY(nViewportCX, nViewportCY);
int xdest = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetX() : 0;
int ydest = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetY() : 0;
int xdest = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetX() : GetVideo().GetFrameBufferCentringOffsetX() * win32Frame.GetViewportScale();
int ydest = win32Frame.IsFullScreen() ? win32Frame.GetFullScreenOffsetY() : GetVideo().GetFrameBufferCentringOffsetY() * win32Frame.GetViewportScale();
int wdest = nViewportCX;
int hdest = nViewportCY;
@ -738,6 +738,7 @@ static void PrintGlyph( const int xDst, const int yDst, const int glyph )
// Manual print of character. A lot faster than BitBlt, which must be avoided.
int index_src = (CONSOLE_FONT_BITMAP_HEIGHT - 1 - ySrc) * CONSOLE_FONT_NUM_CHARS_PER_ROW * CONSOLE_FONT_GRID_X + xSrc; // font bitmap
int index_dst = (DISPLAY_HEIGHT - 1 - yDst) * DEBUG_VIRTUAL_TEXT_WIDTH * CONSOLE_FONT_GRID_X + xDst; // debugger bitmap
for (int yy = 0; yy < CONSOLE_FONT_GRID_Y; yy++)
{
for (int xx = 0; xx < CONSOLE_FONT_GRID_X; xx++)

View File

@ -509,6 +509,7 @@
, CMD_VIEW_DHGRX
, CMD_VIEW_DHGR1
, CMD_VIEW_DHGR2
, CMD_VIEW_SHR
// Watch
, CMD_WATCH // TODO: Deprecated ?
, CMD_WATCH_ADD
@ -770,6 +771,7 @@
Update_t CmdViewOutput_DHGRX (int nArgs);
Update_t CmdViewOutput_DHGR1 (int nArgs);
Update_t CmdViewOutput_DHGR2 (int nArgs);
Update_t CmdViewOutput_SHR (int nArgs);
// Watch
Update_t CmdWatch (int nArgs);
Update_t CmdWatchAdd (int nArgs);

View File

@ -15,7 +15,7 @@ public:
BOOL g_bMultiMon;
bool g_bFreshReset;
virtual void Initialize(void) = 0;
virtual void Initialize(bool resetVideoState) = 0;
virtual void Destroy(void) = 0;
virtual void FrameDrawDiskLEDS() = 0;
@ -26,13 +26,14 @@ public:
virtual void FrameSetCursorPosByMousePos() = 0;
virtual void SetFullScreenShowSubunitStatus(bool bShow) = 0;
virtual bool GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedHeight = 0) = 0;
virtual bool GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedWidth=0, UINT userSpecifiedHeight=0) = 0;
virtual int SetViewportScale(int nNewScale, bool bForce = false) = 0;
virtual void SetAltEnterToggleFullScreen(bool mode) = 0;
virtual void SetLoadedSaveStateFlag(const bool bFlag) = 0;
virtual void VideoPresentScreen(void) = 0;
virtual void ResizeWindow(void) = 0;
// this function has the same interface as MessageBox in windows.h
virtual int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType) = 0;

View File

@ -518,6 +518,11 @@ BYTE __stdcall HarddiskInterfaceCard::IORead(WORD pc, WORD addr, BYTE bWrite, BY
{
memdirty[dstAddr >> 8] = 0xFF;
LPBYTE page = memwrite[dstAddr >> 8];
if (!page)
{
_ASSERT(0);
break;
}
// handle both page-aligned & non-page aligned destinations
UINT size = PAGE_SIZE - (dstAddr & 0xff);

View File

@ -122,6 +122,10 @@ VIDEO SOFT SWITCHES
$C00D W 80COLON Turn on 80 column display
$C00E W ALTCHARSETOFF Turn off alternate characters
$C00F W ALTCHARSETON Turn on alternate characters
$C022 R/W SCREENCOLOR [IIgs] text foreground and background colors (also VidHD)
$C029 R/W NEWVIDEO [IIgs] Select new video modes (also VidHD)
$C034 R/W BORDERCOLOR [IIgs] b3:0 are border color (also VidHD)
$C035 R/W SHADOW [IIgs] auxmem-to-bank-E1 shadowing (also VidHD)
$C050 R/W TEXTOFF Select graphics mode
$C051 R/W TEXTON Select text mode
$C052 R/W MIXEDOFF Use full screen for graphics
@ -470,6 +474,12 @@ static BYTE __stdcall IORead_C02x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
static BYTE __stdcall IOWrite_C02x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
{
if (addr == 0xC022 || addr == 0xC029)
GetVideo().VideoSetMode(pc, addr, bWrite, d, nExecutedCycles);
}
return TapeWrite(pc, addr, bWrite, d, nExecutedCycles); // $C020 TAPEOUT
}
@ -482,6 +492,13 @@ static BYTE __stdcall IORead_C03x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG
static BYTE __stdcall IOWrite_C03x(WORD pc, WORD addr, BYTE bWrite, BYTE d, ULONG nExecutedCycles)
{
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
{
// NB. Writes to $C03x addresses will still toggle the speaker, even with a VidHD present
if (addr == 0xC034 || addr == 0xC035)
GetVideo().VideoSetMode(pc, addr, bWrite, d, nExecutedCycles);
}
return SpkrToggle(pc, addr, bWrite, d, nExecutedCycles);
}

View File

@ -27,6 +27,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Memory.h" // MemGetMainPtr(), MemGetAuxPtr(), MemGetAnnunciator()
#include "Interface.h" // GetFrameBuffer()
#include "RGBMonitor.h"
#include "VidHD.h"
#include "NTSC_CharSet.h"
@ -100,11 +101,14 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define VIDEO_SCANNER_HORZ_START 25 // first displayable horz scanner index
#define VIDEO_SCANNER_Y_MIXED 160 // num scanlins for mixed graphics + text
#define VIDEO_SCANNER_Y_DISPLAY 192 // max displayable scanlines
#define VIDEO_SCANNER_Y_DISPLAY_IIGS 200
// these are initialized in NTSC_VideoInit
// These 3 vars are initialized in NTSC_VideoInit()
static bgra_t* g_pVideoAddress = 0;
static bgra_t *g_pScanLines[VIDEO_SCANNER_Y_DISPLAY*2]; // To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
static UINT g_kFrameBufferWidth;
// To maintain the 280x192 aspect ratio for 560px width, we double every scan line -> 560x384
// NB. For IIgs SHR, the 320x200 is again doubled (to 640x400), but this gives a ~16:9 ratio, when 4:3 is probably required (ie. stretch height from 200 to 240)
static bgra_t* g_pScanLines[VIDEO_SCANNER_Y_DISPLAY_IIGS * 2];
static UINT g_kFrameBufferWidth = 0;
static unsigned short (*g_pHorzClockOffset)[VIDEO_SCANNER_MAX_HORZ] = 0;
@ -348,6 +352,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
static void updateScreenText80RGB ( long cycles6502 );
static void updateScreenDoubleHires80Simplified(long cycles6502);
static void updateScreenDoubleHires80RGB(long cycles6502);
static void updateScreenSHR(long cycles6502);
//===========================================================================
static void set_csbits()
@ -712,13 +717,37 @@ inline void updateVideoScannerHorzEOL()
}
}
inline void updateVideoScannerHorzEOL_SHR()
{
if (VIDEO_SCANNER_MAX_HORZ == ++g_nVideoClockHorz)
{
g_nVideoClockHorz = 0;
if (++g_nVideoClockVert == g_videoScannerMaxVert)
{
g_nVideoClockVert = 0;
}
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS)
{
updateVideoScannerAddress();
}
}
}
//===========================================================================
inline void updateVideoScannerAddress()
{
if (g_nVideoMixed && g_nVideoClockVert >= VIDEO_SCANNER_Y_MIXED && GetVideo().GetVideoRefreshRate() == VR_50HZ) // GH#763
g_nColorBurstPixels = 0; // instantaneously kill color-burst!
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2*g_nVideoClockVert] : g_pScanLines[0];
if (g_pFuncUpdateGraphicsScreen == updateScreenSHR)
{
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS ? g_pScanLines[2 * g_nVideoClockVert] : g_pScanLines[0];
return;
}
g_pVideoAddress = g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY ? g_pScanLines[2 * g_nVideoClockVert] : g_pScanLines[0];
// Adjust, as these video styles have 2x 14M pixels of pre-render
// NB. For VT_COLOR_MONITOR_NTSC, also check color-burst so that TEXT and MIXED(HGR+TEXT) render the TEXT at the same offset (GH#341)
@ -740,6 +769,9 @@ inline void updateVideoScannerAddress()
g_pVideoAddress -= 1;
}
// Centre the older //e video modes when running with a VidHD
g_pVideoAddress += GetVideo().GetFrameBufferCentringValue();
g_nColorPhaseNTSC = INITIAL_COLOR_PHASE;
g_nLastColumnPixelNTSC = 0;
g_nSignalBitsNTSC = 0;
@ -760,7 +792,6 @@ INLINE uint16_t getVideoScannerAddressHGR()
APPLE_IIE_HORZ_CLOCK_OFFSET[g_nVideoClockVert/64][g_nVideoClockHorz] + (g_nHiresPage * 0x2000));
}
// Non-Inline _________________________________________________________
// Build the 4 phase chroma lookup table
@ -1709,6 +1740,42 @@ void updateScreenText80RGB(long cycles6502)
}
}
//===========================================================================
void updateScreenSHR(long cycles6502)
{
for (; cycles6502 > 0; --cycles6502)
{
// 2 pixels per byte in 320-pixel mode = 160 bytes/scanline
// 4 pixels per byte in 640-pixel mode = 160 bytes/scanline
const UINT kBytesPerScanline = 160;
const UINT kBytesPerCycle = 4;
uint16_t addr = 0x2000 + kBytesPerScanline * g_nVideoClockVert + kBytesPerCycle * (g_nVideoClockHorz - VIDEO_SCANNER_HORZ_START);
if (g_nVideoClockVert < VIDEO_SCANNER_Y_DISPLAY_IIGS)
{
if (g_nVideoClockHorz >= VIDEO_SCANNER_HORZ_START)
{
uint32_t* pAux = (uint32_t*) MemGetAuxPtr(addr); // 8 pixels (320 mode) / 16 pixels (640 mode)
uint32_t a = pAux[0];
uint8_t* pControl = MemGetAuxPtr(0x9D00 + g_nVideoClockVert); // scan-line control byte
uint8_t c = pControl[0];
bool is640Mode = c & 0x80;
bool isColorFillMode = c & 0x20;
UINT paletteSelectCode = c & 0xf;
const UINT kColorsPerPalette = 16;
const UINT kColorSize = 2;
uint16_t addrPalette = 0x9E00 + paletteSelectCode * kColorsPerPalette * kColorSize;
VidHDCard::UpdateSHRCell(is640Mode, isColorFillMode, addrPalette, g_pVideoAddress, a);
g_pVideoAddress += 16;
}
}
updateVideoScannerHorzEOL_SHR();
}
}
// Functions (Public) _____________________________________________________________________________
//===========================================================================
@ -1803,6 +1870,19 @@ void NTSC_SetVideoTextMode( int cols )
//===========================================================================
void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
{
if (uVideoModeFlags & VF_SHR)
{
g_pFuncUpdateGraphicsScreen = updateScreenSHR;
g_pFuncUpdateTextScreen = updateScreenSHR;
return;
}
if (g_pFuncUpdateGraphicsScreen == updateScreenSHR && !(uVideoModeFlags & VF_SHR))
{
// Was SHR mode, so clear the framebuffer to remove any SHR residue in the borders
GetVideo().ClearFrameBuffer();
}
if (bDelay && !g_bFullSpeed)
{
// (GH#670) NB. if g_bFullSpeed then NTSC_VideoUpdateCycles() won't be called on the next 6502 opcode.
@ -1812,7 +1892,6 @@ void NTSC_SetVideoMode( uint32_t uVideoModeFlags, bool bDelay/*=false*/ )
return;
}
g_nVideoMixed = uVideoModeFlags & VF_MIXED;
g_nVideoCharSet = GetVideo().VideoGetSWAltCharSet() ? 1 : 0;
@ -2104,7 +2183,7 @@ void NTSC_VideoInit( uint8_t* pFramebuffer ) // wsVideoInit
g_kFrameBufferWidth = GetVideo().GetFrameBufferWidth();
for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY*2); y++)
for (int y = 0; y < (VIDEO_SCANNER_Y_DISPLAY_IIGS*2); y++)
{
uint32_t offset = sizeof(bgra_t) * GetVideo().GetFrameBufferWidth()
* ((GetVideo().GetFrameBufferHeight() - 1) - y - GetVideo().GetFrameBufferBorderHeight())

View File

@ -50,6 +50,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "SNESMAX.h"
#include "Speaker.h"
#include "Speech.h"
#include "VidHD.h"
#include "z80emu.h"
#include "Configuration/Config.h"
@ -288,10 +289,6 @@ static void ParseUnitApple2(YamlLoadHelper& yamlLoadHelper, UINT version)
SpkrLoadSnapshot(yamlLoadHelper);
GetVideo().VideoLoadSnapshot(yamlLoadHelper, version);
MemLoadSnapshot(yamlLoadHelper, version);
// g_Apple2Type may've changed: so redraw frame (title, buttons, leds, etc)
GetVideo().VideoReinitialize(true); // g_CharsetType changed
GetFrame().FrameUpdateApple2Type(); // Calls VideoRedrawScreen() before the aux mem has been loaded (so if DHGR is enabled, then aux mem will be zeros at this stage)
}
//---
@ -381,6 +378,10 @@ static void ParseSlots(YamlLoadHelper& yamlLoadHelper, UINT unitVersion)
{
type = CT_SNESMAX;
}
else if (card == VidHDCard::GetSnapshotCardName())
{
type = CT_VidHD;
}
else
{
throw std::string("Slots: Unknown card: " + card); // todo: don't throw - just ignore & continue
@ -482,6 +483,7 @@ static void Snapshot_LoadState_v2(void)
GetPravets().Reset();
KeybReset();
GetVideo().SetVidHD(false); // Set true later only if VidHDCard is instantiated
GetVideo().VideoResetState();
GetVideo().SetVideoRefreshRate(VR_60HZ); // Default to 60Hz as older save-states won't contain refresh rate
MB_InitializeForLoadingSnapshot(); // GH#609
@ -520,6 +522,12 @@ static void Snapshot_LoadState_v2(void)
DebugReset();
if (g_nAppMode == MODE_DEBUG)
DebugDisplay(TRUE);
frame.Initialize(false); // don't reset the video state
frame.ResizeWindow();
// g_Apple2Type may've changed: so reload button bitmaps & redraw frame (title, buttons, leds, etc)
frame.FrameUpdateApple2Type(); // NB. Calls VideoRedrawScreen()
}
catch(std::string szMessage)
{

View File

@ -541,6 +541,8 @@ void ResetMachineState()
GetCardMgr().GetDisk2CardMgr().Reset(true);
if (GetCardMgr().QuerySlot(SLOT7) == CT_GenericHDD)
GetCardMgr().GetRef(SLOT7).Reset(true);
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
GetCardMgr().GetRef(SLOT3).Reset(true);
g_bFullSpeed = 0; // Might've hit reset in middle of InternalCpuExecute() - so beep may get (partially) muted
MemReset(); // calls CpuInitialize(), CNoSlotClock.Reset()
@ -595,7 +597,9 @@ void CtrlReset()
GetPravets().Reset();
GetCardMgr().GetDisk2CardMgr().Reset();
if (GetCardMgr().QuerySlot(SLOT7) == CT_GenericHDD)
GetCardMgr().GetRef(SLOT7).Reset(true);
GetCardMgr().GetRef(SLOT7).Reset(false);
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
GetCardMgr().GetRef(SLOT3).Reset(false);
KeybReset();
if (GetCardMgr().IsSSCInstalled())
GetCardMgr().GetSSC()->CommReset();

189
source/VidHD.cpp Normal file
View File

@ -0,0 +1,189 @@
/*
AppleWin : An Apple //e emulator for Windows
Copyright (C) 1994-1996, Michael O'Brien
Copyright (C) 1999-2001, Oliver Schmidt
Copyright (C) 2002-2005, Tom Charlesworth
Copyright (C) 2006-2021, Tom Charlesworth, Michael Pohoreski
AppleWin 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.
AppleWin 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 AppleWin; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
Emulate a VidHD card (Blue Shift Inc)
Allows any Apple II to support the IIgs' 320x200 and 640x200 256-colour Super High-Res video modes.
Currently only a //e with 64K aux memory supports SHR mode.
NB. The extended text modes 80x45, 120x67, 240x135 (and setting FG/BG colours) are not supported yet.
*/
#include "StdAfx.h"
#include "Memory.h"
#include "NTSC.h"
#include "Video.h"
#include "VidHD.h"
#include "YamlHelper.h"
void VidHDCard::Reset(const bool powerCycle)
{
m_NEWVIDEO = 0;
GetVideo().SetVideoMode(GetVideo().GetVideoMode() & ~VF_SHR);
}
void VidHDCard::InitializeIO(LPBYTE pCxRomPeripheral)
{
RegisterIoHandler(m_slot, IO_Null, IO_Null, &VidHDCard::IORead, IO_Null, this, NULL);
}
BYTE __stdcall VidHDCard::IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
// Return magic bytes (from the VidHD firmware) for VidHD detection
switch (addr & 0xff)
{
case 0: return 0x24;
case 1: return 0xEA;
case 2: return 0x4C;
}
return IO_Null(pc, addr, bWrite, value, nExecutedCycles);
}
// NB. VidHD has no support for reading the IIgs video registers (from an earlier Apple II)
void VidHDCard::VideoIOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles)
{
switch (addr & 0xff)
{
case 0x22: // SCREENCOLOR
m_SCREENCOLOR = value;
break;
case 0x29: // NEWVIDEO
m_NEWVIDEO = value;
break;
case 0x34: // BORDERCOLOR
m_BORDERCOLOR = value;
break;
case 0x35: // SHADOW
m_SHADOW = value;
break;
default:
_ASSERT(0);
}
}
//===========================================================================
#pragma pack(push)
#pragma pack(1) // Ensure struct is packed
struct Color
{
USHORT blue : 4;
USHORT green : 4;
USHORT red : 4;
USHORT reserved : 4;
};
#pragma pack(pop)
bgra_t ConvertIIgs2RGB(Color color)
{
bgra_t rgb = { 0 };
rgb.r = color.red * 16;
rgb.g = color.green * 16;
rgb.b = color.blue * 16;
return rgb;
}
void VidHDCard::UpdateSHRCell(bool is640Mode, bool isColorFillMode, uint16_t addrPalette, bgra_t* pVideoAddress, uint32_t a)
{
_ASSERT(!is640Mode); // to do: test this mode
Color* palette = (Color*) MemGetAuxPtr(addrPalette);
for (UINT i = 0; i < 4; i++)
{
if (!is640Mode) // 320 mode
{
BYTE pixel1 = (a >> 4) & 0xf;
bgra_t color1 = ConvertIIgs2RGB(palette[pixel1]);
if (isColorFillMode && pixel1 == 0) color1 = *(pVideoAddress - 1);
*pVideoAddress++ = color1;
*pVideoAddress++ = color1;
BYTE pixel2 = a & 0xf;
bgra_t color2 = ConvertIIgs2RGB(palette[pixel2]);
if (isColorFillMode && pixel2 == 0) color2 = color1;
*pVideoAddress++ = color2;
*pVideoAddress++ = color2;
}
else // 640 mode - see IIgs Hardware Ref, Pg.96, Table4-21 'Color Selection in 640 mode'
{
BYTE pixel1 = (a >> 6) & 0x3;
bgra_t color1 = ConvertIIgs2RGB(palette[0x8 + pixel1]);
*pVideoAddress++ = color1;
BYTE pixel2 = (a >> 4) & 0x3;
bgra_t color2 = ConvertIIgs2RGB(palette[0xC + pixel2]);
*pVideoAddress++ = color2;
BYTE pixel3 = (a >> 2) & 0x3;
bgra_t color3 = ConvertIIgs2RGB(palette[0x0 + pixel3]);
*pVideoAddress++ = color3;
BYTE pixel4 = a & 0x3;
bgra_t color4 = ConvertIIgs2RGB(palette[0x4 + pixel4]);
*pVideoAddress++ = color4;
}
a >>= 8;
}
}
//===========================================================================
static const UINT kUNIT_VERSION = 1;
#define SS_YAML_KEY_SCREEN_COLOR "Screen Color"
#define SS_YAML_KEY_NEW_VIDEO "New Video"
#define SS_YAML_KEY_BORDER_COLOR "Border Color"
#define SS_YAML_KEY_SHADOW "Shadow"
std::string VidHDCard::GetSnapshotCardName(void)
{
static const std::string name("VidHD");
return name;
}
void VidHDCard::SaveSnapshot(YamlSaveHelper& yamlSaveHelper)
{
YamlSaveHelper::Slot slot(yamlSaveHelper, GetSnapshotCardName(), m_slot, kUNIT_VERSION);
YamlSaveHelper::Label unit(yamlSaveHelper, "%s:\n", SS_YAML_KEY_STATE);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SCREEN_COLOR, m_SCREENCOLOR);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_NEW_VIDEO, m_NEWVIDEO);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_BORDER_COLOR, m_BORDERCOLOR);
yamlSaveHelper.SaveHexUint8(SS_YAML_KEY_SHADOW, m_SHADOW);
}
bool VidHDCard::LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version)
{
if (version < 1 || version > kUNIT_VERSION)
throw std::string("Card: wrong version");
m_SCREENCOLOR = yamlLoadHelper.LoadUint(SS_YAML_KEY_SCREEN_COLOR);
m_NEWVIDEO = yamlLoadHelper.LoadUint(SS_YAML_KEY_NEW_VIDEO);
m_BORDERCOLOR = yamlLoadHelper.LoadUint(SS_YAML_KEY_BORDER_COLOR);
m_SHADOW = yamlLoadHelper.LoadUint(SS_YAML_KEY_SHADOW);
return true;
}

44
source/VidHD.h Normal file
View File

@ -0,0 +1,44 @@
#pragma once
#include "Card.h"
#include "Interface.h"
class VidHDCard : public Card
{
public:
VidHDCard(UINT slot) :
Card(CT_VidHD, slot)
{
m_SCREENCOLOR = 0;
m_NEWVIDEO = 0;
m_BORDERCOLOR = 0;
m_SHADOW = 0;
GetVideo().SetVidHD(true);
}
virtual ~VidHDCard(void) {}
virtual void Init(void) {}
virtual void Reset(const bool powerCycle);
virtual void Update(const ULONG nExecutedCycles) {}
virtual void InitializeIO(LPBYTE pCxRomPeripheral);
static BYTE __stdcall IORead(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
void VideoIOWrite(WORD pc, WORD addr, BYTE bWrite, BYTE value, ULONG nExecutedCycles);
bool IsSHR(void) { return (m_NEWVIDEO & 0xC0) == 0xC0; } // 11000001 = Enable SHR(b7) | Linearize SHR video memory(b6)
bool IsDHGRBlackAndWhite(void) { return (m_NEWVIDEO & (1 << 5)) ? true : false; }
static void UpdateSHRCell(bool is640Mode, bool isColorFillMode, uint16_t addrPalette, bgra_t* pVideoAddress, uint32_t a);
static std::string GetSnapshotCardName(void);
virtual void SaveSnapshot(YamlSaveHelper& yamlSaveHelper);
virtual bool LoadSnapshot(YamlLoadHelper& yamlLoadHelper, UINT version);
private:
BYTE m_SCREENCOLOR;
BYTE m_NEWVIDEO;
BYTE m_BORDERCOLOR;
BYTE m_SHADOW;
};

View File

@ -29,6 +29,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "StdAfx.h"
#include "Video.h"
#include "CardManager.h"
#include "Core.h"
#include "CPU.h"
#include "Log.h"
@ -36,6 +37,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#include "Registry.h"
#include "NTSC.h"
#include "RGBMonitor.h"
#include "VidHD.h"
#include "YamlHelper.h"
#define SW_80COL (g_uVideoMode & VF_80COL)
@ -45,6 +47,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#define SW_MIXED (g_uVideoMode & VF_MIXED)
#define SW_PAGE2 (g_uVideoMode & VF_PAGE2)
#define SW_TEXT (g_uVideoMode & VF_TEXT)
#define SW_SHR (g_uVideoMode & VF_SHR)
//-------------------------------------
@ -91,14 +94,12 @@ const char* const Video::g_apVideoModeDesc[NUM_VIDEO_MODES] =
UINT Video::GetFrameBufferBorderlessWidth(void)
{
static const UINT uFrameBufferBorderlessW = 560; // 560 = Double Hi-Res
return uFrameBufferBorderlessW;
return HasVidHD() ? kVideoWidthIIgs : kVideoWidthII;
}
UINT Video::GetFrameBufferBorderlessHeight(void)
{
static const UINT uFrameBufferBorderlessH = 384; // 384 = Double Scan Line
return uFrameBufferBorderlessH;
return HasVidHD() ? kVideoHeightIIgs : kVideoHeightII;
}
// NB. These border areas are not visible (... and these border areas are unrelated to the 3D border below)
@ -124,6 +125,29 @@ UINT Video::GetFrameBufferHeight(void)
return GetFrameBufferBorderlessHeight() + 2 * GetFrameBufferBorderHeight();
}
UINT Video::GetFrameBufferCentringOffsetX(void)
{
return HasVidHD() ? ((kVideoWidthIIgs - kVideoWidthII) / 2) : 0;
}
UINT Video::GetFrameBufferCentringOffsetY(void)
{
return HasVidHD() ? ((kVideoHeightIIgs - kVideoHeightII) / 2) : 0;
}
int Video::GetFrameBufferCentringValue(void)
{
int value = 0;
if (HasVidHD())
{
value -= GetFrameBufferCentringOffsetY() * GetFrameBufferWidth();
value += GetFrameBufferCentringOffsetX();
}
return value;
}
//===========================================================================
void Video::VideoReinitialize(bool bInitVideoScannerAddress)
@ -151,12 +175,15 @@ void Video::VideoResetState(void)
//===========================================================================
BYTE Video::VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCycles)
BYTE Video::VideoSetMode(WORD pc, WORD address, BYTE write, BYTE d, ULONG uExecutedCycles)
{
address &= 0xFF;
const uint32_t oldVideoMode = g_uVideoMode;
VidHDCard* vidHD = NULL;
if (GetCardMgr().QuerySlot(SLOT3) == CT_VidHD)
vidHD = dynamic_cast<VidHDCard*>(GetCardMgr().GetObj(SLOT3));
address &= 0xFF;
switch (address)
{
case 0x00: g_uVideoMode &= ~VF_80STORE; break;
@ -165,6 +192,10 @@ BYTE Video::VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCy
case 0x0D: if (!IS_APPLE2){g_uVideoMode |= VF_80COL; NTSC_SetVideoTextMode(80);}; break;
case 0x0E: if (!IS_APPLE2) g_nAltCharSetOffset = 0; break; // Alternate char set off
case 0x0F: if (!IS_APPLE2) g_nAltCharSetOffset = 256; break; // Alternate char set on
case 0x22: if (vidHD) vidHD->VideoIOWrite(pc, address, write, d, uExecutedCycles); break; // VidHD IIgs video mode register
case 0x29: if (vidHD) vidHD->VideoIOWrite(pc, address, write, d, uExecutedCycles); break; // VidHD IIgs video mode register
case 0x34: if (vidHD) vidHD->VideoIOWrite(pc, address, write, d, uExecutedCycles); break; // VidHD IIgs video mode register
case 0x35: if (vidHD) vidHD->VideoIOWrite(pc, address, write, d, uExecutedCycles); break; // VidHD IIgs video mode register
case 0x50: g_uVideoMode &= ~VF_TEXT; break;
case 0x51: g_uVideoMode |= VF_TEXT; break;
case 0x52: g_uVideoMode &= ~VF_MIXED; break;
@ -177,6 +208,11 @@ BYTE Video::VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCy
case 0x5F: if (!IS_APPLE2) g_uVideoMode &= ~VF_DHIRES; break;
}
if (vidHD && vidHD->IsSHR())
g_uVideoMode |= VF_SHR;
else
g_uVideoMode &= ~VF_SHR;
if (!IS_APPLE2)
RGB_SetVideoMode(address);
@ -185,7 +221,7 @@ BYTE Video::VideoSetMode(WORD, WORD address, BYTE write, BYTE, ULONG uExecutedCy
if ((oldVideoMode ^ g_uVideoMode) & (VF_TEXT|VF_MIXED))
delay = true;
NTSC_SetVideoMode( g_uVideoMode, delay );
NTSC_SetVideoMode(g_uVideoMode, delay);
return MemReadFloatingBus(uExecutedCycles);
}
@ -754,16 +790,18 @@ const char* Video::VideoGetAppWindowTitle(void)
return apVideoMonitorModeDesc[ GetVideoRefreshRate() == VR_60HZ ? 0 : 1 ]; // NTSC or PAL
}
void Video::Initialize(uint8_t* frameBuffer)
void Video::Initialize(uint8_t* frameBuffer, bool resetState)
{
SetFrameBuffer(frameBuffer);
// RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET
VideoResetState();
if (resetState)
{
// RESET THE VIDEO MODE SWITCHES AND THE CHARACTER SET OFFSET
VideoResetState();
}
// DRAW THE SOURCE IMAGE INTO THE SOURCE BIT BUFFER
memset(GetFrameBuffer(), 0, GetFrameBufferWidth() * GetFrameBufferHeight() * sizeof(bgra_t));
ClearFrameBuffer();
// CREATE THE OFFSET TABLE FOR EACH SCAN LINE IN THE FRAME BUFFER
NTSC_VideoInit(GetFrameBuffer());
@ -796,3 +834,15 @@ void Video::VideoRefreshBuffer(uint32_t uRedrawWholeScreenVideoMode, bool bRedra
NTSC_VideoRedrawWholeScreen();
}
}
void Video::ClearFrameBuffer(void)
{
memset(GetFrameBuffer(), 0, GetFrameBufferWidth() * GetFrameBufferHeight() * sizeof(bgra_t));
}
// Called when entering debugger, and after viewing Apple II video screen from debugger
void Video::ClearSHRResidue(void)
{
ClearFrameBuffer();
GetFrame().VideoPresentScreen();
}

View File

@ -55,7 +55,8 @@ enum VideoFlag_e
VF_80STORE= 0x00000008,
VF_MIXED = 0x00000010,
VF_PAGE2 = 0x00000020,
VF_TEXT = 0x00000040
VF_TEXT = 0x00000040,
VF_SHR = 0x00000080 // For VidHD's support for IIgs SHR video modes
};
enum AppleFont_e
@ -193,9 +194,12 @@ public:
g_nMonochromeRGB = RGB(0xC0,0xC0,0xC0);
g_videoRomSize = 0;
g_videoRomRockerSwitch = false;
m_hasVidHD = false;
}
void Initialize(uint8_t* frameBuffer); // Do not call directly. Call FrameBase::Initialize()
~Video(void){}
void Initialize(uint8_t* frameBuffer, bool resetState); // Do not call directly. Call FrameBase::Initialize()
void Destroy(void); // Call FrameBase::Destroy()
uint8_t* GetFrameBuffer(void) { return g_pFramebufferbits; }
@ -207,6 +211,9 @@ public:
UINT GetFrameBufferBorderHeight(void);
UINT GetFrameBufferWidth(void);
UINT GetFrameBufferHeight(void);
UINT GetFrameBufferCentringOffsetX(void);
UINT GetFrameBufferCentringOffsetY(void);
int GetFrameBufferCentringValue(void);
COLORREF GetMonochromeRGB(void) { return g_nMonochromeRGB; }
void SetMonochromeRGB(COLORREF colorRef) { g_nMonochromeRGB = colorRef; }
@ -214,6 +221,8 @@ public:
void VideoReinitialize(bool bInitVideoScannerAddress);
void VideoResetState(void);
void VideoRefreshBuffer(uint32_t uRedrawWholeScreenVideoMode, bool bRedrawWholeScreen);
void ClearFrameBuffer(void);
void ClearSHRResidue(void);
enum VideoScanner_e {VS_FullAddr, VS_PartialAddrV, VS_PartialAddrH};
WORD VideoGetScannerAddress(DWORD nCycles, VideoScanner_e videoScannerAddr = VS_FullAddr);
@ -268,6 +277,9 @@ public:
const char* VideoGetAppWindowTitle(void);
const char* GetVideoChoices(void) { return g_aVideoChoices; }
bool HasVidHD(void) { return m_hasVidHD; }
void SetVidHD(bool hasVidHD) { m_hasVidHD = hasVidHD; }
static const UINT kVideoRomSize2K = 1024*2;
static const UINT kVideoRomSize4K = kVideoRomSize2K*2;
@ -275,7 +287,6 @@ protected:
uint8_t *g_pFramebufferbits;
private:
void SetFrameBuffer(uint8_t* frameBuffer) { g_pFramebufferbits = frameBuffer; }
std::string VideoGetSnapshotStructName(void);
@ -285,6 +296,7 @@ private:
VideoStyle_e g_eVideoStyle;
bool g_bVideoScannerNTSC; // NTSC video scanning (or PAL)
COLORREF g_nMonochromeRGB; // saved to Registry
bool m_hasVidHD;
WinBmpHeader_t g_tBmpHeader;
@ -309,4 +321,10 @@ private:
static const char m_szModeDesc7[];
static const char m_szModeDesc8[];
static const char* const g_apVideoModeDesc[NUM_VIDEO_MODES];
static const UINT kVideoHeightII = 192*2;
static const UINT kVideoHeightIIgs = 200*2;
static const UINT kVideoWidthII = 280*2;
static const UINT kVideoWidthIIgs = 320*2;
};

View File

@ -667,6 +667,7 @@ static void OneTimeInitialization(HINSTANCE passinstance)
// DO INITIALIZATION THAT MUST BE REPEATED FOR A RESTART
static void RepeatInitialization(void)
{
GetVideo().SetVidHD(false); // Set true later only if VidHDCard is instantiated
ResetToLogoMode();
// NB. g_OldAppleWinVersion needed by LoadConfiguration() -> Config_Load_Video()
@ -731,13 +732,6 @@ static void RepeatInitialization(void)
JoyInitialize();
LogFileOutput("Main: JoyInitialize()\n");
GetFrame().Initialize(); // g_pFramebufferinfo been created now & COM init'ed
LogFileOutput("Main: VideoInitialize()\n");
LogFileOutput("Main: FrameCreateWindow() - pre\n");
Win32Frame::GetWin32Frame().FrameCreateWindow(); // GetFrame().g_hFrameWindow is now valid
LogFileOutput("Main: FrameCreateWindow() - post\n");
// Init palette color
VideoSwitchVideocardPalette(RGB_GetVideocard(), GetVideo().GetVideoType());
@ -753,6 +747,11 @@ static void RepeatInitialization(void)
if (g_cmdLine.bSlotEmpty[SLOT6])
GetCardMgr().Remove(SLOT6);
if (g_cmdLine.slotInsert[SLOT3] != CT_Empty && g_cmdLine.slotInsert[SLOT3] == CT_VidHD) // For now just support VidHD in slot 3
{
GetCardMgr().Insert(SLOT3, g_cmdLine.slotInsert[SLOT3]);
}
if (g_cmdLine.slotInsert[SLOT5] != CT_Empty)
{
if (GetCardMgr().QuerySlot(SLOT4) == CT_MockingboardC && g_cmdLine.slotInsert[SLOT5] != CT_MockingboardC) // Currently MB occupies slot4+5 when enabled
@ -764,6 +763,35 @@ static void RepeatInitialization(void)
GetCardMgr().Insert(SLOT5, g_cmdLine.slotInsert[SLOT5]);
}
// Create window after inserting/removing VidHD card (as it affects width & height)
{
Win32Frame::GetWin32Frame().SetViewportScale(Win32Frame::GetWin32Frame().GetViewportScale(), true);
GetFrame().Initialize(true); // g_pFramebufferinfo been created now & COM init'ed
LogFileOutput("Main: VideoInitialize()\n");
LogFileOutput("Main: FrameCreateWindow() - pre\n");
Win32Frame::GetWin32Frame().FrameCreateWindow(); // GetFrame().g_hFrameWindow is now valid
LogFileOutput("Main: FrameCreateWindow() - post\n");
}
// Set best W,H resolution after inserting/removing VidHD card
if (g_cmdLine.bestFullScreenResolution || g_cmdLine.userSpecifiedWidth || g_cmdLine.userSpecifiedHeight)
{
bool res = false;
UINT bestWidth = 0, bestHeight = 0;
if (g_cmdLine.bestFullScreenResolution)
res = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight);
else
res = GetFrame().GetBestDisplayResolutionForFullScreen(bestWidth, bestHeight, g_cmdLine.userSpecifiedWidth, g_cmdLine.userSpecifiedHeight);
if (res)
LogFileOutput("Best resolution for -fs-height/height=x switch(es): Width=%d, Height=%d\n", bestWidth, bestHeight);
else
LogFileOutput("Failed to set parameter for -fs-width/height=x switch(es)\n");
}
// Pre: may need g_hFrameWindow for MessageBox errors
// Post: may enable HDD, required for MemInitialize()->MemInitializeIO()
{

View File

@ -33,16 +33,12 @@ Win32Frame::Win32Frame()
g_bFrameActive = false;
g_windowMinimized = false;
g_bFullScreen_ShowSubunitStatus = true;
g_win_fullscreen_scale = 1;
g_win_fullscreen_offsetx = 0;
g_win_fullscreen_offsety = 0;
m_bestWidthForFullScreen = 0;
m_bestHeightForFullScreen = 0;
m_changedDisplaySettings = false;
g_nViewportCX = GetVideo().GetFrameBufferBorderlessWidth() * kDEFAULT_VIEWPORT_SCALE;
g_nViewportCY = GetVideo().GetFrameBufferBorderlessHeight() * kDEFAULT_VIEWPORT_SCALE;
g_nViewportScale = kDEFAULT_VIEWPORT_SCALE; // saved REGSAVE
g_nMaxViewportScale = kDEFAULT_VIEWPORT_SCALE; // Max scale in Windowed mode with borders, buttons etc (full-screen may be +1)
btnfacebrush = (HBRUSH)0;
@ -52,8 +48,6 @@ Win32Frame::Win32Frame()
buttonactive = -1;
buttondown = -1;
buttonover = -1;
buttonx = BUTTONX; // NB. macro uses g_nViewportCX
buttony = BUTTONY;
g_hFrameDC = (HDC)0;
memset(&framerect, 0, sizeof(framerect));
@ -76,9 +70,12 @@ Win32Frame::Win32Frame()
g_eStatusDrive1 = DISK_STATUS_OFF;
g_eStatusDrive2 = DISK_STATUS_OFF;
// Set g_nViewportScale, g_nViewportCX, g_nViewportCY & buttonx, buttony
SetViewportScale(kDEFAULT_VIEWPORT_SCALE, true);
}
void Win32Frame::videoCreateDIBSection(Video & video)
void Win32Frame::VideoCreateDIBSection(bool resetVideoState)
{
// CREATE THE DEVICE CONTEXT
HWND window = GetDesktopWindow();
@ -91,7 +88,10 @@ void Win32Frame::videoCreateDIBSection(Video & video)
// CREATE THE FRAME BUFFER DIB SECTION
if (g_hDeviceBitmap)
{
DeleteObject(g_hDeviceBitmap);
GetVideo().Destroy();
}
uint8_t* pFramebufferbits;
@ -102,29 +102,33 @@ void Win32Frame::videoCreateDIBSection(Video & video)
(LPVOID*)&pFramebufferbits, 0, 0
);
SelectObject(g_hDeviceDC, g_hDeviceBitmap);
video.Initialize(pFramebufferbits);
GetVideo().Initialize(pFramebufferbits, resetVideoState);
}
void Win32Frame::Initialize(void)
void Win32Frame::Initialize(bool resetVideoState)
{
// LOAD THE LOGO
g_hLogoBitmap = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN));
if (g_hLogoBitmap == NULL)
{
// LOAD THE LOGO
g_hLogoBitmap = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN));
}
if (g_pFramebufferinfo)
delete[] g_pFramebufferinfo;
// CREATE A BITMAPINFO STRUCTURE FOR THE FRAME BUFFER
g_pFramebufferinfo = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD)];
Video & video = GetVideo();
memset(g_pFramebufferinfo, 0, sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD));
g_pFramebufferinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
g_pFramebufferinfo->bmiHeader.biWidth = video.GetFrameBufferWidth();
g_pFramebufferinfo->bmiHeader.biHeight = video.GetFrameBufferHeight();
g_pFramebufferinfo->bmiHeader.biWidth = GetVideo().GetFrameBufferWidth();
g_pFramebufferinfo->bmiHeader.biHeight = GetVideo().GetFrameBufferHeight();
g_pFramebufferinfo->bmiHeader.biPlanes = 1;
g_pFramebufferinfo->bmiHeader.biBitCount = 32;
g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB;
g_pFramebufferinfo->bmiHeader.biClrUsed = 0;
videoCreateDIBSection(video);
VideoCreateDIBSection(resetVideoState);
#if 0
DDInit(); // For WaitForVerticalBlank()

View File

@ -25,7 +25,8 @@ class Video;
class Win32Frame : public FrameBase
{
public:
Win32Frame();
Win32Frame(void);
virtual ~Win32Frame(void){}
static Win32Frame& GetWin32Frame();
static LRESULT CALLBACK FrameWndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
@ -38,15 +39,16 @@ public:
virtual void FrameSetCursorPosByMousePos();
virtual void SetFullScreenShowSubunitStatus(bool bShow);
virtual bool GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedHeight = 0);
virtual bool GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedWidth=0, UINT userSpecifiedHeight=0);
virtual int SetViewportScale(int nNewScale, bool bForce = false);
virtual void SetAltEnterToggleFullScreen(bool mode);
virtual void SetLoadedSaveStateFlag(const bool bFlag);
virtual void Initialize(void);
virtual void Initialize(bool resetVideoState);
virtual void Destroy(void);
virtual void VideoPresentScreen(void);
virtual void ResizeWindow(void);
virtual int FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType);
virtual void GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits);
@ -64,6 +66,7 @@ public:
UINT Get3DBorderHeight(void);
int GetViewportScale(void);
void GetViewportCXCY(int& nViewportCX, int& nViewportCY);
void SetFullScreenViewportScale(int nNewXScale, int nNewYScale);
void ApplyVideoModeChange(void);
@ -76,7 +79,7 @@ private:
static BOOL CALLBACK DDEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext);
LRESULT WndProc(HWND window, UINT message, WPARAM wparam, LPARAM lparam);
void videoCreateDIBSection(Video& video);
void VideoCreateDIBSection(bool resetVideoState);
void VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale);
bool DDInit(void);
void DDUninit(void);
@ -129,7 +132,6 @@ private:
bool g_windowMinimized;
std::string driveTooltip;
bool g_bFullScreen_ShowSubunitStatus;
FULLSCREEN_SCALE_TYPE g_win_fullscreen_scale;
int g_win_fullscreen_offsetx;
int g_win_fullscreen_offsety;
UINT m_bestWidthForFullScreen;

View File

@ -463,11 +463,20 @@ void Win32Frame::DrawFrameWindow (bool bPaintingWindow/*=false*/)
DrawButton(dc,iButton);
}
if (g_nViewportScale == 2)
if (g_nViewportScale == 2 || GetVideo().HasVidHD())
{
int x = buttonx + 1;
int y = buttony + BUTTONS*BUTTONCY + 36; // 36 = height of StatusArea
RECT rect = {x, y, x+45, y+BUTTONS*BUTTONCY+22};
const int x = buttonx + 1;
const int y = buttony + BUTTONS * BUTTONCY + 36; // 36 = height of StatusArea
RECT rect = { x, y, x + BUTTONCX, y + BUTTONS * BUTTONCY + 22 };
if (GetVideo().HasVidHD())
{
if (g_nViewportScale == 1)
rect.bottom += 14;
else
rect.bottom += 32;
}
int res = FillRect(dc, &rect, btnfacebrush);
}
}
@ -1933,6 +1942,7 @@ void Win32Frame::ProcessButtonClick(int button, bool bFromButtonUI /*=false*/)
}
else // MODE_RUNNING, MODE_LOGO, MODE_PAUSED
{
GetVideo().ClearSHRResidue(); // Clear the framebuffer to remove any SHR residue in the borders
DebugBegin();
}
break;
@ -2149,13 +2159,14 @@ void Win32Frame::SetFullScreenMode(void)
scalex = width / GetVideo().GetFrameBufferBorderlessWidth();
scaley = height / GetVideo().GetFrameBufferBorderlessHeight();
g_win_fullscreen_scale = (scalex <= scaley) ? scalex : scaley;
g_win_fullscreen_offsetx = ((int)width - (int)(g_win_fullscreen_scale * GetVideo().GetFrameBufferBorderlessWidth())) / 2;
g_win_fullscreen_offsety = ((int)height - (int)(g_win_fullscreen_scale * GetVideo().GetFrameBufferBorderlessHeight())) / 2;
// NB. Separate x,y scaling is OK in full-screen mode
// . eg. SHR 640x400 (scalex=2, scaley=3) => 1280x1200, which roughly gives a 4:3 aspect ratio for a resolution of 1600x1200
g_win_fullscreen_offsetx = ((int)width - (int)(scalex * GetVideo().GetFrameBufferBorderlessWidth())) / 2;
g_win_fullscreen_offsety = ((int)height - (int)(scaley * GetVideo().GetFrameBufferBorderlessHeight())) / 2;
SetWindowPos(g_hFrameWindow, NULL, left, top, (int)width, (int)height, SWP_NOZORDER | SWP_NOACTIVATE | SWP_FRAMECHANGED);
g_bIsFullScreen = true;
SetViewportScale(g_win_fullscreen_scale, true);
SetFullScreenViewportScale(scalex, scaley);
buttonx = GetFullScreenOffsetX() + g_nViewportCX + VIEWPORTX*2;
buttony = GetFullScreenOffsetY();
@ -2187,7 +2198,6 @@ void Win32Frame::SetNormalMode(void)
g_win_fullscreen_offsetx = 0;
g_win_fullscreen_offsety = 0;
g_win_fullscreen_scale = 1;
SetWindowLong(g_hFrameWindow, GWL_STYLE, g_main_window_saved_style);
SetWindowLong(g_hFrameWindow, GWL_EXSTYLE, g_main_window_saved_exstyle);
SetWindowPos(g_hFrameWindow, NULL,
@ -2249,9 +2259,22 @@ int Win32Frame::SetViewportScale(int nNewScale, bool bForce /*=false*/)
g_nViewportCX = g_nViewportScale * GetVideo().GetFrameBufferBorderlessWidth();
g_nViewportCY = g_nViewportScale * GetVideo().GetFrameBufferBorderlessHeight();
buttonx = BUTTONX; // NB. macro uses g_nViewportCX
buttony = BUTTONY;
return nNewScale;
}
void Win32Frame::SetFullScreenViewportScale(int nNewXScale, int nNewYScale)
{
g_nViewportScale = MIN(nNewXScale, nNewYScale); // Not needed in FS mode
g_nViewportCX = nNewXScale * GetVideo().GetFrameBufferBorderlessWidth();
g_nViewportCY = nNewYScale * GetVideo().GetFrameBufferBorderlessHeight();
buttonx = BUTTONX; // NB. macro uses g_nViewportCX
buttony = BUTTONY;
}
void Win32Frame::SetupTooltipControls(void)
{
TOOLINFO toolinfo;
@ -2303,6 +2326,12 @@ void Win32Frame::GetWidthHeight(int& nWidth, int& nHeight)
#endif
}
// Window frame's border size has changed (eg. VidHD added/removed)
void Win32Frame::ResizeWindow(void)
{
FrameResizeWindow(GetViewportScale());
}
void Win32Frame::FrameResizeWindow(int nNewScale)
{
int nOldWidth, nOldHeight;
@ -2314,11 +2343,6 @@ void Win32Frame::FrameResizeWindow(int nNewScale)
int nXPos = framerect.left;
int nYPos = framerect.top;
//
buttonx = g_nViewportCX + VIEWPORTX*2;
buttony = 0;
// Invalidate old rect region
{
RECT irect;
@ -2697,7 +2721,7 @@ void Win32Frame::FrameUpdateApple2Type(void)
DrawFrameWindow();
}
bool Win32Frame::GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedHeight /*= 0*/)
bool Win32Frame::GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& bestHeight, UINT userSpecifiedWidth/*=0*/, UINT userSpecifiedHeight/*=0*/)
{
m_bestWidthForFullScreen = 0;
m_bestHeightForFullScreen = 0;
@ -2734,10 +2758,17 @@ bool Win32Frame::GetBestDisplayResolutionForFullScreen(UINT& bestWidth, UINT& be
if (vecDisplayResolutions.size() == 0)
return false;
// Pick least width (such that it's wide enough to scale)
// Pick user-specific width if it exists
// Else pick least width (such that it's wide enough to scale)
UINT width = (UINT)-1;
for (VEC_PAIR::iterator it = vecDisplayResolutions.begin(); it!= vecDisplayResolutions.end(); ++it)
{
if (it->first == userSpecifiedWidth)
{
width = userSpecifiedWidth;
break;
}
if (width > it->first)
{
UINT scaleFactor = it->second / GetVideo().GetFrameBufferBorderlessHeight();