DirectDraw выходной адаптации

Я работаю над проектом, чтобы добавить функциональность в старую игру; Идея состоит в том, чтобы добавить опцию, чтобы запустить его в окне (первоначально он поддерживает только 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 для исправления изображения?

2 ответа

Решение

После долгих исследований я нашел обертку (как предложил Росс Ридж), которая делает трюк и заставляет игру работать с openGL, а также включает множество полезных функций и совместима даже с первыми версиями ddraw.

https://sourceforge.net/p/dxwnd

Оригинальная игра 8-битная, поэтому она опирается на палитру. GetDIBits будет использовать текущую палитру, связанную с его DC, чтобы преобразовать 8-битные значения пикселей в 32-битные значения, которые вы запрашиваете с помощью bitmapHeader.

Я думаю, что это первая часть проблемы, так как DC игры, вероятно, не имеет выбранной и реализованной палитры. Поскольку он использовал DirectDraw в монопольном режиме, он, вероятно, устанавливал палитру непосредственно в видеокарте, и GDI понятия не имел, что это за палитра.

Чтобы решить эту проблему, я думаю, вам нужно будет найти код, который устанавливает и изменяет палитру, а затем явно выбирать и реализовывать эту палитру в DC игры, прежде чем вы начнете делать GetDIBits.

После этого мне непонятно, как вы получаете пиксели в окне DC. Похоже, вы создаете DC памяти, совместимый с окном, а затем используете SetDIBits для получения данных в него, но я не вижу, куда вы затем переместитесь из DC памяти в фактический DC окна.

Другие вопросы по тегам