添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

I'm gho author of the DxWnd tool that tries to provide support to run old and legacy programs on modern windows environment.

A very strange game is G-Nome that, despite being able to run natively on Win7-10 systems, brings a serious problem for graphic manipulation.

The game links to ddraw, but builds every frame as a DIB_PAL_COLORS DIB and brings the DIB to screen using SetDIBitsToDevice user32 calls. The operation is supported by OBJ_DC type DC on video also on 32 bit color depth video modes, but produces bad colors when applied to MEM_DC type DC. I found this while trying to scale the DIB using a typical schema like this (variable declarations and error checking stripped for brevity):

hTempDc=CreateCompatibleDC(hdc);
hbmPic=CreateCompatibleBitmap(hdc, OrigWidth, OrigHeight);
SelectObject(hTempDc, hbmPic);
SetDIBitsToDevice(hTempDc, 0, 0, OrigWidth, OrigHeight, XSrc, YSrc, uStartScan, cScanLines, lpvBits, lpbmi, fuColorUse);
StretchBlt(hdc, XDest, YDest, dwWidth, dwHeight, hTempDc, 0, 0, OrigWidth, OrigHeight, SRCCOPY);

According to MSDN, when you output a DIB_PAL_COLORS DIB the pixels are mapped to the "current" realized palette, but of course on a 32 bit surface and on its memory DC clone there is no palette at all, so it's no wonder that the pixel colors look all wrong.

An alternative solution could be to emulate the SetDIBitsToDevice behaviour building a 32 bit memory DC to be then scaled at will with StretchBlt, but again it is not documented how I could convert a 8bpp DIB_PAL_COLORS DIB to either a 32bpp DIB_RGB_DIB or a 32bpp DC.

I already tried in several ways, but in all cases it seems that I can't identify the correct palette to be used to convert pixel indices. Could someone help me to interpret the 8bpp DIB_PAL_COLORS DIB format?

Also tried to add a SelectObject with the current palette, but with no avail: the GetCurrentObject(hdc, OBJ_PAL) returns NULL. – gho Nov 27, 2017 at 15:58

If I understand the question correctly, you have a source image in the form of a DIB with a color table and you want to get that image onto a non-palette DC using SetDIBitsToDevice.

I haven't worked with palettes in a very long time, but, if I recall correctly, you cannot use DIB_PAL_COLORS unless the destination DC is a palette device. It seems unlikely that your memory DC is a palette device, but you can check:

GetDeviceCaps(hTempDc, RASTERCAPS) & RC_PALETTE

Assuming it's not a palette device, I think you have to use DIB_RGB_COLORS for fuColorUse. SetDIBitsToDevice will use each pixel's index to look up the corresponding RGBQUAD value in the color table. (The color table comes after the BITMAPINFOHEADER in the BITMAPINFO pointed to by lpbmi.) The RGBQUAD values are applied pixel-by-pixel to the destination device.

If you still have problems, I'd look closely at the BITMAPINFO and the color table you're providing to make sure they correctly represent the format of the pixel data and the corresponding color table.

Unfortunately, I don't have that freedom of choice. DxWnd is an API hooker, that is intercepts library calls such as GDI32, USER32 or DDRAW and reroutes the program flow to hooker routines. It is looking at the logs that I discovered that the G-Nome PC game renders frames to video by calling SetDIBitToDevice calls having DIB_PAL_COLORS images in input. So, I can write a hooker routine that receives the same inputs and should blit the DIB to a window surface with custom size and in desktop native color depth, but I can't change the way the program executable (without available C code) works. – gho Nov 27, 2017 at 19:43 Unless I'm misunderstanding the question, you don't have to change the source game. It's your hook function that needs to do the right thing. – Adrian McCarthy Nov 27, 2017 at 20:50 I am confused: According to MSDN a DIB_RGB_COLORS DIB has BITMAPINFOHEADER followed by the RGBQUAD array while a DIB_PAL_COLORS DIB is followed by the array of WORD indices to the palette (that my memory dumps show to be just after the index array) so that declaring a different ColorUse value should lead random colors. As a matter of fact, I did what you suggested and the result was one of the best I ever had: most colors are ok, but looking at the screenshots there is simply a big percentage of magenta pixels, which makes me think that we're close but we have a transparency problem ... – gho Nov 28, 2017 at 8:56 Is there a way to upload screenshots here? If you want to see the result, I can upload somewhere and add a link. – gho Nov 28, 2017 at 8:57 I think I know why there's such a large amount of magenta color: dumping the memory content you can find the Index table next to BITMAPINFOHEADER. The index table is 258 words with progressive numbers, dumped as bytes it is like this: 01,00,02,00...FE,00,FF,00. But if you consider these as RGBQUAD palette entries, these are all (nn,00,nn+1,00) = red+blue=magenta colors with no green and no alpha. So, the bitmap uses a wrong half palette. – gho Nov 28, 2017 at 12:43

Oh, I think I got the culprit: another DxWnd hooker was faking the RC_PALETTE capability in GetDeviceCaps(). Removing that fake capability the game no longer tries to use DIB_PAL_COLORS format and builds more manageable DIB_RGB_COLORS DIBs. Problem fixed, sorry for the false track and thank you for helping.

Thanks for contributing an answer to Stack Overflow!

  • Please be sure to answer the question. Provide details and share your research!

But avoid

  • Asking for help, clarification, or responding to other answers.
  • Making statements based on opinion; back them up with references or personal experience.

To learn more, see our tips on writing great answers.