How to filter out common color around object within rectangle?

Started by
9 comments, last by Nik02 11 years, 8 months ago
I am currently working on a 2D game where spritesheets are obtained through memory in .pak files. The images are .bmp files and the sprites render correctly, except for the fact the background/unused color/pixels around the sprite appears, as expected; however, I want to be able to remove the background pixels like such:

Rendered sprite without removing surrounding pixels:
17044956.png


This is the output I would like to achieve:
38470221.png

Thanks for any suggestions or help.
Advertisement
It sounds like you should be using the alpha channel instead of a solid background color. This also allows nicely antialiased sprite edges.
It would be good to have alpha based sprites, however I am currently working on an old mmorpg and converting everything to Direct X 9. The game achieves this through their own procedure with DirectDraw7 to render the finalized sprites. I was just wondering if there was any simpler way to do this in Direct X 9 instead of following the same procedure as the old game code. If I can find the code where they do this I will post it, but for now does anyone have any other alternatives other than creating an alpha channel in all the sprites? (because there is about 1000 sprite sheets and I want to refrain from creating alpha channels for them all for obvious reasons).
I was thinking of using texture filtering but I am unsure if this will achieve what I am looking for. Can someone verify?

On a side note: all the sprites have no anti-aliasing with the background color so it can be easily separated from the object within the sprite, but I am unsure of a procedure at the moment.
Legacy code/assets. Sounds fun. ;) I guess you could filter out that specific background color on a per-pixel basis, but... why? My suggestion would be write a quick conversion tool that loops through a directory, loads each file, replaces that color with transparent, then saves the file in a new location.
Use chroma-keying, it's supported by DX 9

******************************************************************************************
Youtube Channel


Legacy code/assets. Sounds fun. ;) I guess you could filter out that specific background color on a per-pixel basis, but... why? My suggestion would be write a quick conversion tool that loops through a directory, loads each file, replaces that color with transparent, then saves the file in a new location.


Its not only one specific color... because a sprite can have any color. So the background color must be always completely different than the objects that a sprite contains in order for the background to be easily filtered out which limits that approach.


I will look into chroma-keying as LancerSolurus suggested.

Use chroma-keying, it's supported by DX 9


This appears to be a very reliable option especially since the background is only one color per sprite. I am doing my research now, but if you have any resources you can link to me, that would speed things up a lot for me. Thanks!

I also think this is performance-friendly since the gpu loads all the sprites before the game starts, I will be able to create an alpha channel for all the pixels processed through chroma-keying. But for now, like I said, I will be doing some research and if you have any links to site(s) that explain the process or any approaches to accomplish this that would be great!
Here is some code that I promised (I am not sure if this will achieve what I want, I tried to show all the highlights from the old source code that I am converting to Direct X 9... hopefully I got the right stuff):

If anything highlights what I am trying to achieve, please let me know as I am unfimiliar with the functions processed with all this code. I am sorry and hate to just pile stuff on everyone but I am sure an experienced coder can just schim through without even reading to recognize when pixels are being removed or replaced that would most likely be removing a background color around an object within a sprite.

This is where all the bitmap image data is read:

IDirectDrawSurface7 * CSprite::_pMakeSpriteSurface()
{
IDirectDrawSurface7 * pdds4;
HDC hDC;
WORD * wp;
m_bOnCriticalSection = TRUE;
if( m_stBrush == NULL ) return NULL;
CMyDib mydib(m_cPakFileName, m_dwBitmapFileStartLoc); // Reads bitmap data/info
m_wBitmapSizeX = mydib.m_wWidthX; // image width
m_wBitmapSizeY = mydib.m_wHeightY; // image height
pdds4 = m_pDDraw->pCreateOffScreenSurface(m_wBitmapSizeX, m_wBitmapSizeY);
if (pdds4 == NULL) return NULL;
pdds4->GetDC(&hDC);
mydib.PaintImage(hDC);
pdds4->ReleaseDC(hDC);
DDSURFACEDESC2 ddsd;
ddsd.dwSize = 124;
if (pdds4->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) return NULL;
pdds4->Unlock(NULL);
wp = (WORD *)ddsd.lpSurface;
m_wColorKey = *wp;
m_bOnCriticalSection = FALSE;
return pdds4;
}


This is where the Off Screen Surface is created:

IDirectDrawSurface7 * DXC_ddraw::pCreateOffScreenSurface(WORD wSzX, WORD wSzY)
{
DDSURFACEDESC2 ddsd;
IDirectDrawSurface7 * pdds4;
ZeroMemory(&ddsd, sizeof(ddsd));
if ((wSzX % 4) != 0) wSzX += 4 - (wSzX % 4);
ddsd.dwSize = sizeof(ddsd);
ddsd.dwFlags = DDSD_CAPS | DDSD_HEIGHT |DDSD_WIDTH;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY;
ddsd.dwWidth = (DWORD)wSzX;
ddsd.dwHeight = (DWORD)wSzY;
if (m_lpDD4->CreateSurface(&ddsd, &pdds4, NULL) != DD_OK) return NULL;
return pdds4;
}


Before the sprite(surface) is rendered, this is called:

bool CSprite::_iOpenSprite()
{
if (m_lpSurface != NULL) return FALSE;
m_lpSurface = _pMakeSpriteSurface(); // image data read and surface created
if (m_lpSurface == NULL) return FALSE;
m_pDDraw->iSetColorKey(m_lpSurface, m_wColorKey);
m_bIsSurfaceEmpty = FALSE;
DDSURFACEDESC2 ddsd;
ddsd.dwSize = 124;
if (m_lpSurface->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL) != DD_OK) return FALSE;
m_pSurfaceAddr = (WORD *)ddsd.lpSurface;
m_sPitch = (short)ddsd.lPitch >> 1;
m_lpSurface->Unlock(NULL);
return TRUE;
}

HRESULT DXC_ddraw::iSetColorKey(IDirectDrawSurface7 * pdds4, WORD wColorKey)
{
DDCOLORKEY ddck;
ddck.dwColorSpaceLowValue = _dwColorMatch(pdds4, wColorKey);
ddck.dwColorSpaceHighValue = ddck.dwColorSpaceLowValue;
return pdds4->SetColorKey(DDCKEY_SRCBLT, &ddck);
}

DWORD DXC_ddraw::_dwColorMatch(IDirectDrawSurface7 * pdds4, WORD wColorKey)
{
DWORD dw = CLR_INVALID, * dwp;
DDSURFACEDESC2 ddsd2;
HRESULT hres;

ddsd2.dwSize = sizeof(ddsd2);
while ((hres = pdds4->Lock(NULL, &ddsd2, 0, NULL)) == DDERR_WASSTILLDRAWING);
if (hres == DD_OK)
{
dwp = (DWORD *)ddsd2.lpSurface;
*dwp = (DWORD)wColorKey;
dw = *(DWORD *)ddsd2.lpSurface;
dw &= (1 << ddsd2.ddpfPixelFormat.dwRGBBitCount)-1;
pdds4->Unlock(NULL);
}
return dw;
}


This renders the sprite in the end:

m_pDDraw->m_lpBackB4->BltFast( dX, dY, m_lpSurface, &rcRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT );




Thanks for your patience and support.
I believe the solution I need to achieve this is through color keying hense all the variations of (colorkey) variable names in the code I just posted, lol. Heres is a similar thread I found here on these forums; however, it is based on OpenGL: http://www.gamedev.net/topic/419337-opengl-and-sprites/

Any suggestions or guidance is appreciated as I continue to research color keying.

Thanks a lot for all your help.

This topic is closed to new replies.

Advertisement