Archived

This topic is now archived and is closed to further replies.

ms291052

D3DXLoadSurfaceFromSurface

Recommended Posts

I am currently rewriting my slow old 2D engine to be a little more efficient. In the old version it copied a bitmap pixel by pixel to the desired surface frame by frame, which was, of course, extraordinarily slow. Now I copy it once, to a stored surface which I then D3DXLoadSurfaceFromSurface to the desired surface. The only problem with this is that with my old version if the current pixel (the one it''s about to copy) matched the ColorKey, it was never copied and with D3DXLoadSurfaceFromSurface it copies black instead, forcing a black rectangle around all my 2D bitmaps I''m trying to display. Is there a way, to simply make D3DXLoadSurfaceFromSurface not touch instead of setting all the ColorKey-colored pixels to black?

Share this post


Link to post
Share on other sites
hmmm.. It appears as though D3DXLoadSurfaceFromSurface is doing its job after all. It''s setting the appropriate pixels to ARGB(0,0,0,0) but my program''s still rendering them and I''m not quite sure why...

Share this post


Link to post
Share on other sites
You should set the alpha blending related renderstates for the transparency to work.
Use the search function, this has been discussed many, many times here...

-Nik

Share this post


Link to post
Share on other sites

g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

I have ALPHABLENDENABLE as well as SRC and DEST BLENDs. Did I leave out any other important ones?

Share this post


Link to post
Share on other sites
Those seem OK. What about texture stage states? In particular, alpha source state?

-Nik

EDIT:
Use D3DBLEND_INVSRCALPHA for dest factor, see if that has any effect (i doubt it).

[edited by - Nik02 on October 12, 2003 5:08:17 AM]

Share this post


Link to post
Share on other sites

g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );

EDIT:
D3DBLEND_INVSRCALPHA had no effect either

[edited by - ms291052 on October 12, 2003 5:19:00 AM]

Share this post


Link to post
Share on other sites
The BMP doesn''t but the pixels do when they get to the surface... Assuming all unshown functions work (they do) here''s my code:

void CBitmap::DrawBitmap(DWORD* pDestData, int DestPitch, LPDIRECT3DSURFACE9 pDestSurface)
{
if(!RenderedOnce)
{
D3DLOCKED_RECT LockedRect;
pDestSurface->LockRect(&LockedRect, NULL, 0);
pDestSurface->UnlockRect();
pDestData = (DWORD*)LockedRect.pBits;
DestPitch = LockedRect.Pitch;

RenderedOnce = true;
LoadBitmapToSurface(strPathName, &pBitmapSurface, g_pd3dDevice);
D3DSURFACE_DESC d3dsd;
pBitmapSurface->GetDesc(&d3dsd);
width = d3dsd.Width;
height = d3dsd.Height;
HRESULT r = 0;
int OffsetX = 0, OffsetY = 0;
POINT BmpDestPoint = {0,0};
RECT BmpRect = {0,0,0,0};
OffsetX = rect.left;
OffsetY = rect.top;
SetRect(&BmpRect, OffsetX, OffsetY, rect.right, rect.bottom);
BmpDestPoint.x = x;
BmpDestPoint.y = y;
D3DLOCKED_RECT LockedBitmap;
r = pBitmapSurface->LockRect(&LockedBitmap, 0, D3DLOCK_READONLY);
if(FAILED(r))
return;
DWORD* pBMPData = (DWORD*)LockedBitmap.pBits;
LockedBitmap.Pitch /= 4;
DestPitch /= 4;
int BMPOffset = OffsetY * LockedBitmap.Pitch + OffsetX;
int DestOffset = y * DestPitch + x;
for(int cy = 0; cy < (rect.bottom - rect.top); cy++)
{
for(int cx = 0; cx < (rect.right - rect.left); cx++)
{
if(bTransparent)
{
if(pBMPData[BMPOffset] != ColorKey)
pDestData[DestOffset] = pBMPData[BMPOffset];
else
pBMPData[BMPOffset] = D3DCOLOR_ARGB(0, 255, 0, 255);
}
else
{
pDestData[DestOffset] = pBMPData[BMPOffset];
}
BMPOffset++;
DestOffset++;
}
DestOffset += DestPitch - (rect.right - rect.left);
BMPOffset += LockedBitmap.Pitch - (rect.right - rect.left);
}
pBitmapSurface->UnlockRect();
cout << "Copying..." << endl;
}
RECT rect3 = {x, y, x + width, y + height};
D3DXLoadSurfaceFromSurface(pDestSurface, NULL,&rect3,pBitmapSurface,NULL,NULL,D3DX_DEFAULT,D3DCOLOR_ARGB(0, 255, 0, 255));
}

and the ColorKey is (255, 0, 255).
And for what it''s worth:

