2020-12-24 15:08:50 +00:00
|
|
|
#include "StdAfx.h"
|
|
|
|
|
|
|
|
#include "Windows/Win32Frame.h"
|
2021-01-03 16:21:24 +00:00
|
|
|
#include "Interface.h"
|
|
|
|
#include "Core.h"
|
|
|
|
#include "CPU.h"
|
|
|
|
#include "Joystick.h"
|
|
|
|
#include "Log.h"
|
|
|
|
#include "Memory.h"
|
|
|
|
#include "CardManager.h"
|
2021-01-13 22:02:48 +00:00
|
|
|
#include "Debugger/Debug.h"
|
2021-01-03 16:21:24 +00:00
|
|
|
#include "../resource/resource.h"
|
2020-12-24 15:08:50 +00:00
|
|
|
|
|
|
|
// Win32Frame methods are implemented in AppleWin, WinFrame and WinVideo.
|
|
|
|
// in time they should be brought together and more freestanding functions added to Win32Frame.
|
2021-01-03 16:21:24 +00:00
|
|
|
|
|
|
|
Win32Frame::Win32Frame()
|
|
|
|
{
|
|
|
|
g_pFramebufferinfo = NULL;
|
|
|
|
num_draw_devices = 0;
|
|
|
|
g_lpDD = NULL;
|
|
|
|
g_hLogoBitmap = (HBITMAP)0;
|
|
|
|
g_hDeviceBitmap = (HBITMAP)0;
|
|
|
|
g_hDeviceDC = (HDC)0;
|
2021-01-10 16:33:06 +00:00
|
|
|
g_bAltEnter_ToggleFullScreen = false;
|
|
|
|
g_bIsFullScreen = false;
|
|
|
|
g_bShowingCursor = true;
|
|
|
|
g_bLastCursorInAppleViewport = false;
|
|
|
|
g_uCount100msec = 0;
|
|
|
|
g_TimerIDEvent_100msec = 0;
|
|
|
|
g_bUsingCursor = FALSE;
|
|
|
|
g_bAppActive = false;
|
|
|
|
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;
|
2021-05-31 15:09:39 +00:00
|
|
|
m_bestWidthForFullScreen = 0;
|
|
|
|
m_bestHeightForFullScreen = 0;
|
2021-06-19 14:06:04 +00:00
|
|
|
m_changedDisplaySettings = false;
|
2021-01-16 21:57:28 +00:00
|
|
|
|
|
|
|
btnfacebrush = (HBRUSH)0;
|
|
|
|
btnfacepen = (HPEN)0;
|
|
|
|
btnhighlightpen = (HPEN)0;
|
|
|
|
btnshadowpen = (HPEN)0;
|
|
|
|
buttonactive = -1;
|
|
|
|
buttondown = -1;
|
|
|
|
buttonover = -1;
|
|
|
|
buttonx = BUTTONX;
|
|
|
|
buttony = BUTTONY;
|
|
|
|
g_hFrameDC = (HDC)0;
|
2021-01-16 22:13:02 +00:00
|
|
|
memset(&framerect, 0, sizeof(framerect));
|
2021-01-16 21:57:28 +00:00
|
|
|
|
|
|
|
helpquit = 0;
|
|
|
|
smallfont = (HFONT)0;
|
|
|
|
tooltipwindow = (HWND)0;
|
|
|
|
viewportx = VIEWPORTX; // Default to Normal (non-FullScreen) mode
|
|
|
|
viewporty = VIEWPORTY; // Default to Normal (non-FullScreen) mode
|
|
|
|
|
|
|
|
g_bScrollLock_FullSpeed = false;
|
|
|
|
|
|
|
|
g_nTrackDrive1 = -1;
|
|
|
|
g_nTrackDrive2 = -1;
|
|
|
|
g_nSectorDrive1 = -1;
|
|
|
|
g_nSectorDrive2 = -1;
|
2021-01-16 22:13:02 +00:00
|
|
|
strcpy_s(g_sTrackDrive1, sizeof(g_sTrackDrive1), "??");
|
|
|
|
strcpy_s(g_sTrackDrive2, sizeof(g_sTrackDrive1), "??");
|
|
|
|
strcpy_s(g_sSectorDrive1, sizeof(g_sTrackDrive1), "??");
|
|
|
|
strcpy_s(g_sSectorDrive2, sizeof(g_sTrackDrive1), "??");
|
2021-01-16 21:57:28 +00:00
|
|
|
|
|
|
|
g_eStatusDrive1 = DISK_STATUS_OFF;
|
|
|
|
g_eStatusDrive2 = DISK_STATUS_OFF;
|
|
|
|
|
|
|
|
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)
|
2021-01-03 16:21:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Win32Frame::videoCreateDIBSection(Video & video)
|
|
|
|
{
|
|
|
|
// CREATE THE DEVICE CONTEXT
|
|
|
|
HWND window = GetDesktopWindow();
|
|
|
|
HDC dc = GetDC(window);
|
|
|
|
if (g_hDeviceDC)
|
|
|
|
{
|
|
|
|
DeleteDC(g_hDeviceDC);
|
|
|
|
}
|
|
|
|
g_hDeviceDC = CreateCompatibleDC(dc);
|
|
|
|
|
|
|
|
// CREATE THE FRAME BUFFER DIB SECTION
|
|
|
|
if (g_hDeviceBitmap)
|
|
|
|
DeleteObject(g_hDeviceBitmap);
|
|
|
|
|
|
|
|
uint8_t* pFramebufferbits;
|
|
|
|
|
|
|
|
g_hDeviceBitmap = CreateDIBSection(
|
|
|
|
dc,
|
|
|
|
g_pFramebufferinfo,
|
|
|
|
DIB_RGB_COLORS,
|
|
|
|
(LPVOID*)&pFramebufferbits, 0, 0
|
|
|
|
);
|
|
|
|
SelectObject(g_hDeviceDC, g_hDeviceBitmap);
|
|
|
|
video.Initialize(pFramebufferbits);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Win32Frame::Initialize(void)
|
|
|
|
{
|
|
|
|
// LOAD THE LOGO
|
|
|
|
g_hLogoBitmap = LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_APPLEWIN));
|
|
|
|
|
|
|
|
// 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.biPlanes = 1;
|
|
|
|
g_pFramebufferinfo->bmiHeader.biBitCount = 32;
|
|
|
|
g_pFramebufferinfo->bmiHeader.biCompression = BI_RGB;
|
|
|
|
g_pFramebufferinfo->bmiHeader.biClrUsed = 0;
|
|
|
|
|
|
|
|
videoCreateDIBSection(video);
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
DDInit(); // For WaitForVerticalBlank()
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void Win32Frame::Destroy(void)
|
|
|
|
{
|
|
|
|
// DESTROY BUFFERS
|
|
|
|
delete[] g_pFramebufferinfo;
|
|
|
|
g_pFramebufferinfo = NULL;
|
|
|
|
|
|
|
|
// DESTROY FRAME BUFFER
|
|
|
|
DeleteDC(g_hDeviceDC);
|
|
|
|
g_hDeviceDC = (HDC)0;
|
|
|
|
|
|
|
|
DeleteObject(g_hDeviceBitmap); // this invalidates the Video's FrameBuffer pointer
|
|
|
|
GetVideo().Destroy(); // this resets the Video's FrameBuffer pointer
|
|
|
|
g_hDeviceBitmap = (HBITMAP)0;
|
|
|
|
|
|
|
|
// DESTROY LOGO
|
|
|
|
if (g_hLogoBitmap) {
|
|
|
|
DeleteObject(g_hLogoBitmap);
|
|
|
|
g_hLogoBitmap = (HBITMAP)0;
|
|
|
|
}
|
|
|
|
|
|
|
|
DDUninit();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
void Win32Frame::Benchmark(void)
|
|
|
|
{
|
|
|
|
_ASSERT(g_nAppMode == MODE_BENCHMARK);
|
|
|
|
Sleep(500);
|
|
|
|
Video& video = GetVideo();
|
|
|
|
|
|
|
|
// PREPARE TWO DIFFERENT FRAME BUFFERS, EACH OF WHICH HAVE HALF OF THE
|
|
|
|
// BYTES SET TO 0x14 AND THE OTHER HALF SET TO 0xAA
|
|
|
|
int loop;
|
|
|
|
LPDWORD mem32 = (LPDWORD)mem;
|
|
|
|
for (loop = 4096; loop < 6144; loop++)
|
|
|
|
*(mem32 + loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0x14141414
|
|
|
|
: 0xAAAAAAAA;
|
|
|
|
for (loop = 6144; loop < 8192; loop++)
|
|
|
|
*(mem32 + loop) = ((loop & 1) ^ ((loop & 0x40) >> 6)) ? 0xAAAAAAAA
|
|
|
|
: 0x14141414;
|
|
|
|
|
|
|
|
// SEE HOW MANY TEXT FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE
|
|
|
|
// GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO
|
|
|
|
// SIMULATE THE ACTIVITY OF AN AVERAGE GAME
|
|
|
|
DWORD totaltextfps = 0;
|
|
|
|
|
|
|
|
video.SetVideoMode(VF_TEXT);
|
|
|
|
memset(mem + 0x400, 0x14, 0x400);
|
|
|
|
VideoRedrawScreen();
|
|
|
|
DWORD milliseconds = GetTickCount();
|
|
|
|
while (GetTickCount() == milliseconds);
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
DWORD cycle = 0;
|
|
|
|
do {
|
|
|
|
if (cycle & 1)
|
|
|
|
memset(mem + 0x400, 0x14, 0x400);
|
|
|
|
else
|
|
|
|
memcpy(mem + 0x400, mem + ((cycle & 2) ? 0x4000 : 0x6000), 0x400);
|
|
|
|
VideoPresentScreen();
|
|
|
|
if (cycle++ >= 3)
|
|
|
|
cycle = 0;
|
|
|
|
totaltextfps++;
|
|
|
|
} while (GetTickCount() - milliseconds < 1000);
|
|
|
|
|
|
|
|
// SEE HOW MANY HIRES FRAMES PER SECOND WE CAN PRODUCE WITH NOTHING ELSE
|
|
|
|
// GOING ON, CHANGING HALF OF THE BYTES IN THE VIDEO BUFFER EACH FRAME TO
|
|
|
|
// SIMULATE THE ACTIVITY OF AN AVERAGE GAME
|
|
|
|
DWORD totalhiresfps = 0;
|
|
|
|
video.SetVideoMode(VF_HIRES);
|
|
|
|
memset(mem + 0x2000, 0x14, 0x2000);
|
|
|
|
VideoRedrawScreen();
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
while (GetTickCount() == milliseconds);
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
cycle = 0;
|
|
|
|
do {
|
|
|
|
if (cycle & 1)
|
|
|
|
memset(mem + 0x2000, 0x14, 0x2000);
|
|
|
|
else
|
|
|
|
memcpy(mem + 0x2000, mem + ((cycle & 2) ? 0x4000 : 0x6000), 0x2000);
|
|
|
|
VideoPresentScreen();
|
|
|
|
if (cycle++ >= 3)
|
|
|
|
cycle = 0;
|
|
|
|
totalhiresfps++;
|
|
|
|
} while (GetTickCount() - milliseconds < 1000);
|
|
|
|
|
|
|
|
// DETERMINE HOW MANY 65C02 CLOCK CYCLES WE CAN EMULATE PER SECOND WITH
|
|
|
|
// NOTHING ELSE GOING ON
|
|
|
|
DWORD totalmhz10[2] = { 0,0 }; // bVideoUpdate & !bVideoUpdate
|
|
|
|
for (UINT i = 0; i < 2; i++)
|
|
|
|
{
|
|
|
|
CpuSetupBenchmark();
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
while (GetTickCount() == milliseconds);
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
do {
|
|
|
|
CpuExecute(100000, i == 0 ? true : false);
|
|
|
|
totalmhz10[i]++;
|
|
|
|
} while (GetTickCount() - milliseconds < 1000);
|
|
|
|
}
|
|
|
|
|
|
|
|
// IF THE PROGRAM COUNTER IS NOT IN THE EXPECTED RANGE AT THE END OF THE
|
|
|
|
// CPU BENCHMARK, REPORT AN ERROR AND OPTIONALLY TRACK IT DOWN
|
|
|
|
if ((regs.pc < 0x300) || (regs.pc > 0x400))
|
2021-01-19 20:37:43 +00:00
|
|
|
if (FrameMessageBox(
|
2021-01-03 16:21:24 +00:00
|
|
|
TEXT("The emulator has detected a problem while running ")
|
|
|
|
TEXT("the CPU benchmark. Would you like to gather more ")
|
|
|
|
TEXT("information?"),
|
|
|
|
TEXT("Benchmarks"),
|
|
|
|
MB_ICONQUESTION | MB_YESNO | MB_SETFOREGROUND) == IDYES) {
|
|
|
|
BOOL error = 0;
|
|
|
|
WORD lastpc = 0x300;
|
|
|
|
int loop = 0;
|
|
|
|
while ((loop < 10000) && !error) {
|
|
|
|
CpuSetupBenchmark();
|
|
|
|
CpuExecute(loop, true);
|
|
|
|
if ((regs.pc < 0x300) || (regs.pc > 0x400))
|
|
|
|
error = 1;
|
|
|
|
else {
|
|
|
|
lastpc = regs.pc;
|
|
|
|
++loop;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (error) {
|
|
|
|
TCHAR outstr[256];
|
|
|
|
wsprintf(outstr,
|
|
|
|
TEXT("The emulator experienced an error %u clock cycles ")
|
|
|
|
TEXT("into the CPU benchmark. Prior to the error, the ")
|
|
|
|
TEXT("program counter was at $%04X. After the error, it ")
|
|
|
|
TEXT("had jumped to $%04X."),
|
|
|
|
(unsigned)loop,
|
|
|
|
(unsigned)lastpc,
|
|
|
|
(unsigned)regs.pc);
|
2021-01-19 20:37:43 +00:00
|
|
|
FrameMessageBox(
|
2021-01-03 16:21:24 +00:00
|
|
|
outstr,
|
|
|
|
TEXT("Benchmarks"),
|
|
|
|
MB_ICONINFORMATION | MB_SETFOREGROUND);
|
|
|
|
}
|
|
|
|
else
|
2021-01-19 20:37:43 +00:00
|
|
|
FrameMessageBox(
|
2021-01-03 16:21:24 +00:00
|
|
|
TEXT("The emulator was unable to locate the exact ")
|
|
|
|
TEXT("point of the error. This probably means that ")
|
|
|
|
TEXT("the problem is external to the emulator, ")
|
|
|
|
TEXT("happening asynchronously, such as a problem in ")
|
|
|
|
TEXT("a timer interrupt handler."),
|
|
|
|
TEXT("Benchmarks"),
|
|
|
|
MB_ICONINFORMATION | MB_SETFOREGROUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
// DO A REALISTIC TEST OF HOW MANY FRAMES PER SECOND WE CAN PRODUCE
|
|
|
|
// WITH FULL EMULATION OF THE CPU, JOYSTICK, AND DISK HAPPENING AT
|
|
|
|
// THE SAME TIME
|
|
|
|
DWORD realisticfps = 0;
|
|
|
|
memset(mem + 0x2000, 0xAA, 0x2000);
|
|
|
|
VideoRedrawScreen();
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
while (GetTickCount() == milliseconds);
|
|
|
|
milliseconds = GetTickCount();
|
|
|
|
cycle = 0;
|
|
|
|
do {
|
|
|
|
if (realisticfps < 10) {
|
|
|
|
int cycles = 100000;
|
|
|
|
while (cycles > 0) {
|
|
|
|
DWORD executedcycles = CpuExecute(103, true);
|
|
|
|
cycles -= executedcycles;
|
|
|
|
GetCardMgr().GetDisk2CardMgr().UpdateDriveState(executedcycles);
|
|
|
|
JoyUpdateButtonLatch(executedcycles);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (cycle & 1)
|
|
|
|
memset(mem + 0x2000, 0xAA, 0x2000);
|
|
|
|
else
|
|
|
|
memcpy(mem + 0x2000, mem + ((cycle & 2) ? 0x4000 : 0x6000), 0x2000);
|
|
|
|
VideoRedrawScreen();
|
|
|
|
if (cycle++ >= 3)
|
|
|
|
cycle = 0;
|
|
|
|
realisticfps++;
|
|
|
|
} while (GetTickCount() - milliseconds < 1000);
|
|
|
|
|
|
|
|
// DISPLAY THE RESULTS
|
|
|
|
DisplayLogo();
|
|
|
|
TCHAR outstr[256];
|
|
|
|
wsprintf(outstr,
|
|
|
|
TEXT("Pure Video FPS:\t%u hires, %u text\n")
|
|
|
|
TEXT("Pure CPU MHz:\t%u.%u%s (video update)\n")
|
|
|
|
TEXT("Pure CPU MHz:\t%u.%u%s (full-speed)\n\n")
|
|
|
|
TEXT("EXPECTED AVERAGE VIDEO GAME\n")
|
|
|
|
TEXT("PERFORMANCE: %u FPS"),
|
|
|
|
(unsigned)totalhiresfps,
|
|
|
|
(unsigned)totaltextfps,
|
|
|
|
(unsigned)(totalmhz10[0] / 10), (unsigned)(totalmhz10[0] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")),
|
|
|
|
(unsigned)(totalmhz10[1] / 10), (unsigned)(totalmhz10[1] % 10), (LPCTSTR)(IS_APPLE2 ? TEXT(" (6502)") : TEXT("")),
|
|
|
|
(unsigned)realisticfps);
|
2021-01-19 20:37:43 +00:00
|
|
|
FrameMessageBox(
|
2021-01-03 16:21:24 +00:00
|
|
|
outstr,
|
|
|
|
TEXT("Benchmarks"),
|
|
|
|
MB_ICONINFORMATION | MB_SETFOREGROUND);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
// This is called from PageConfig
|
|
|
|
void Win32Frame::ChooseMonochromeColor(void)
|
|
|
|
{
|
|
|
|
Video& video = GetVideo();
|
|
|
|
CHOOSECOLOR cc;
|
|
|
|
memset(&cc, 0, sizeof(CHOOSECOLOR));
|
|
|
|
cc.lStructSize = sizeof(CHOOSECOLOR);
|
|
|
|
cc.hwndOwner = g_hFrameWindow;
|
|
|
|
cc.rgbResult = video.GetMonochromeRGB();
|
|
|
|
cc.lpCustColors = customcolors + 1;
|
|
|
|
cc.Flags = CC_RGBINIT | CC_SOLIDCOLOR;
|
|
|
|
if (ChooseColor(&cc))
|
|
|
|
{
|
|
|
|
video.SetMonochromeRGB(cc.rgbResult);
|
2021-01-13 22:02:48 +00:00
|
|
|
ApplyVideoModeChange();
|
2021-01-03 16:21:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void Win32Frame::VideoDrawLogoBitmap(HDC hDstDC, int xoff, int yoff, int srcw, int srch, int scale)
|
|
|
|
{
|
|
|
|
HDC hSrcDC = CreateCompatibleDC(hDstDC);
|
|
|
|
SelectObject(hSrcDC, g_hLogoBitmap);
|
|
|
|
StretchBlt(
|
|
|
|
hDstDC, // hdcDest
|
|
|
|
xoff, yoff, // nXDest, nYDest
|
|
|
|
scale * srcw, scale * srch, // nWidth, nHeight
|
|
|
|
hSrcDC, // hdcSrc
|
|
|
|
0, 0, // nXSrc, nYSrc
|
|
|
|
srcw, srch,
|
|
|
|
SRCCOPY // dwRop
|
|
|
|
);
|
|
|
|
|
|
|
|
DeleteObject(hSrcDC);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void Win32Frame::DisplayLogo(void)
|
|
|
|
{
|
|
|
|
Video& video = GetVideo();
|
|
|
|
int nLogoX = 0, nLogoY = 0;
|
|
|
|
int scale = GetViewportScale();
|
|
|
|
|
|
|
|
HDC hFrameDC = FrameGetDC();
|
|
|
|
|
|
|
|
// DRAW THE LOGO
|
|
|
|
SelectObject(hFrameDC, GetStockObject(NULL_PEN));
|
|
|
|
|
|
|
|
if (g_hLogoBitmap)
|
|
|
|
{
|
|
|
|
BITMAP bm;
|
|
|
|
if (GetObject(g_hLogoBitmap, sizeof(bm), &bm))
|
|
|
|
{
|
|
|
|
nLogoX = (g_nViewportCX - scale * bm.bmWidth) / 2;
|
|
|
|
nLogoY = (g_nViewportCY - scale * bm.bmHeight) / 2;
|
|
|
|
|
|
|
|
if (IsFullScreen())
|
|
|
|
{
|
|
|
|
nLogoX += GetFullScreenOffsetX();
|
|
|
|
nLogoY += GetFullScreenOffsetY();
|
|
|
|
}
|
|
|
|
|
|
|
|
VideoDrawLogoBitmap(hFrameDC, nLogoX, nLogoY, bm.bmWidth, bm.bmHeight, scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// DRAW THE VERSION NUMBER
|
|
|
|
TCHAR sFontName[] = TEXT("Arial");
|
|
|
|
HFONT font = CreateFont(-20, 0, 0, 0, FW_NORMAL, 0, 0, 0, ANSI_CHARSET,
|
|
|
|
OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY,
|
|
|
|
VARIABLE_PITCH | 4 | FF_SWISS,
|
|
|
|
sFontName);
|
|
|
|
SelectObject(hFrameDC, font);
|
|
|
|
SetTextAlign(hFrameDC, TA_RIGHT | TA_TOP);
|
|
|
|
SetBkMode(hFrameDC, TRANSPARENT);
|
|
|
|
|
|
|
|
TCHAR szVersion[64];
|
|
|
|
StringCbPrintf(szVersion, 64, "Version %s", VERSIONSTRING);
|
|
|
|
int xoff = GetFullScreenOffsetX(), yoff = GetFullScreenOffsetY();
|
|
|
|
|
|
|
|
#define DRAWVERSION(x,y,c) \
|
|
|
|
SetTextColor(hFrameDC,c); \
|
|
|
|
TextOut(hFrameDC, \
|
|
|
|
scale*540+x+xoff,scale*358+y+yoff, \
|
|
|
|
szVersion, \
|
|
|
|
strlen(szVersion));
|
|
|
|
|
|
|
|
if (GetDeviceCaps(hFrameDC, PLANES) * GetDeviceCaps(hFrameDC, BITSPIXEL) <= 4) {
|
|
|
|
DRAWVERSION(2, 2, RGB(0x00, 0x00, 0x00));
|
|
|
|
DRAWVERSION(1, 1, RGB(0x00, 0x00, 0x00));
|
|
|
|
DRAWVERSION(0, 0, RGB(0xFF, 0x00, 0xFF));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
DRAWVERSION(1, 1, PALETTERGB(0x30, 0x30, 0x70));
|
|
|
|
DRAWVERSION(-1, -1, PALETTERGB(0xC0, 0x70, 0xE0));
|
|
|
|
DRAWVERSION(0, 0, PALETTERGB(0x70, 0x30, 0xE0));
|
|
|
|
}
|
|
|
|
|
|
|
|
#if _DEBUG
|
|
|
|
StringCbPrintf(szVersion, 64, "DEBUG");
|
|
|
|
DRAWVERSION(2, -358 * scale, RGB(0x00, 0x00, 0x00));
|
|
|
|
DRAWVERSION(1, -357 * scale, RGB(0x00, 0x00, 0x00));
|
|
|
|
DRAWVERSION(0, -356 * scale, RGB(0xFF, 0x00, 0xFF));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#undef DRAWVERSION
|
|
|
|
|
|
|
|
DeleteObject(font);
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
void Win32Frame::VideoPresentScreen(void)
|
|
|
|
{
|
|
|
|
HDC hFrameDC = FrameGetDC();
|
|
|
|
|
|
|
|
if (hFrameDC)
|
|
|
|
{
|
|
|
|
Video& video = GetVideo();
|
|
|
|
int xSrc = video.GetFrameBufferBorderWidth();
|
|
|
|
int ySrc = video.GetFrameBufferBorderHeight();
|
|
|
|
|
|
|
|
int xdest = IsFullScreen() ? GetFullScreenOffsetX() : 0;
|
|
|
|
int ydest = IsFullScreen() ? GetFullScreenOffsetY() : 0;
|
|
|
|
int wdest = g_nViewportCX;
|
|
|
|
int hdest = g_nViewportCY;
|
|
|
|
|
|
|
|
SetStretchBltMode(hFrameDC, COLORONCOLOR);
|
|
|
|
StretchBlt(
|
|
|
|
hFrameDC,
|
|
|
|
xdest, ydest,
|
|
|
|
wdest, hdest,
|
|
|
|
g_hDeviceDC,
|
|
|
|
xSrc, ySrc,
|
|
|
|
video.GetFrameBufferBorderlessWidth(), video.GetFrameBufferBorderlessHeight(),
|
|
|
|
SRCCOPY);
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef NO_DIRECT_X
|
|
|
|
#else
|
|
|
|
//if (g_lpDD) g_lpDD->WaitForVerticalBlank(DDWAITVB_BLOCKBEGIN, NULL);
|
|
|
|
#endif // NO_DIRECT_X
|
|
|
|
|
|
|
|
GdiFlush();
|
|
|
|
}
|
|
|
|
|
|
|
|
//===========================================================================
|
|
|
|
|
|
|
|
BOOL CALLBACK Win32Frame::DDEnumProc(LPGUID lpGUID, LPCTSTR lpszDesc, LPCTSTR lpszDrvName, LPVOID lpContext)
|
|
|
|
{
|
|
|
|
Win32Frame* obj = (Win32Frame*)lpContext;
|
|
|
|
|
|
|
|
int i = obj->num_draw_devices;
|
|
|
|
if (i == MAX_DRAW_DEVICES)
|
|
|
|
return TRUE;
|
|
|
|
if (lpGUID != NULL)
|
|
|
|
memcpy(&(obj->draw_device_guid[i]), lpGUID, sizeof(GUID));
|
|
|
|
obj->draw_devices[i] = _strdup(lpszDesc);
|
|
|
|
|
|
|
|
if (g_fh) fprintf(g_fh, "%d: %s - %s\n", i, lpszDesc, lpszDrvName);
|
|
|
|
|
|
|
|
(obj->num_draw_devices)++;
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool Win32Frame::DDInit(void)
|
|
|
|
{
|
|
|
|
#ifdef NO_DIRECT_X
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
#else
|
|
|
|
HRESULT hr = DirectDrawEnumerate((LPDDENUMCALLBACK)DDEnumProc, this);
|
|
|
|
if (FAILED(hr))
|
|
|
|
{
|
|
|
|
LogFileOutput("DSEnumerate failed (%08X)\n", hr);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
LogFileOutput("Number of draw devices = %d\n", num_draw_devices);
|
|
|
|
|
|
|
|
bool bCreatedOK = false;
|
|
|
|
for (int x = 0; x < num_draw_devices; x++)
|
|
|
|
{
|
|
|
|
hr = DirectDrawCreate(&draw_device_guid[x], &g_lpDD, NULL);
|
|
|
|
if (SUCCEEDED(hr))
|
|
|
|
{
|
|
|
|
LogFileOutput("DSCreate succeeded for draw device #%d\n", x);
|
|
|
|
bCreatedOK = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
LogFileOutput("DSCreate failed for draw device #%d (%08X)\n", x, hr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!bCreatedOK)
|
|
|
|
{
|
|
|
|
LogFileOutput("DSCreate failed for all draw devices\n");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
#endif // NO_DIRECT_X
|
|
|
|
}
|
|
|
|
|
|
|
|
// From SoundCore.h
|
|
|
|
#define SAFE_RELEASE(p) { if(p) { (p)->Release(); (p)=NULL; } }
|
|
|
|
|
|
|
|
void Win32Frame::DDUninit(void)
|
|
|
|
{
|
|
|
|
SAFE_RELEASE(g_lpDD);
|
|
|
|
}
|
|
|
|
|
|
|
|
#undef SAFE_RELEASE
|
2021-01-10 16:33:06 +00:00
|
|
|
|
2021-01-13 22:02:48 +00:00
|
|
|
void Win32Frame::ApplyVideoModeChange(void)
|
|
|
|
{
|
|
|
|
Video& video = GetVideo();
|
|
|
|
video.Config_Save_Video();
|
|
|
|
video.VideoReinitialize(false);
|
|
|
|
|
|
|
|
if (g_nAppMode != MODE_LOGO)
|
|
|
|
{
|
|
|
|
if (g_nAppMode == MODE_DEBUG)
|
|
|
|
{
|
|
|
|
UINT debugVideoMode;
|
|
|
|
if (DebugGetVideoMode(&debugVideoMode))
|
|
|
|
VideoRefreshScreen(debugVideoMode, true);
|
|
|
|
else
|
|
|
|
VideoPresentScreen();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
VideoPresentScreen();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-10 16:33:06 +00:00
|
|
|
Win32Frame& Win32Frame::GetWin32Frame()
|
|
|
|
{
|
|
|
|
FrameBase& frameBase = GetFrame();
|
|
|
|
Win32Frame& win32Frame = dynamic_cast<Win32Frame&>(frameBase);
|
|
|
|
return win32Frame;
|
|
|
|
}
|
2021-01-19 20:37:43 +00:00
|
|
|
|
|
|
|
int Win32Frame::FrameMessageBox(LPCSTR lpText, LPCSTR lpCaption, UINT uType)
|
|
|
|
{
|
|
|
|
const HWND handle = g_hFrameWindow ? g_hFrameWindow : GetDesktopWindow();
|
|
|
|
return MessageBox(handle, lpText, lpCaption, uType);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Win32Frame::GetBitmap(LPCSTR lpBitmapName, LONG cb, LPVOID lpvBits)
|
|
|
|
{
|
|
|
|
HBITMAP hBitmap = LoadBitmap(g_hInstance, lpBitmapName);
|
|
|
|
GetBitmapBits(hBitmap, cb, lpvBits);
|
|
|
|
DeleteObject(hBitmap);
|
|
|
|
}
|
|
|
|
|
|
|
|
void Win32Frame::Restart()
|
|
|
|
{
|
|
|
|
// Changed h/w config, eg. Apple computer type (][+ or //e), slot configuration, etc.
|
|
|
|
g_bRestart = true;
|
|
|
|
PostMessage(g_hFrameWindow, WM_CLOSE, 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
BYTE* Win32Frame::GetResource(WORD id, LPCSTR lpType, DWORD dwExpectedSize)
|
|
|
|
{
|
|
|
|
HRSRC hResInfo = FindResource(NULL, MAKEINTRESOURCE(id), lpType);
|
|
|
|
if (hResInfo == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
DWORD dwResSize = SizeofResource(NULL, hResInfo);
|
|
|
|
if (dwResSize != dwExpectedSize)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
HGLOBAL hResData = LoadResource(NULL, hResInfo);
|
|
|
|
if (hResData == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
BYTE* pResource = (BYTE*)LockResource(hResData); // NB. Don't need to unlock resource
|
|
|
|
|
|
|
|
return pResource;
|
|
|
|
}
|