Jump to content
  • Advertisement
Sign in to follow this  
LevyDee

Locking and writing to certain channels of surface data

This topic is 2126 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I am looking for a way to manually adjust the alpha channel of an A8R8G8B8 formatted texture. I create the texture as managed in order to lock the surface and get the pBits describing the surface data. So how would you loop through the entire surface and only change the alpha channel of each pixel?

 

I know you can do something like this

 
BYTE* bytePointer = (BYTE*)surfaceData.pBits;
 
for(int i = 0; i < surfaceData.pitch * textureHeight; i++)
{
    bytePointer[i] = //some value
}

This will loop through every bit, but how do I figure which channel of the pixel I am on so I can update only the alpha channel of an A8R8G8B8 texture?

 

Thank you.

Share this post


Link to post
Share on other sites
Advertisement

An A8R8G8B8 texture is actually ordered as BGRA, so the alpha channel is going to be the third component.  You'd do it like this:

void UpdateAlpha (IDirect3DTexture9 *texture, int newAlpha)
{
	D3DLOCKED_RECT lockrect;
	D3DSURFACE_DESC desc;

	// so we can be certain that we're using the correct width and height
	if (SUCCEEDED (texture->GetLevelDesc (0, &desc)))
	{
		assert (desc.Format == D3DFMT_A8R8G8B8);

		if (SUCCEEDED (texture->LockRect (0, &lockrect, NULL, 0)))
		{
			unsigned *data = (unsigned *) lockrect.pBits;

			for (int y = 0; y < desc.Height; y++)
			{
				for (int x = 0; x < desc.Width; x++)
				{
					((byte *) &data[x])[3] = newAlpha;
				}

				// 32bpp == 4 bytes and pitch may not be == width * 4
				data += lockrect.Pitch >> 2;
			}

			texture->UnlockRect (0);
		}
	}
}

Share this post


Link to post
Share on other sites

Thank you for the response. This seems to change the correct value, but the change is not reflecting in my rendering. Is their anything that would prevent my change from taking effect?

 

The purpose of this is I am building an editor for my engine. I want to have multiple layers for terrain painting. So you have the base layer, and then you can have layers on top of that. Each extra layer can be "painted" by lowering the alpha channel of which ever layer you like. So what I m trying to do is manually edit the alpha channel only at certain indices of the surface data(due to mouse dragging). I have manually set up a test case where I just lower the alpha to 50 percent ala 255 / 2 but it has zero effect. If I set the alpha channel to 0.5f in my shader before the alpha blending occurs, it works as expected. Will locking the surface of the texture and setting the alpha channel there not effect my alpha channel I receive in my shader? that seems to be the case right now.

 

Using your example this is what my test function looks like. It is simply supposed to adjust every texels alpha channel to 0.5f in my shader.

 

Shader(tested and verified to work)

//Alpha blend
float4 blendResult;

blendResult.a = layerTwo.a + (1.0f - layerTwo.a) * layerOne.a;
blendResult.rgb = (1.0f / blendResult.a) * (layerTwo.a * layerTwo.rgb + (1.0f - layerTwo.a) * layerOne.a * layerOne.rgb);    
    
color = blendResult;

 

Alpha function

IDirect3DSurface9* surf;
            _layers[1].texture->GetSurfaceLevel(0, &surf);

            //Get surface description
            D3DSURFACE_DESC desc;
            surf->GetDesc(&desc);

            //Lock surface data
            D3DLOCKED_RECT surfaceData;
            surf->LockRect(&surfaceData, 0, D3DLOCK_READONLY);    

            //Make pointer to directly edit surface data
            BYTE* bytePointer = (BYTE*)surfaceData.pBits;

            for (int y = 0; y < desc.Height; y++)
            {
                for (int x = 0; x < desc.Width; x++)
                {
                    //Alpha channel
                    ((byte *) &bytePointer[x])[3] = 255 / 2;
                }

                // 32bpp == 4 bytes and pitch may not be == width * 4
                bytePointer += surfaceData.Pitch >> 2;
            }

            //Unlock
            surf->UnlockRect();
Edited by Slig Commando

Share this post


Link to post
Share on other sites

Your byte pointer is still wrong above; it should be an unsigned int.  You can certainly use bytes but then you need to fix up the array indexing and increment-by-pitch part to 4* what it currently is; I just find that using unsigned ints is clearer and easier here.

 

You're also locking with read-only which is definitely not what you want to do if you're modifying the texture (you've just told D3D that you're not going to write to it, so D3D is free to not update the texture when you unlock); generally for updating a managed texture you'd use lock flags of either 0 or D3DLOCK_NO_DIRTY_UPDATE - the latter is useful if you're doing lots of small locks before you need to use the texture; you can then take all of the updates via a single AddDirtyRect call, which can perform better.

 

It's unusual to see LockRect on a surface when you can do it on the texture itself, but it still works.  Don't forget to Release the surface after the unlock though, otherwise you'll leak the resource.

Share this post


Link to post
Share on other sites

Ah, roger that. Thats what I get for copying my lock from a different function I wrote(meant to read, not write...) Thank you for the help. That seemed to do the trick.

Share this post


Link to post
Share on other sites

The texture interface's LockRect method is a shortcut which internally works just like the above code (and takes the surface level as a parameter). You'd only save a few lines of code by using that, but the functionality is exactly the same as you have now :)

 

Mhagain: your code is unsafe in that you assume the pitch is a multiple of four; in practice, it always is, but there is no explicit guarantee :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

GameDev.net is your game development community. Create an account for your GameDev Portfolio and participate in the largest developer community in the games industry.

Sign me up!