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.
Оригинальная игра 8-битная, поэтому она опирается на палитру. GetDIBits будет использовать текущую палитру, связанную с его DC, чтобы преобразовать 8-битные значения пикселей в 32-битные значения, которые вы запрашиваете с помощью bitmapHeader.
Я думаю, что это первая часть проблемы, так как DC игры, вероятно, не имеет выбранной и реализованной палитры. Поскольку он использовал DirectDraw в монопольном режиме, он, вероятно, устанавливал палитру непосредственно в видеокарте, и GDI понятия не имел, что это за палитра.
Чтобы решить эту проблему, я думаю, вам нужно будет найти код, который устанавливает и изменяет палитру, а затем явно выбирать и реализовывать эту палитру в DC игры, прежде чем вы начнете делать GetDIBits.
После этого мне непонятно, как вы получаете пиксели в окне DC. Похоже, вы создаете DC памяти, совместимый с окном, а затем используете SetDIBits для получения данных в него, но я не вижу, куда вы затем переместитесь из DC памяти в фактический DC окна.