DirectDraw输出适配

DirectDraw output adaptation

我正在做一个为老游戏添加功能的项目;这个想法是将选项添加到 运行 它窗口化(最初它只支持 800x600 全屏)。

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

到目前为止,我尝试使用 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 

有什么方法可以通过更改对 BltFast 的调用以正确输出到屏幕来直接从缓冲区转换 8 位颜色格式?

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

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

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

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

在那之后,我不清楚您是如何将像素获取到 window DC 的。您似乎创建了一个与 window 兼容的内存 DC,然后使用 SetDIBits 获取数据,但我看不到您从内存 DC 到实际 window DC 的位置.

经过大量研究,我找到了一个包装器(如 Ross Ridge 所建议的那样),它可以解决问题并强制游戏与 openGL 一起工作,并且还支持许多简洁的功能,甚至与ddraw

的第一个版本

https://sourceforge.net/p/dxwnd