Archived

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

ms291052

D3DXLoadSurfaceFromSurface

Recommended Posts

ms291052    223
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
ms291052    223
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
Nik02    4348
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
ms291052    223

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
Nik02    4348
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
ms291052    223

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
ms291052    223
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
Nik02    4348
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
ms291052    223
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
Nik02    4348
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
ms291052    223
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
Nik02    4348
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
ms291052    223
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
Nik02    4348
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
ms291052    223
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
Nik02    4348
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
ms291052    223
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