class CBitmap
{
public:
char* strPathName;
int x, y, height, width, xVel, yVel;
BOOL bTransparent;
BOOL RenderedOnce;
BOOL draw;
D3DCOLOR ColorKey;
RECT rect;
LPDIRECT3DSURFACE9 pBitmapSurface;
CBitmap();
~CBitmap();
void DrawBitmap(DWORD* pDestData, int DestPitch, LPDIRECT3DSURFACE9);
void Update();
void GetBounds(RECT* prect);
BOOL Intersects(CBitmap* cbmp);
};

Share this post


Link to post
Share on other sites
Can you spot a bug?


if(bTransparent)
{
if(pBMPData[BMPOffset] != ColorKey)
pDestData[DestOffset] = pBMPData[BMPOffset];
else
pBMPData[BMPOffset] = D3DCOLOR_ARGB(0, 255, 0, 255);
}
else
{
pDestData[DestOffset] = pBMPData[BMPOffset];
}


-Nik

[edited by - Nik02 on October 12, 2003 5:40:51 AM]

Share this post


Link to post
Share on other sites
err...
test pixel against the color key... if it''s not the same, then copy it, otherwise set it to (0, 255, 0, 255)

unless I''m missing something, that code''s clean (although I''m known for missing the obvious)

Share this post


Link to post
Share on other sites
You seem to set the source pixel to transparent, instead of destination pixel:


pBMPData[BMPOffset] = D3DCOLOR_ARGB(0, 255, 0, 255);

//should probably be:

pDestData[DestOffset] = D3DCOLOR_ARGB(0, 255, 0, 255);


You missed the obvious

-Nik

Share this post


Link to post
Share on other sites
pDestData[DestOffset] = D3DCOLOR_ARGB(0, 255, 0, 255);
definately changed something but it's not perfect yet

we went from the left to the right here. The right side is the original.


EDIT:
if I change the ColorKey paramater of D3DXLoadSurfaceFromSurface(...) to D3DCOLOR_ARGB(0, 255, 0, 255) instead of D3DCOLOR_ARGB(255, 255, 0, 255), we go back to the left side.

[edited by - ms291052 on October 12, 2003 6:03:42 AM]

Share this post


Link to post
Share on other sites
Do you clear to black? If so, then the code works!


-Nik

EDIT:
change this:

D3DCOLOR_ARGB(0, 255, 0, 255);


to this:

D3DCOLOR_ARGB(255, 0, 255, 0);


[edited by - Nik02 on October 12, 2003 6:04:16 AM]

Share this post


Link to post
Share on other sites
I''m clearing to black but I have other things behind the bitmap (that grey stuff behind the bitmap is part of something larger).

Share this post


Link to post
Share on other sites
eh, if my pDestData[DestOffset] and my ColorKey (passed to D3DXCreateSurfaceFromSurface) are the same, I get the *non-* transparent black background, otherwise it shows the original (pink) background.

Edit:
D3DCOLOR_ARGB(255, 0, 255, 0) -> Black Background.

[edited by - ms291052 on October 12, 2003 6:09:30 AM]

Share this post


Link to post
Share on other sites
In case of colorkey pixel, try setting the destination pixel to, pure and simple, 0. That means completely transparent black.

-Nik

EDIT:
And therefore would act as transparent when rendered, assuming the blending states are on.

[edited by - Nik02 on October 12, 2003 6:11:25 AM]

Share this post


Link to post
Share on other sites
Draw the quad last, after any other geometry. It could be that z-buffering is playing tricks here...

-Nik

[edited by - Nik02 on October 12, 2003 6:14:55 AM]

Share this post


Link to post
Share on other sites
It is drawn dead last. Should I try disabling Z-buffering? Should I try it with W-buffering or what?

g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, D3DTOP_SELECTARG2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, D3DTOP_SELECTARG2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_SRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_INVSRCALPHA);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, TRUE);

g_pBackSurf = 0;
g_pd3dDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &g_pBackSurf);
Bitmap.DrawBitmap(0, 0, g_pBackSurf);
g_pBackSurf->Release();
g_pBackSurf=0;

g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLOROP, 4 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, 2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP, 2 );
g_pd3dDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, 2 );
g_pd3dDevice->SetRenderState(D3DRS_SRCBLEND, D3DBLEND_ZERO);
g_pd3dDevice->SetRenderState(D3DRS_DESTBLEND, D3DBLEND_ONE);
g_pd3dDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);

EDIT:
No good with Z-Buffing off either.

[edited by - ms291052 on October 12, 2003 6:17:13 AM]

Share this post


Link to post
Share on other sites
I spotted the answer!

Don't modify the destination pixel at all in case of src colorkey pixel.

All this time i was thinking about alphablending, but it doesn't have anything to do with manual colorkeying.

-Nik

EDIT:
For real alphablending, one must render some geometry with a texture blessed with alpha (or material with alpha).
It seems I missed the obvious!

-Nik

[edited by - Nik02 on October 12, 2003 6:24:03 AM]

Share this post


Link to post
Share on other sites
Well i don''t know if it means anything but if I set RenderedOnce to false (again) at the end, and take out the CopySurface line, it works just fine. However, copying pixel by pixel every frame is terribly slow.

Share this post


Link to post
Share on other sites