Search code examples
windowsassemblygdidirectdraw

DirectDraw output adaptation


I'm working on a project to add functionality to an old game; the idea is to add the option to run it windowed (originally it only supports 800x600 fullscreen).

So far, i modified directDraw's initialization to remove fullscreen exclusive mode and to enable it to work with GDI, created a clipper and set everything properly the point is, the game sets the fullscreen mode to 8bit color depth, running it windowed causes it to output garbage like this image:

Game output running windowed

So far i tried to do some tricks using GetDIBits and SetDIBits to work around the problem but i had no success.

The game works with a very old directDraw version (there is no documentation at all about this version, most of my work is based on guesses and tests).

The game uses BltFast to get information to the screen.

Here is a piece of the code that was written to try to fix the issue using DIBits

PrimarySurface = Game primary surface itself

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 

Is there any way i can convert the 8bit color format directly from the buffer by changing the call to BltFast to output correctly to the screen?

Is it a better solution to reroute the output to another DC to then use GetDIBits/SetDIBits to fix the image?


Solution

  • After a lot of research, i found a wrapper (as suggested by Ross Ridge) that does the trick and forces the game to work with openGL and also enables a lot of neat features as well and is compatible even with the first versions of ddraw

    https://sourceforge.net/p/dxwnd