Skip to main content
GameDev.net gamedev.net
🔒 Locked

PCX files decoding

Started by Tomalla Jun 29, 2009 at 6:08 AM 9 replies 3.1k views
Original Post
Tomalla
Tomalla
Hi there, I'm Thomas. I was searching for some informations for almost a month, and I got here :P So, here is my problem: I'm creating a 2D game, using DirectDraw module. However, I have encountered really nasty problem: if my game used bitmaps only ( *.BMP files ), it would get really over-sized ... wouldn't it? So, I'm trying to find, which image format would perfectly fit my needs. After few days of thinking, I've decided to use *.PCX files' format. Here is my aim: decode header, and decode image data ( and store it as DIB data, as an array of BYTEs ). So far, I've successfully decoded header ( with a little help of PCX documentation ). I stopped when trying to decode image data. Even with a help of few different documentations, I didn't make it :( When I was searching the internet, I found this tutorial ( heh, it's from GameDev by the way ): http://www.gamedev.net/reference/articles/article1305.asp I found right there, how to make DIB data displayed on the screen. Now, there's still a question: how to get DIB data? I'm certain, there's a library, just like Intels' JPG one ( from an article above ), which could return DIB data from PCX file on the hard drive. But, I can't find any ;( Could someone give me an advice, how to proceed? Maybe there's a library, like described above? Or maybe PCX was not so good choice? I'm waiting for Your opinion :) Regards, Tomalla
bubu LV
bubu LV
What do you mean "DIB data in PCX"? There is no DIB inside PCX. DIB is BMP specific structure.

You can decode PCX with DevIL library.

I myself would not use PCX format at all. It is old and has not so good compression. I would use PNG files instead (which you can decode, for example, with stb_image). Or bunch of BMP/TGA files inside ZIP/7Z archive. It would compress much better and would load faster than PCX.
Tomalla
Tomalla
Thank you for Your reply!

I'm trying to use stb_image: load file from hard drive, and stretch in on whole screen. The result is really impressive! However, it's not the image that I wanted to load. Have a look:

http://i340.photobucket.com/albums/o324/tomalla5120x/Temporary/temp-2.jpg

For sure, I have messed something up with a code ...

So, here is a function, that creates an off-screen surface based on a image filename:

IDirectDrawSurface7* CreateOSSFromImage(IDirectDraw7* pIDD7, char* pszFileName){   if((pIDD7 == NULL) || (pszFileName == NULL))        return NULL;	   HBITMAP hBitmap = NULL;   int width, height, n;   BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 0);   hBitmap = CreateBitmap(width, height, 2, 8, imageData);      //(HBITMAP)LoadImage(NULL, pszBmpFileName,IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE);    if(hBitmap == NULL) return NULL;   BITMAP BitmapInfo = {0};   GetObject(hBitmap, sizeof(BITMAP), &BitmapInfo); 	   DDSURFACEDESC2 ddSD2 = {0};   ddSD2.dwSize = sizeof(DDSURFACEDESC2);   ddSD2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;   ddSD2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;   ddSD2.dwWidth = BitmapInfo.bmWidth;   ddSD2.dwHeight = BitmapInfo.bmHeight;    IDirectDrawSurface7* pIDDS7 = NULL;   pIDD7->CreateSurface(&ddSD2, &pIDDS7, NULL);   if(pIDDS7 == NULL)   {      DeleteObject(hBitmap);      return NULL;   }    HDC hDCMemory = NULL;   HGDIOBJ hGDIObj = NULL;   hDCMemory = CreateCompatibleDC(NULL);   hGDIObj = SelectObject(hDCMemory, hBitmap);    HDC hDCSurface = NULL;   if(DD_OK == pIDDS7->GetDC(&hDCSurface))   {      BitBlt(hDCSurface, 0, 0, BitmapInfo.bmWidth,              BitmapInfo.bmHeight, hDCMemory, 0, 0, SRCCOPY);      pIDDS7->ReleaseDC(hDCSurface);   }    SelectObject(hDCMemory, hGDIObj);   DeleteDC(hDCMemory);   DeleteObject(hBitmap);    return pIDDS7;}


And, this is DisplayMode function, setting up resolution etc.:

m_IDD7->SetDisplayMode(640,480,16,0,NULL);


No matter, what I would change in file I want to load, result will be the same. I don't know, what might be a reason. And I tried to load all possible file formats: PNG, TGA, JPG, BMP ... the same result ... "rainbow" screen ;/
Kitt3n
Kitt3n

>Or maybe PCX was not so good choice? I'm waiting for Your opinion :)
If you want to "do it yourself" (tm), I would suggest using
uncompressed 32bit tga - it's really trivial to load that
fileformat (a small header and then a chuck of bgra data)

Regards
visit my website at www.kalmiya.com
Tomalla
Tomalla
@Kitt3n, thanks, I'll try it as well, but if I'll succeed with stb_image, it will be a lot easier for me :)

According to my previous post, I've changed this line:
   BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 0);


... to following:
   BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 2);


and every image is loading now. But, this "2" I changed to, refers to grey and alpha components, so everything is in one shade ( ... no, definitely not gray, but: yellow! Every color is in shade of yellow! ). There's only one step ... bring back colors ... Any idea?

