Sign in to follow this  
kamal7

How to filter out common color around object within rectangle?

Recommended Posts

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:
[img]http://img594.imageshack.us/img594/1343/17044956.png[/img]


This is the output I would like to achieve:
[img]http://img801.imageshack.us/img801/8518/38470221.png[/img]

Thanks for any suggestions or help. Edited by kamal7

Share this post


Link to post
Share on other sites
It sounds like you should be using the alpha channel instead of a solid background color. This also allows nicely antialiased sprite edges.

Share this post


Link to post
Share on other sites
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).

Share this post


Link to post
Share on other sites
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. Edited by kamal7

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
[quote name='jefferytitan' timestamp='1343701141' post='4964677']
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.
[/quote]

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. Edited by kamal7

Share this post


Link to post
Share on other sites
[quote name='LancerSolurus' timestamp='1343702489' post='4964682']
Use chroma-keying, it's supported by DX 9
[/quote]

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! Edited by kamal7

Share this post


Link to post
Share on other sites
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:
[CODE]
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;
}
[/CODE]

This is where the Off Screen Surface is created:
[CODE]
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;
}
[/CODE]

Before the sprite(surface) is rendered, this is called:
[CODE]
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;
}
[/CODE]

This renders the sprite in the end:
[CODE]
m_pDDraw->m_lpBackB4->BltFast( dX, dY, m_lpSurface, &rcRect, DDBLTFAST_SRCCOLORKEY | DDBLTFAST_WAIT );
[/CODE]



Thanks for your patience and support. Edited by kamal7

Share this post


Link to post
Share on other sites
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: [url="http://www.gamedev.net/topic/419337-opengl-and-sprites/"]http://www.gamedev.net/topic/419337-opengl-and-sprites/[/url]

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

Thanks a lot for all your help.

Share this post


Link to post
Share on other sites
D3D does not support color keying like DirectDraw does.

When using D3D, D3DXCreateTextureFromFileEx function lets you specify a color key that you want to define as transparent. Internally, said function allocates an alpha channel and sets alpha to zero on all texels which match the supplied key value. This effectively makes them transparent if you use alpha blending or alpha testing to render the texture.

This functionality is very easy to replicate in your own code, should you need to do so. Just loop thru the texels, compare each texel against the key and write alpha = 0 to the texel if match is found.

EDIT: The keying logic presented by MENTAL in that linked thread is extremely similar if implemented in D3D. Edited by Nik02

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this