DirectDraw输出适应

时间:2016-08-05 18:01:40

标签: windows assembly gdi directdraw

我正在开发一个项目来为旧游戏添加功能;我们的想法是添加运行窗口的选项(原来它只支持800x600全屏)。

到目前为止,我修改了directDraw的初始化以删除全屏独占模式,并使其能够与GDI一起工作,创建一个限幅器并正确设置所有内容,游戏将全屏模式设置为8位颜色深度,运行它窗口导致它输出像这个图像的垃圾:

Game output running windowed

到目前为止,我尝试使用GetDIBits和SetDIBits来解决问题,但我没有成功。

游戏使用的是一个非常古老的directDraw版本(关于这个版本没有任何文档,我的大部分工作都基于猜测和测试)。

游戏使用BltFast将信息提供给屏幕。

以下是为尝试使用DIBits

解决问题而编写的一段代码

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 

有没有办法可以直接从缓冲区转换8位颜色格式,方法是将调用更改为BltFast以正确输出到屏幕上?

将输出重新路由到另一个DC然后使用GetDIBits / SetDIBits来修复图像是否是更好的解决方案?

2 个答案:

答案 0 :(得分:1)

经过大量的研究,我发现了一个包装器(正如Ross Ridge所建议的那样)可以解决这个问题并强制游戏与openGL协同工作,并且还可以实现许多简洁的功能,并且即使与第一个版本兼容也是如此ddraw

https://sourceforge.net/p/dxwnd

答案 1 :(得分:0)

原始游戏是8位,所以它依赖于调色板。 GetDIBits将使用与其DC相关联的当前调色板,以便将8位像素值转换为您使用bitmapHeader请求的32位值。

我认为这是问题的第一部分,因为游戏的DC可能没有选择和实现调色板。由于它是在独占模式下使用DirectDraw,它可能直接在视频卡中设置调色板,而GDI没有关于调色板是什么的概念。

要解决这个问题,我认为您需要找到设置和修改调色板的代码,然后在执行GetDIBits之前明确选择并在游戏的DC中实现该调色板。

之后,我不清楚你是如何将像素带到窗口DC的。你似乎创建了一个与窗口兼容的内存DC,然后使用SetDIBits来获取数据,但是我没有看到你从内存DC到实际窗口DC的位置。