Tomalla
bubu LV
bubu LV
Use 3 or 4 to get 24-bit RGB or 32-bit RGBA pixel format.
And if you are using DirectX you can use D3DX utility functions, such as D3DXCreateTextureFromFile, to load textures from file. No need to use 3rd party libraries.
Tomalla
Tomalla
I know that from comments in stb_image.c file. However, if I typed 0, 1, 3 or 4, the result was ... like in the screenshot few posts ago. It wasn't even similar to the image I wanted to load =?
bubu LV
bubu LV
Have you also modified fourth argument of CreateBitmap function accordingly?
Tomalla
Tomalla
Fourth argument is imageData ... how do I have to change this parameter and last one in stbi_load function? I tried:

BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 3);  hBitmap = CreateBitmap(width, height, 3, 8, imageData);


... and:

BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 4);  hBitmap = CreateBitmap(width, height, 4, 8, imageData);


Result is few green dots in the middle of a screen. I think I have misunderstood something ...
bubu LV
bubu LV
I'm counting from 1, not 0 :) I'm talking about argument with value 8 (and probably also value 2).
If you don't know how CreateBitmap function needs to be used then read the documentation (MSDN). Afaik 8 means 8-bits per pixel. But if you tell stbi to load 24 or 32 bit images...
I have not worked with DirectDraw at all, but cann't you simply use DirectDraw surfaces to fill their contents from stbi_load loaded data (some kind of lock/memcpy/unlock) ? I mean - don't use GDI at all, if you are programming with DirectDraw.
And doesn't DirectDraw have some functions itself for loading images?
Tomalla
Tomalla
OK, here's what I got:

1. This time, I used function DDCopyBitmap from DDUtil.h. Code:

IDirectDrawSurface7* CreateOSSFromImage(IDirectDraw7* pIDD7, char* pszFileName){   if((pIDD7 == NULL) || (pszFileName == NULL))        return NULL;	   HBITMAP hBitmap = NULL;   int width, height, n;	BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 2);   hBitmap = CreateBitmap(width, height, 2, 8, imageData);    if(hBitmap == NULL) return NULL;   BITMAP BitmapInfo = {0};   GetObject(hBitmap, sizeof(BITMAP), &BitmapInfo); 	   DDSURFACEDESC2 ddSD2 = {0};   ddSD2.dwSize = sizeof(DDSURFACEDESC2);   ddSD2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;   ddSD2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;   ddSD2.dwWidth = BitmapInfo.bmWidth;   ddSD2.dwHeight = BitmapInfo.bmHeight;    IDirectDrawSurface7* pIDDS7 = NULL;   pIDD7->CreateSurface(&ddSD2, &pIDDS7, NULL);   if(pIDDS7 == NULL)   {      DeleteObject(hBitmap);      return NULL;   }    DDCopyBitmap(pIDDS7, hBitmap, 0, 0, 0, 0);    DeleteObject(hBitmap);    return pIDDS7;}


Result: every image have colors from white to yellow. There is no other color, like red, blue or green! However, it stays yellow even after changing the last parameter of stbi_load function to 0, 1, 2, 3 and 4. Weird ...

2. I tried with locking and memcpy function:

IDirectDrawSurface7* CreateOSSFromImage(IDirectDraw7* pIDD7, char* pszFileName){   if((pIDD7 == NULL) || (pszFileName == NULL))        return NULL;   int width, height, n;	BYTE* imageData = stbi_load(pszFileName, &width, &height, &n, 2);    DDSURFACEDESC2 ddSD2 = {0};   ddSD2.dwSize = sizeof(DDSURFACEDESC2);   ddSD2.dwFlags = DDSD_CAPS | DDSD_WIDTH | DDSD_HEIGHT;   ddSD2.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;   ddSD2.dwWidth = width;   ddSD2.dwHeight = height;    IDirectDrawSurface7* pIDDS7 = NULL;   pIDD7->CreateSurface(&ddSD2, &pIDDS7, NULL);   if(pIDDS7 == NULL)   {      return NULL;   } 	//Fill whole surface with blue color	//DDBLTFX ddBltFX = {0};	//ddBltFX.dwSize = sizeof(DDBLTFX);	//ddBltFX.dwFillColor = 0x000000FF;	//pIDDS7->Blt(NULL, NULL, NULL,DDBLT_WAIT | DDBLT_COLORFILL, &ddBltFX);	//Lock, memcpy, unlock	ZeroMemory(&ddSD2,sizeof(ddSD2)); 	ddSD2.dwSize = sizeof(ddSD2); 	if(pIDDS7->Lock(NULL,&ddSD2,DDLOCK_WAIT,NULL)!=DD_OK)		return NULL;	memcpy(ddSD2.lpSurface, imageData, sizeof(imageData));	pIDDS7->Unlock(NULL);    return pIDDS7;}


Result: few color pixels in top-right corner of a screen.

Now, I feel like some data is staying in memory after application terminates! Because, when I remove comments from " //Fill whole surface with blue color" section, background is becoming blue, as I wanted it to. But when I comment these lines once again, the background STAYS blue! I have to uncomment these lines and change color, for example to 0x00000000 ( black ) to make black background. What the ... ? What is going on? I feel really confused ... !

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.