From 80f1d0576cac85c12e63a3e586ed0f59f07df9e7 Mon Sep 17 00:00:00 2001 From: Paper Date: Sun, 3 Aug 2025 19:09:16 -0400 Subject: [PATCH 1/2] graphics: fall back to GDI when DirectDraw isn't available (or failed to init) --- Graphics.cpp | 823 +++++++++++++++++++++++---------------- Graphics.h | 105 ++++- SecondRealityW32.vcxproj | 4 +- main.cpp | 36 +- 4 files changed, 599 insertions(+), 369 deletions(-) diff --git a/Graphics.cpp b/Graphics.cpp index d7e39bf..5fa4b58 100644 --- a/Graphics.cpp +++ b/Graphics.cpp @@ -2,42 +2,233 @@ #include "Graphics.h" #include "Resources/resource.h" +/* ---------------------------------------------------------------------------------------------- */ +/* Graphics (toplevel class, doesn't do much) */ + Graphics::Graphics() - : mDirectDraw( NULL ) - , mSurfacePrimary( NULL ) - , mSurfaceSecondary( NULL ) - , mBPP( 0 ) - , mHWnd( 0 ) - , mPhysicalWidth( 0 ) + : mPhysicalWidth( 0 ) , mPhysicalHeight( 0 ) , mIntegerZoom( 0 ) - , mWantsToQuit( 0 ) , mWindowType( WindowType::Windowed ) , mPhysicalScreen( NULL ) { - ZeroMemory( &mRectWindow, sizeof( RECT ) ); - ZeroMemory( &mRectViewport, sizeof( RECT ) ); - ZeroMemory( &mRectScreen, sizeof( RECT ) ); + /* nothing */ } Graphics::~Graphics() { + Close(); } -bool Graphics::Init( HINSTANCE _instance, int _screenWidth, int _screenHeight, int _zoom, WindowType _windowType ) +bool Graphics::Init( int _screenWidth, int _screenHeight, int _zoom, WindowType _windowType ) { mPhysicalWidth = _screenWidth; mPhysicalHeight = _screenHeight; mWindowType = _windowType; - + mIntegerZoom = _zoom; - mPhysicalScreen = new unsigned int[ mPhysicalWidth * mPhysicalHeight ]; - ZeroMemory( mPhysicalScreen, sizeof( unsigned int ) * mPhysicalWidth * mPhysicalHeight ); + mPhysicalScreen = new uint32_t[ mPhysicalWidth * mPhysicalHeight ]; + memset(mPhysicalScreen, 0, sizeof(uint32_t) * mPhysicalWidth * mPhysicalHeight); + + /* we're done here */ + return true; +} + +void Graphics::Close() +{ + if ( mPhysicalScreen ) + { + delete[] mPhysicalScreen; + mPhysicalScreen = NULL; + } +} + +void Graphics::Update( void * _buffer, int _width, int _height ) +{ + int zoom = mIntegerZoom; + if ( zoom == -1 ) + { + zoom = 1; + while ( _width * zoom <= mPhysicalWidth && _height * zoom <= mPhysicalHeight ) + { + zoom++; + } + zoom--; + } + + int zoomedX = _width * zoom; + int zoomedY = _height * zoom; + int mCenterX = ( mPhysicalWidth - zoomedX ) / 2; + int mCenterY = ( mPhysicalHeight - zoomedY ) / 2; + +#ifdef _DEBUG + memset( mPhysicalScreen, 0x30, mPhysicalWidth * mPhysicalHeight * sizeof( unsigned int ) ); +#else + memset( mPhysicalScreen, 0x00, mPhysicalWidth * mPhysicalHeight * sizeof( unsigned int ) ); +#endif // _DEBUG + + uint32_t *src = (uint32_t *) _buffer; + uint32_t *dst = (uint32_t *) mPhysicalScreen + mCenterY * mPhysicalWidth + mCenterX; + for ( int y = 0; y < _height; y++ ) + { + uint32_t * srcline = NULL; + + srcline = src; + for ( int x = 0; x < _width; x++ ) + { + for ( int xz = 0; xz < zoom; xz++ ) + { + *( dst++ ) = *srcline; + } + srcline++; + } + dst += mPhysicalWidth - ( _width * zoom ); + + for ( int yz = 1; yz < zoom; yz++ ) + { + memcpy( dst, dst - mPhysicalWidth, zoomedX * sizeof( unsigned int ) ); + dst += mPhysicalWidth; + } + src = srcline; + } + + Blit( mPhysicalScreen ); +} + +/* gutted from ddraw */ +void Graphics::FastBlit(const uint32_t* vscr, void* surfacePtr, int bpp, + uint32_t width, uint32_t height, uint32_t noMansLandSizeInBytes) +{ + switch (bpp) + { + case 32: + __asm + { + push es + mov ax, ds + mov es, ax + mov esi, [vscr] + mov edi, [surfacePtr] + mov ecx, [height] + Oneline32: + push ecx + mov ecx, [width] + rep movsd + add edi, [noMansLandSizeInBytes] + pop ecx + loop Oneline32 + pop es + } break; + case 24: + __asm + { + push es + mov ax, ds + mov es, ax + mov esi, [vscr] + mov edi, [surfacePtr] + mov ecx, [height] + Oneline24: + push ecx + mov ecx, [width] + Onepix24 : + movsw + movsb + inc esi + loop Onepix24 + add edi, [noMansLandSizeInBytes] + pop ecx + loop Oneline24 + pop es + } break; + case 16: + __asm + { + push es + mov ax, ds + mov es, ax + mov esi, [vscr] + mov edi, [surfacePtr] + mov ecx, [height] + Oneline16: + push ecx + mov ecx, [width] + Onepix16 : + lodsd + shr ax, 2 + shl al, 2 + shr ax, 3 + mov bx, ax + shr eax, 8 + and ax, 1111100000000000b + or ax, bx + stosw + loop Onepix16 + add edi, [noMansLandSizeInBytes] + pop ecx + loop Oneline16 + pop es + } break; + case 15: + __asm + { + push es + mov ax, ds + mov es, ax + mov esi, [vscr] + mov edi, [surfacePtr] + mov ecx, [height] + Oneline15: + push ecx + mov ecx, [width] + Onepix15 : + lodsd + shr ax, 3 + shl al, 3 + shr ax, 3 + mov bx, ax + shr eax, 9 + and ax, 0111110000000000b + or ax, bx + stosw + loop Onepix15 + add edi, [noMansLandSizeInBytes] + pop ecx + loop Oneline15 + pop es + } break; + } +} + +/* ---------------------------------------------------------------------------------------------- */ +/* GraphicsWindows */ + +GraphicsWindows::GraphicsWindows() + : Graphics() + , mHWnd(0) + , mWantsToQuit(0) +{ + ZeroMemory(&mRectWindow, sizeof(RECT)); + ZeroMemory(&mRectViewport, sizeof(RECT)); + ZeroMemory(&mRectScreen, sizeof(RECT)); +} + +GraphicsWindows::~GraphicsWindows() +{ + Close(); +} + +bool GraphicsWindows::Init(int _screenWidth, int _screenHeight, int _zoom, WindowType _windowType) +{ + if (!Graphics::Init(_screenWidth, _screenHeight, _zoom, _windowType)) + return false; + + HINSTANCE _instance = GetModuleHandle(NULL); DWORD wExStyle = WS_EX_APPWINDOW; DWORD wStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_VISIBLE; - if ( mWindowType == WindowType::Windowed ) + if (mWindowType == WindowType::Windowed) { wStyle |= WS_OVERLAPPED | WS_CAPTION; } @@ -48,81 +239,226 @@ bool Graphics::Init( HINSTANCE _instance, int _screenWidth, int _screenHeight, i wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = _instance; - wndClass.hIcon = LoadIcon( _instance, MAKEINTRESOURCE( IDI_ICON1 ) ); - wndClass.hCursor = LoadCursor( NULL, IDC_ARROW ); + wndClass.hIcon = LoadIcon(_instance, MAKEINTRESOURCE(IDI_ICON1)); + wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = NULL; wndClass.lpszMenuName = NULL; - wndClass.lpszClassName = _T( "ud2dwindow" ); + wndClass.lpszClassName = _T("ud2dwindow"); - if ( !RegisterClass( &wndClass ) ) + if (!RegisterClass(&wndClass) && GetLastError() != ERROR_CLASS_ALREADY_EXISTS) { return false; } RECT windowRect = { 0,0,mPhysicalWidth,mPhysicalHeight }; - AdjustWindowRectEx( &windowRect, wStyle, FALSE, wExStyle ); + AdjustWindowRectEx(&windowRect, wStyle, FALSE, wExStyle); - mHWnd = CreateWindowEx( wExStyle, wndClass.lpszClassName, _T( "Second Reality (Win32)" ), wStyle, - ( GetSystemMetrics( SM_CXSCREEN ) - ( windowRect.right - windowRect.left ) ) / 2, - ( GetSystemMetrics( SM_CYSCREEN ) - ( windowRect.bottom - windowRect.top ) ) / 2, + mHWnd = CreateWindowEx(wExStyle, wndClass.lpszClassName, _T("Second Reality (Win32)"), wStyle, + (GetSystemMetrics(SM_CXSCREEN) - (windowRect.right - windowRect.left)) / 2, + (GetSystemMetrics(SM_CYSCREEN) - (windowRect.bottom - windowRect.top)) / 2, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, - NULL, NULL, _instance, this ); + NULL, NULL, _instance, this); - if ( !mHWnd ) + if (!mHWnd) { return false; } - ShowWindow( mHWnd, SW_SHOW ); - SetForegroundWindow( mHWnd ); - SetFocus( mHWnd ); + ShowWindow(mHWnd, SW_SHOW); + SetForegroundWindow(mHWnd); + SetFocus(mHWnd); + + GetClientRect(mHWnd, &mRectViewport); + GetClientRect(mHWnd, &mRectScreen); + ClientToScreen(mHWnd, (POINT*)&mRectScreen.left); + ClientToScreen(mHWnd, (POINT*)&mRectScreen.right); + + mWantsToQuit = false; + + ShowCursor(FALSE); + + return true; +} + +void GraphicsWindows::Close() +{ + if (mHWnd) { + ShowWindow(mHWnd, SW_HIDE); // window doesn't actually get killed without this (?) + DestroyWindow(mHWnd); + } + + Graphics::Close(); +} - GetClientRect( mHWnd, &mRectViewport ); - GetClientRect( mHWnd, &mRectScreen ); - ClientToScreen( mHWnd, (POINT *) &mRectScreen.left ); - ClientToScreen( mHWnd, (POINT *) &mRectScreen.right ); +void GraphicsWindows::HandleMessages() +{ + MSG msg; + if (PeekMessage(&msg, mHWnd, 0U, 0U, PM_REMOVE)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } +} + +LRESULT CALLBACK GraphicsWindows::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +{ + switch ( uMsg ) + { + case WM_MOVE: + { + GetWindowRect( hWnd, &mRectWindow ); + GetClientRect( hWnd, &mRectViewport ); + GetClientRect( hWnd, &mRectScreen ); + ClientToScreen( hWnd, (POINT *) &mRectScreen.left ); + ClientToScreen( hWnd, (POINT *) &mRectScreen.right ); + } + break; - ////////////////////////////////////////////////////////////////////////// + case WM_PAINT: + { + if ( mWindowType == WindowType::Fullscreen ) + { + return 0; + } + } + break; + case WM_KEYDOWN: + { + switch ( wParam ) + { + case VK_ESCAPE: + { + // this isn't necessary, and also isn't how you're supposed to do it. + // MSDN: "Do not post the WM_QUIT message using the PostMessage function; use PostQuitMessage." + //PostMessage( hWnd, WM_QUIT, 0, 0 ); + mWantsToQuit = true; + return 0L; + } + break; + } + } + break; + + case WM_CLOSE: + case WM_DESTROY: + { + mWantsToQuit = true; + //PostMessage( hWnd, WM_QUIT, 0, 0 ); + } + break; + + case WM_SYSCOMMAND: + { + switch ( wParam ) + { + case SC_SCREENSAVE: + case SC_MONITORPOWER: + { + return 0; + } + } + break; + } + break; + + } + return DefWindowProc( hWnd, uMsg, wParam, lParam ); +} + +LRESULT CALLBACK GraphicsWindows::WndProcStatic(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + GraphicsWindows* This; + + if (uMsg == WM_CREATE) { + This = (GraphicsWindows *)((LPCREATESTRUCT)lParam)->lpCreateParams; + SetWindowLongPtr(hWnd, GWLP_USERDATA, (LONG_PTR)This); + } else { + This = (GraphicsWindows*)GetWindowLongPtr(hWnd, GWLP_USERDATA); + } + + return This->WndProc(hWnd, uMsg, wParam, lParam); +} + +/* ---------------------------------------------------------------------------------------------- */ +/* GraphicsWindowsDDraw */ + +GraphicsWindowsDDraw::GraphicsWindowsDDraw() + : GraphicsWindows() + , mDirectDraw(NULL) + , mSurfacePrimary(NULL) + , mSurfaceSecondary(NULL) + , mBPP(0) + , mhDDraw(NULL) +{ + /* nothing */ +} + +GraphicsWindowsDDraw::~GraphicsWindowsDDraw() +{ + Close(); +} + +bool GraphicsWindowsDDraw::Init(int _screenWidth, int _screenHeight, int _zoom, WindowType _windowType) +{ HRESULT result; - result = DirectDrawCreateEx( NULL, (VOID **) &mDirectDraw, IID_IDirectDraw7, NULL ); - if ( result != DD_OK ) + { - return false; + /* dynload ddraw for systems without it (archaic) + * this is done before window creation, because that works around unnecessary + * window creation (when ddraw isn't available) */ + typedef HRESULT(__stdcall* tpDirectDrawCreateEx)(GUID* lpGuid, LPVOID* lplpDD, REFIID iid, IUnknown* pUnkOuter); + tpDirectDrawCreateEx pDirectDrawCreateEx; + + mhDDraw = LoadLibraryA("DDRAW.DLL"); + if (!mhDDraw) + return false; + + pDirectDrawCreateEx = (tpDirectDrawCreateEx)GetProcAddress(mhDDraw, "DirectDrawCreateEx"); + if (!pDirectDrawCreateEx) + return false; + + result = pDirectDrawCreateEx(NULL, (VOID**)&mDirectDraw, IID_IDirectDraw7, NULL); + + if (result != DD_OK) + return false; } - if ( mWindowType == WindowType::Fullscreen ) + if (!GraphicsWindows::Init(_screenWidth, _screenHeight, _zoom, _windowType)) + return false; + + if (mWindowType == WindowType::Fullscreen) { - result = mDirectDraw->SetCooperativeLevel( mHWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN ); - if ( result != DD_OK ) + result = mDirectDraw->SetCooperativeLevel(mHWnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN); + if (result != DD_OK) { return false; } - result = mDirectDraw->SetDisplayMode( mPhysicalWidth, mPhysicalHeight, mBPP = 32, 0, 0 ); - if ( result != DD_OK ) + result = mDirectDraw->SetDisplayMode(mPhysicalWidth, mPhysicalHeight, mBPP = 32, 0, 0); + if (result != DD_OK) { - result = mDirectDraw->SetDisplayMode( mPhysicalWidth, mPhysicalHeight, mBPP = 24, 0, 0 ); - if ( result != DD_OK ) + result = mDirectDraw->SetDisplayMode(mPhysicalWidth, mPhysicalHeight, mBPP = 24, 0, 0); + if (result != DD_OK) { - result = mDirectDraw->SetDisplayMode( mPhysicalWidth, mPhysicalHeight, mBPP = 16, 0, 0 ); - if ( result != DD_OK ) + result = mDirectDraw->SetDisplayMode(mPhysicalWidth, mPhysicalHeight, mBPP = 16, 0, 0); + if (result != DD_OK) { return false; } else { DDSURFACEDESC2 ddsd; - ZeroMemory( &ddsd, sizeof( ddsd ) ); - ddsd.dwSize = sizeof( ddsd ); - mDirectDraw->GetDisplayMode( &ddsd ); - if ( mBPP == 16 ) + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); + mDirectDraw->GetDisplayMode(&ddsd); + if (mBPP == 16) { - if ( ddsd.ddpfPixelFormat.dwRBitMask == 0x7c00 ) + if (ddsd.ddpfPixelFormat.dwRBitMask == 0x7c00) { mBPP = 15; } - else if ( ddsd.ddpfPixelFormat.dwRBitMask != 0xf800 ) + else if (ddsd.ddpfPixelFormat.dwRBitMask != 0xf800) { return false; } @@ -132,58 +468,56 @@ bool Graphics::Init( HINSTANCE _instance, int _screenWidth, int _screenHeight, i } DDSURFACEDESC2 ddsd; - ZeroMemory( &ddsd, sizeof( ddsd ) ); - ddsd.dwSize = sizeof( ddsd ); + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS | DDSD_BACKBUFFERCOUNT; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE | DDSCAPS_FLIP | DDSCAPS_COMPLEX; ddsd.dwBackBufferCount = 1; - result = mDirectDraw->CreateSurface( &ddsd, &mSurfacePrimary, NULL ); - if ( result != DD_OK ) + result = mDirectDraw->CreateSurface(&ddsd, &mSurfacePrimary, NULL); + if (result != DD_OK) { return false; } DDSCAPS2 ddscaps; - ZeroMemory( &ddscaps, sizeof( ddscaps ) ); + ZeroMemory(&ddscaps, sizeof(ddscaps)); ddscaps.dwCaps = DDSCAPS_BACKBUFFER; - result = mSurfacePrimary->GetAttachedSurface( &ddscaps, &mSurfaceSecondary ); - if ( result != DD_OK ) + result = mSurfacePrimary->GetAttachedSurface(&ddscaps, &mSurfaceSecondary); + if (result != DD_OK) { return false; } - - ShowCursor( FALSE ); } else { - result = mDirectDraw->SetCooperativeLevel( mHWnd, DDSCL_NORMAL ); - if ( result != DD_OK ) + result = mDirectDraw->SetCooperativeLevel(mHWnd, DDSCL_NORMAL); + if (result != DD_OK) { return false; } DDSURFACEDESC2 ddsd; - ZeroMemory( &ddsd, sizeof( ddsd ) ); - ddsd.dwSize = sizeof( ddsd ); + ZeroMemory(&ddsd, sizeof(ddsd)); + ddsd.dwSize = sizeof(ddsd); ddsd.dwFlags = DDSD_CAPS; ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE; - result = mDirectDraw->CreateSurface( &ddsd, &mSurfacePrimary, NULL ); - if ( result != DD_OK ) + result = mDirectDraw->CreateSurface(&ddsd, &mSurfacePrimary, NULL); + if (result != DD_OK) { return false; } LPDIRECTDRAWCLIPPER pClipper; - result = mDirectDraw->CreateClipper( 0, &pClipper, NULL ); - if ( result != DD_OK ) + result = mDirectDraw->CreateClipper(0, &pClipper, NULL); + if (result != DD_OK) { return false; } - pClipper->SetHWnd( 0, mHWnd ); - result = mSurfacePrimary->SetClipper( pClipper ); + pClipper->SetHWnd(0, mHWnd); + result = mSurfacePrimary->SetClipper(pClipper); pClipper->Release(); - if ( result != DD_OK ) + if (result != DD_OK) { return false; } @@ -192,319 +526,136 @@ bool Graphics::Init( HINSTANCE _instance, int _screenWidth, int _screenHeight, i ddsd.dwWidth = mPhysicalWidth; ddsd.dwHeight = mPhysicalHeight; ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN; - result = mDirectDraw->CreateSurface( &ddsd, &mSurfaceSecondary, NULL ); - if ( result != DD_OK ) + result = mDirectDraw->CreateSurface(&ddsd, &mSurfaceSecondary, NULL); + if (result != DD_OK) { return false; } - mBPP = GetDeviceCaps( GetDC( mHWnd ), BITSPIXEL ); + mBPP = GetDeviceCaps(GetDC(mHWnd), BITSPIXEL); } - ShowCursor( FALSE ); - - mWantsToQuit = false; - - return 1; + return true; } -void Graphics::Close() +void GraphicsWindowsDDraw::Close() { - if ( mDirectDraw != NULL ) + if (mDirectDraw != NULL) { - mDirectDraw->SetCooperativeLevel( mHWnd, DDSCL_NORMAL ); - if ( mSurfaceSecondary != NULL ) + mDirectDraw->SetCooperativeLevel(mHWnd, DDSCL_NORMAL); + if (mSurfaceSecondary != NULL) { mSurfaceSecondary->Release(); mSurfaceSecondary = NULL; } - if ( mSurfacePrimary != NULL ) + if (mSurfacePrimary != NULL) { mSurfacePrimary->Release(); mSurfacePrimary = NULL; } mDirectDraw->Release(); } - if ( mPhysicalScreen ) - { - delete[] mPhysicalScreen; - mPhysicalScreen = NULL; - } - DestroyWindow( mHWnd ); -} + if (mhDDraw != NULL) + FreeLibrary(mhDDraw); -void Graphics::HandleMessages() -{ - MSG msg; - if ( PeekMessage( &msg, mHWnd, 0U, 0U, PM_REMOVE ) ) - { - TranslateMessage( &msg ); - DispatchMessage( &msg ); - } + GraphicsWindows::Close(); } -void Graphics::Update( void * _buffer, int _width, int _height ) +void GraphicsWindowsDDraw::Blit(void* _buffer) { - int zoom = mIntegerZoom; - if ( zoom == -1 ) - { - zoom = 1; - while ( _width * zoom <= mPhysicalWidth && _height * zoom <= mPhysicalHeight ) - { - zoom++; - } - zoom--; - } - - int zoomedX = _width * zoom; - int zoomedY = _height * zoom; - int mCenterX = ( mPhysicalWidth - zoomedX ) / 2; - int mCenterY = ( mPhysicalHeight - zoomedY ) / 2; - -#ifdef _DEBUG - memset( mPhysicalScreen, 0x30, mPhysicalWidth * mPhysicalHeight * sizeof( unsigned int ) ); -#else - memset( mPhysicalScreen, 0x00, mPhysicalWidth * mPhysicalHeight * sizeof( unsigned int ) ); -#endif // _DEBUG - - unsigned int * src = (unsigned int *) _buffer; - unsigned int * dst = (unsigned int *) mPhysicalScreen + mCenterY * mPhysicalWidth + mCenterX; - for ( int y = 0; y < _height; y++ ) - { - unsigned int * srcline = NULL; - - srcline = src; - for ( int x = 0; x < _width; x++ ) - { - for ( int xz = 0; xz < zoom; xz++ ) - { - *( dst++ ) = *srcline; - } - srcline++; - } - dst += mPhysicalWidth - ( _width * zoom ); - - for ( int yz = 1; yz < zoom; yz++ ) - { - memcpy( dst, dst - mPhysicalWidth, zoomedX * sizeof( unsigned int ) ); - dst += mPhysicalWidth; - } - src = srcline; - } - - Blit( mPhysicalScreen ); -} - -void Graphics::Blit( void * _buffer ) -{ - unsigned int * vscr = (unsigned int *) _buffer; + uint32_t* vscr = (unsigned int*)_buffer; DDSURFACEDESC2 ddsdBack; - ZeroMemory( &ddsdBack, sizeof( DDSURFACEDESC ) ); - ddsdBack.dwSize = sizeof( ddsdBack ); - if ( mSurfaceSecondary->Lock( 0, &ddsdBack, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, 0 ) == DD_OK ) + ZeroMemory(&ddsdBack, sizeof(DDSURFACEDESC)); + ddsdBack.dwSize = sizeof(ddsdBack); + if (mSurfaceSecondary->Lock(0, &ddsdBack, DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT, 0) == DD_OK) { - long noMansLandSizeInBytes = ddsdBack.lPitch - ddsdBack.dwWidth * ( ( mBPP + 1 ) / 8 ); + long noMansLandSizeInBytes = ddsdBack.lPitch - ddsdBack.dwWidth * ((mBPP + 1) / 8); LPVOID surfacePtr = ddsdBack.lpSurface; - switch ( mBPP ) - { - case 32: - __asm - { - push es - mov ax, ds - mov es, ax - mov esi, [ vscr ] - mov edi, [ surfacePtr ] - mov ecx, [ ddsdBack.dwHeight ] - Oneline32: - push ecx - mov ecx, [ ddsdBack.dwWidth ] - rep movsd - add edi, [ noMansLandSizeInBytes ] - pop ecx - loop Oneline32 - pop es - } break; - case 24: - __asm - { - push es - mov ax, ds - mov es, ax - mov esi, [ vscr ] - mov edi, [ surfacePtr ] - mov ecx, [ ddsdBack.dwHeight ] - Oneline24: - push ecx - mov ecx, [ ddsdBack.dwWidth ] - Onepix24 : - movsw - movsb - inc esi - loop Onepix24 - add edi, [ noMansLandSizeInBytes ] - pop ecx - loop Oneline24 - pop es - } break; - case 16: - __asm - { - push es - mov ax, ds - mov es, ax - mov esi, [ vscr ] - mov edi, [ surfacePtr ] - mov ecx, [ ddsdBack.dwHeight ] - Oneline16: - push ecx - mov ecx, [ ddsdBack.dwWidth ] - Onepix16 : - lodsd - shr ax, 2 - shl al, 2 - shr ax, 3 - mov bx, ax - shr eax, 8 - and ax, 1111100000000000b - or ax, bx - stosw - loop Onepix16 - add edi, [ noMansLandSizeInBytes ] - pop ecx - loop Oneline16 - pop es - } break; - case 15: - __asm - { - push es - mov ax, ds - mov es, ax - mov esi, [ vscr ] - mov edi, [ surfacePtr ] - mov ecx, [ ddsdBack.dwHeight ] - Oneline15: - push ecx - mov ecx, [ ddsdBack.dwWidth ] - Onepix15 : - lodsd - shr ax, 3 - shl al, 3 - shr ax, 3 - mov bx, ax - shr eax, 9 - and ax, 0111110000000000b - or ax, bx - stosw - loop Onepix15 - add edi, [ noMansLandSizeInBytes ] - pop ecx - loop Oneline15 - pop es - } break; - } + FastBlit(vscr, surfacePtr, mBPP, ddsdBack.dwWidth, ddsdBack.dwHeight, noMansLandSizeInBytes); - mSurfaceSecondary->Unlock( NULL ); + mSurfaceSecondary->Unlock(NULL); } - HRESULT hRes = NULL; - if ( mWindowType == WindowType::Fullscreen ) - { - hRes = mSurfacePrimary->Flip( NULL, NULL ); - } - else - { - hRes = mSurfacePrimary->Blt( &mRectScreen, mSurfaceSecondary, &mRectViewport, DDBLT_WAIT, NULL ); - } + HRESULT hRes = (mWindowType == WindowType::Fullscreen) + ? mSurfacePrimary->Flip(NULL, NULL) + : mSurfacePrimary->Blt(&mRectScreen, mSurfaceSecondary, &mRectViewport, DDBLT_WAIT, NULL); - if ( hRes == DDERR_SURFACELOST ) + if (hRes == DDERR_SURFACELOST) { mSurfacePrimary->Restore(); } } -LRESULT CALLBACK Graphics::WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +/* ---------------------------------------------------------------------------------------------- */ +/* GraphicsWindowsGDI */ + +GraphicsWindowsGDI::GraphicsWindowsGDI() + : GraphicsWindows() + , mBITMAP(NULL) + , mBmpBuf(NULL) { - switch ( uMsg ) - { - case WM_MOVE: - { - GetWindowRect( hWnd, &mRectWindow ); - GetClientRect( hWnd, &mRectViewport ); - GetClientRect( hWnd, &mRectScreen ); - ClientToScreen( hWnd, (POINT *) &mRectScreen.left ); - ClientToScreen( hWnd, (POINT *) &mRectScreen.right ); - } - break; +} - case WM_PAINT: - { - if ( mWindowType == WindowType::Fullscreen ) - { - return 0; - } - } - break; +GraphicsWindowsGDI::~GraphicsWindowsGDI() +{ + Close(); +} - case WM_KEYDOWN: - { - switch ( wParam ) - { - case VK_ESCAPE: - { - PostMessage( hWnd, WM_QUIT, 0, 0 ); - mWantsToQuit = true; - return 0L; - } - break; - } - } - break; +bool GraphicsWindowsGDI::Init(int width, int height, int zoom, WindowType type) +{ + BITMAPINFO bmi = { 0 }; + HDC hdc; - case WM_CLOSE: - case WM_DESTROY: - { - mWantsToQuit = true; - PostMessage( hWnd, WM_QUIT, 0, 0 ); - } - break; + if (!GraphicsWindows::Init(width, height, zoom, type)) + return false; - case WM_SYSCOMMAND: - { - switch ( wParam ) - { - case SC_SCREENSAVE: - case SC_MONITORPOWER: - { - return 0; - } - } - break; - } - break; + /* now initialize our bitmap :) */ + bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; /* bitmaps are negative */ + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; + bmi.bmiHeader.biCompression = BI_RGB; - } - return DefWindowProc( hWnd, uMsg, wParam, lParam ); -} + hdc = GetDC(mHWnd); + + mBITMAP = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**)&mBmpBuf, NULL, 0); + if (!mBITMAP || !mBmpBuf) + return false; -Graphics * pGlobalDisp = NULL; + ReleaseDC(mHWnd, hdc); + + return true; +} -LRESULT CALLBACK Graphics::WndProcStatic( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ) +void GraphicsWindowsGDI::Close() { - if ( uMsg == WM_CREATE ) - { - CREATESTRUCT * createStruct = (CREATESTRUCT *) lParam; // todo: split to multiple hWnd-s! (if needed) - pGlobalDisp = (Graphics *) createStruct->lpCreateParams; + if (mBITMAP) { + DeleteObject(mBITMAP); + mBITMAP = NULL; + mBmpBuf = NULL; } +} - if ( !pGlobalDisp->WndProc( hWnd, uMsg, wParam, lParam ) ) - { - return 0; - } +void GraphicsWindowsGDI::Blit(void *buffer) +{ + HDC hdc; + HDC hdcMem; + HGDIOBJ old; - return DefWindowProc( hWnd, uMsg, wParam, lParam ); -} \ No newline at end of file + hdc = GetDC(mHWnd); + hdcMem = CreateCompatibleDC(hdc); + old = SelectObject(hdcMem, mBITMAP); + + /* i'm looking for somebody who is 4 */ + memcpy(mBmpBuf, buffer, mPhysicalWidth * mPhysicalHeight * 4); + + BitBlt(hdc, 0, 0, mPhysicalWidth, mPhysicalHeight, hdcMem, 0, 0, SRCCOPY); + + SelectObject(hdcMem, old); + DeleteDC(hdcMem); + ReleaseDC(mHWnd, hdc); +} diff --git a/Graphics.h b/Graphics.h index 6c9d6f1..0518c53 100644 --- a/Graphics.h +++ b/Graphics.h @@ -1,5 +1,9 @@ +#ifndef GRAPHICS_H_ +#define GRAPHICS_H_ + #include #include +#include class Graphics { @@ -12,38 +16,97 @@ class Graphics }; Graphics(); - ~Graphics(); + virtual ~Graphics(); + + void Update(void *buffer, int width, int height); + + virtual bool Init( int _width, int _height, int _zoom, WindowType _fullscreen ); + virtual void Close(); + + virtual void HandleMessages() = 0; + + virtual const bool WantsToQuit() const = 0; + +protected: + virtual void Blit( void * _screenBuffer ) = 0; + + /* fast blit function from 32-bit -> some bpp */ + static void FastBlit(const uint32_t* vscr, void* surfacePtr, int bpp, + uint32_t width, uint32_t height, uint32_t noMansLandSizeInBytes); + + int mPhysicalWidth; + int mPhysicalHeight; + int mIntegerZoom; + + WindowType mWindowType; + uint32_t *mPhysicalScreen; +}; + +/* graphics stuff specific to Windows */ +class GraphicsWindows : public Graphics +{ +public: + GraphicsWindows(); + virtual ~GraphicsWindows(); - bool Init( HINSTANCE _instance, int _width, int _height, int _zoom, WindowType _fullscreen ); - void Update( void * _screenBuffer, int _screenWidth, int _screenHeight ); - void HandleMessages(); - void Close(); + virtual bool Init( int _width, int _height, int _zoom, WindowType _fullscreen ) override; + virtual void HandleMessages() override; + virtual void Close() override; - const bool WantsToQuit() const { return mWantsToQuit; } - const HWND GetWindowHandle() const { return mHWnd; } + virtual const bool WantsToQuit() const override { return mWantsToQuit; } -private: - void Blit( void * _screenBuffer ); +protected: + /* handled by gdi/ddraw/etc */ + virtual void Blit( void * _screenBuffer ) = 0; + /* and now to the goodies */ static LRESULT CALLBACK WndProcStatic( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); LRESULT CALLBACK WndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); - LPDIRECTDRAW7 mDirectDraw; - LPDIRECTDRAWSURFACE7 mSurfacePrimary; - LPDIRECTDRAWSURFACE7 mSurfaceSecondary; - int mBPP; - RECT mRectWindow; RECT mRectViewport; RECT mRectScreen; HWND mHWnd; - - int mPhysicalWidth; - int mPhysicalHeight; - int mIntegerZoom; bool mWantsToQuit; - WindowType mWindowType; - unsigned int * mPhysicalScreen; -}; \ No newline at end of file +}; + +class GraphicsWindowsDDraw : public GraphicsWindows +{ +public: + GraphicsWindowsDDraw(); + virtual ~GraphicsWindowsDDraw(); + + virtual bool Init(int width, int height, int zoom, WindowType type) override; + virtual void Close() override; + +protected: + virtual void Blit(void* buffer) override; + + LPDIRECTDRAW7 mDirectDraw; + LPDIRECTDRAWSURFACE7 mSurfacePrimary; + LPDIRECTDRAWSURFACE7 mSurfaceSecondary; + int mBPP; /* BITS per pixel */ + + /* needs to stay in memory for as long as graphics are open */ + HMODULE mhDDraw; +}; + +class GraphicsWindowsGDI : public GraphicsWindows +{ +public: + GraphicsWindowsGDI(); + virtual ~GraphicsWindowsGDI(); + + virtual bool Init(int width, int height, int zoom, WindowType type) override; + virtual void Close() override; + +protected: + virtual void Blit(void* buffer) override; + + HBITMAP mBITMAP; + uint32_t* mBmpBuf; +}; + +#endif /* GRAPHICS_H_ */ \ No newline at end of file diff --git a/SecondRealityW32.vcxproj b/SecondRealityW32.vcxproj index ab5d6e6..f08e177 100644 --- a/SecondRealityW32.vcxproj +++ b/SecondRealityW32.vcxproj @@ -37,7 +37,7 @@ Application false - v143 + v142 true Unicode @@ -98,7 +98,7 @@ Console true - ddraw.lib;dxguid.lib;winmm.lib;%(AdditionalDependencies) + dxguid.lib;winmm.lib;%(AdditionalDependencies) true diff --git a/main.cpp b/main.cpp index 8cb65be..3d97c0c 100644 --- a/main.cpp +++ b/main.cpp @@ -51,7 +51,7 @@ extern "C" void end_music(); unsigned int * screen32; -Graphics graphics; +static Graphics *graphics = NULL; extern "C" void demo_blit(); @@ -77,7 +77,7 @@ void demo_blit() printf( "%04X %04X | %04X %4d | %d\r", order, row, plus, (short)plus, frame ); #endif - graphics.HandleMessages(); + graphics->HandleMessages(); if ( demo_screen_width == 320 && demo_screen_height == 200 ) { @@ -133,13 +133,13 @@ void demo_blit() } #endif - graphics.Update( screen32, virtual_screen_width, virtual_screen_height ); + graphics->Update( screen32, virtual_screen_width, virtual_screen_height ); } extern "C" bool demo_wantstoquit(); bool demo_wantstoquit() { - return graphics.WantsToQuit(); + return graphics->WantsToQuit(); } double currentTime = 0.0; @@ -188,6 +188,7 @@ void demo_vsync() int main( int argc, char * argv[] ) { + // should dynload this, this is Vista+ --paper ::SetProcessDPIAware(); // self-modifying code everywhere, wahey! @@ -242,12 +243,27 @@ int main( int argc, char * argv[] ) break; } #endif // _DEBUG - if ( !graphics.Init( GetModuleHandle( NULL ), windowWidth, windowHeight, -1, windowType ) ) - { - return -3; - } - screen32 = new unsigned int[ virtual_screen_width * virtual_screen_height ]; +#define TRY_GRAPHICS(x) \ +do { \ + if (graphics) delete graphics; \ +\ + graphics = new Graphics##x; \ +\ + if (graphics->Init(windowWidth, windowHeight, -1, windowType)) \ + goto BS_havegraphics; \ +} while (0) + + TRY_GRAPHICS(WindowsDDraw); + TRY_GRAPHICS(WindowsGDI); + + if (graphics) delete graphics; + + return -3; + +BS_havegraphics: + + screen32 = new uint32_t[ virtual_screen_width * virtual_screen_height ]; ZeroMemory( screen32, virtual_screen_width * virtual_screen_height * sizeof( unsigned int ) ); typedef struct @@ -359,7 +375,7 @@ int main( int argc, char * argv[] ) end_music(); delete[] screen32; - graphics.Close(); + graphics->Close(); return 0; } From 699c9fe3524a3d24bbbb905fac81b44302002218 Mon Sep 17 00:00:00 2001 From: Paper Date: Sun, 3 Aug 2025 19:15:57 -0400 Subject: [PATCH 2/2] music: fix build in vs2019 thanks microsoft, very cool --- music.c | 1 + 1 file changed, 1 insertion(+) diff --git a/music.c b/music.c index 461d8d5..ca86a12 100644 --- a/music.c +++ b/music.c @@ -1,3 +1,4 @@ +#define _CRT_SECURE_NO_WARNINGS #include unsigned char * reality_fc_data = NULL;