2016-08-05 22 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。 –