【问题标题】:DirectDraw output adaptationDirectDraw 输出适配
【发布时间】:2016-08-09 22:20:52
【问题描述】:

我正在做一个项目,为旧游戏添加功能;这个想法是添加选项以窗口化运行它(最初它只支持 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 

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

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

【问题讨论】:

  • 看起来您的源格式不是您期望的格式,或者您的目标格式不是。你确定游戏没有使用 800x600x4(16 色)吗?无论如何,我认为你的做法是错误的,我根本不会使用 GDI。我只是编写一个 DirectDraw 包装器,它使用 DirectDraw 窗口模式模拟独占模式。无需修补可执行文件或使用程序集。只需将您自己的 DDRAW.DLL 转储到同一目录中即可。至少已经有一个程序,我不知道他的名字,它已经做到了。
  • 我是 DirectDraw 的新手,所以我真的不知道如何基于全屏模拟窗口模式,您对此有什么参考吗?另外,游戏使用了一个非常旧的ddraw版本,我猜windows会切换到一些兼容版本(如果你使用游戏分发的ddraw,什么都不会起作用)
  • 我找到了“DirectDraw hack”,这似乎是您提到的修复方法;它不适用于我正在使用的游戏,但我会尝试使其适应我的情况。不过,我想将 8 位图像转换为 32 位应该更容易,我只是不知道到目前为止如何正确地得到这个

标签: windows assembly gdi directdraw


【解决方案1】:

经过大量研究,我找到了一个包装器(正如 Ross Ridge 所建议的那样),它可以解决问题并强制游戏与 openGL 一起使用,并且还启用了许多简洁的功能,并且即使与第一个版本也兼容画法

https://sourceforge.net/p/dxwnd

【讨论】:

    【解决方案2】:

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

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

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

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

    【讨论】:

    • 屏幕截图显示了游戏在没有使用 Dibits 方法进行实际修复的情况下运行(正如我所提到的,它并没有真正起作用);我的想法是从表面获取 DC,然后获取目标窗口 BitmapInfo 以指定 DIB 格式,然后最终复制数据。您是否有关于您提到的方法的代码示例?游戏确实创建了一个调色板,我可以访问它。
    • 我没有代码示例,但基本模式是调用 CreatePalette,然后使用 SelectPalette 将其选中到 DC。选择它后,您可能还需要调用 RealizePalette,但我不确定您拥有的 DC 类型是否需要最后一步。
    • 要获取数据到窗口,可以跳过内存DC,直接使用SetDIBitsToDevice获取像素数据到窗口DC。
    猜你喜欢
    • 1970-01-01
    • 2011-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多