2016-08-05 25 views
0

我正在開發一個項目,爲舊遊戲添加功能;這個想法是添加運行窗口選項(最初它只支持800x600全屏)。DirectDraw輸出自適應

到目前爲止,我修改了directDraw的初始化以刪除全屏獨佔模式並使其能夠與GDI一起工作,創建了一個剪輯器並正確設置了所有事情,遊戲將全屏模式設置爲8位顏色深度,運行窗口它會導致這樣的圖像輸出垃圾:

Game output running windowed

到目前爲止,我試圖做使用的GetDIBits和SetDIBits來解決這個問題一些技巧,但我沒有成功。

該遊戲適用於一個非常古老的directDraw版本(沒有關於此版本的文檔,大部分工作都基於猜測和測試)。

遊戲使用BltFast獲取信息到屏幕。

這裏是一塊已寫入嘗試使用雙位

PrimarySurface =遊戲主表面本身

patch_1: 
    ; Blt interface 
    CALL DWORD [EDX+1Ch] ;<--- Surface->BltFast() Outputs game screen, params pushed to stack elsewhere 

    pushad 

    ; Get diBits and transform it properly to display 
    push surfaceDC 
    mov eax, [PrimarySurface] 
    mov edx, [eax] 
    push eax 
    call dword [edx+44h] ; Surface->GetDC(&surfaceDC) 
    test eax, eax 
    je patch_1_abort 
    invoke FindWindowA, 0, 'Rising Lands' 
    mov [windowHandle], eax 
    invoke GetDC, eax 
    mov [windowDC], eax 
    invoke CreateCompatibleDC, [surfaceDC] 
    mov [compatibleDC], eax 
    invoke CreateCompatibleDC, [windowDC] 
    mov [compatibleWindowDC], eax 
    invoke CreateCompatibleBitmap, [windowDC], 800, 600 
    mov [zbitmap], eax 

    ; Get screen header 
    invoke GetDIBits, [compatibleWindowDC], [zbitmap], 0, 0, 0, bitmapHeader, 0 

    ; Get game screen data 
    invoke GetDIBits, [compatibleDC], [zbitmap], 0, 600, bbuffer, bitmapHeader, 0 

    ; Copy content back to screen 
    invoke SetDIBits, [compatibleWindowDC], [zbitmap], 0, 600, bbuffer, bitmapHeader, 0 

    ; Release 
    push [surfaceDC] 
    mov eax, [PrimarySurface] 
    mov edx, [eax] 
    push eax 
    call dword [edx+68h] 

    patch_1_abort: 
    popad 

    ; Original code finalization 
    MOV EDX,EAX 
    TEST EAX, EAX 
    jmp [p1r] 

    surfaceDC dd 0 
    windowHandle dd 0 
    windowDC dd 0 
    compatibleDC dd 0 
    compatibleWindowDC dd 0 
    zbitmap dd 0 


    bitmapInfo dd bitmapHeader 
    dd 0 

    bitmapHeader: 
    hSize dd endHeader - bitmapHeader 
    hWidth dd 0;800 
    hHeight dd 0;600 
    hPlanes dw 0;1 
    hBitCount dw 0;32 
    hCompression dd 0 
    hSizeImage dd 0 
    hxPPm dd 0 
    hyPPm dd 0 
    hClrUsed dd 0 
    hClrImp dd 0 
    endHeader: 

    bbuffer rb 800*600*10 

來解決該問題的代碼是有什麼辦法可以轉換的8bit色彩格式通過改變調用BltFast直接從緩衝區直接輸出到屏幕?

它是一個更好的解決方案,重新路由輸出到另一個DC然後使用GetDIBits/SetDIBits來修復圖像?

+3

它看起來的版本或者你的源格式是不是您所期望它是或者你的目標不是。你確定遊戲沒有使用800x600x4(16種顏色)嗎?無論如何,我認爲你會錯誤地採用這種方式,我根本不會使用GDI。我只寫了一個DirectDraw封裝器,它使用DirectDraw窗口模式來模擬獨佔模式。無需修補可執行文件或使用程序集。只需將您自己的DDRAW.DLL轉儲到同一個目錄即可。已經有至少一個程序,誰的名字逃脫我,這已經這樣做。 –

+0

我有點新DirectDraw,所以我真的不知道我將如何模仿基於全屏的窗口模式,你有任何參考?此外,遊戲使用ddraw的極其舊的版本,我猜想windows會切換到某些兼容版本(如果您使用隨遊戲分發的ddraw,根本沒有任何工作) –

+0

DirectDraw 7仍在線記錄:https:// msdn.microsoft.com/en-us/library/windows/desktop/gg426124.aspx –

回答

1

經過大量的研究,我發現了一個封裝(如Ross Ridge所建議的),它可以實現這個技巧,並且可以強制遊戲與openGL一起工作,並且還可以使用很多整齊的功能,並且與第一個DDRAW

https://sourceforge.net/p/dxwnd

0

原來的遊戲是8位的,所以它依賴於一個調色板。 GetDIBits將使用與其DC相關聯的當前調色板,以便將8位像素值轉換爲您在bitmapHeader中請求的32位值。

我認爲這是問題的第一部分,因爲遊戲的DC可能沒有選擇和實現調色板。由於它是在獨佔模式下使用DirectDraw,因此可能直接在顯卡中設置調色板,而GDI不知道該調色板是什麼。

爲了解決這個問題,我認爲你需要找到設置和修改調色板的代碼,然後在你執行GetDIBits之前明確地選擇並實現調色板到遊戲的DC中。

之後,我不清楚你是如何獲得窗口DC的像素。您似乎創建了一個與窗口兼容的內存DC,然後使用SetDIBits將數據提供給它,但是我沒有看到從存儲器DC到實際窗口DC的哪個位置。

+0

截圖顯示遊戲運行沒有使用Dibits方法的實際修復(如我所說,它並沒有真正的工作);我的想法是從表面獲取DC,然後獲取目標窗口BitmapInfo來指定DIB格式,然後最終複製數據。你會有關於你提到的方法的代碼示例嗎?遊戲確實創建了一個調色板,我確實可以訪問它。 –

+0

我沒有代碼示例,但基本模式是調用CreatePalette,然後使用SelectPalette將其選中到DC中。選中它之後,您可能還需要調用RealizePalette,但我不確定是否需要爲DC類型的最後一步。 –

+1

要獲取數據到窗口,您可能可以跳過內存DC,並使用SetDIBitsToDevice直接將像素數據獲取到窗口DC。 –