Sign in to follow this  

DX9, writing to a texture

This topic is 3412 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

once I create a IDirect3DTexture9 object with IDirect3DDevice9::CreateTexture, how do I read/write into it? I cant find any method like getTexel() or putTexel(), is there any other way, except rendering to texture?

Share this post


Link to post
Share on other sites
Use GetSurfaceLevel() to grab an IDirect3DSurface9 interface then call LockRect() on it. You can only grab the raw bits and there are no helper functions like "SetPixel" or "GetPixel" and you need to do appropriate formatting to match the pixel description.

hth
Jack

Share this post


Link to post
Share on other sites
If your texture is not in the default pool (Which it probably shouldn't be unless it's dynamic (Created with D3DUSAGE_DYNAMIC) in which case it has to be in the default pool), you can Lock() it with LockRect(). That gives you a pointer to the texel data that you can then read to / write from.
If it is in the default pool and it's not dynamic, and you have a good reason for doing that, then you'll have to use UpdateTexture instead.

When you lock a texture, you're given a void* which is a pointer to the start of the top left texel in your requested rect (Often you'll lock the entire texture in one go). The format of that void* depends on the format you created the texture with. If it's a D3DFMT_A8R8G8B8 texture, then you can cast the void* to a DWORD* instead, where the top 8 bits are alpha, the next 8 are red, the next 8 are green, and the low 8 are blue.

Make sure you use the pitch when accessing texels on all but the first row, since drivers are free to stuff extra information at the end of a scanline. The pitch is the length in bytes of one scanline.

Share this post


Link to post
Share on other sites
Hi,

You first need to get access to one of the mip map levels, using IDirect3DTexture9 ::GetSurfaceLevel. On the IDirect3DSurface9 object that you receive you can then call LockRect to lock a piece (or all) of the surface. Locking will provide you with a memory pointer through which you have access to the pixel data of the surface. To calculate the address offset of a pixel you need to consider two things: a) the size of each pixel in bytes (e.g. 4 for 32bit textures) b) the size of each line in the texture in bytes. The latter is called the "pitch" or "stride" and is not necessarily equal to width_in_pixel x bytes_per_pixel due to alignment and what not.

To process every pixel in a texture surface, you would maybe go like this:

void DoSomethingWithATexture(IDirect3DTexture9 * texture){

IDirect3DSurface9 * surface = 0;
// get surface of first mip level
texture->GetSurfaceLevel(0, &surface);

// get description of the surface (width, height etc)
D3DSURFACE_DESC desc;
texture->GetLevelDesc(0, &desc);

LOCKED_RECT locked;
// lock whole surface for read-only access
surface->LockRect(&locked, 0, D3DLOCK_READONLY);

unsigned char* rowData = reinterpret_cast<unsigned char*>(locked.pBits);

for(int row = 0; row < desc.Height; ++row){
unsigned char * pixelPtr = rowData;
for(int col = 0; col < desc.Width; ++col){
// pixelPtr points to the first byte of the pixel,
// whatever you need

// example: 32 bit pixel:
D3DCOLOR pixel = *reinterpret_cast<D3DCOLOR*>(pixelPtr);

// when done, move to next pixel in row
pixelPtr += PixelSizeInBytes(dec.Format);
}

// move to next row:
rowData += locked.Pitch;
}

// important, clean up!
surface->UnlockRect();
surface->Release();
}



(The code above is completely written out of my head - and furthermore it's been a while since I used D3D in C++, I'm a C# guy. Furthermore I ommitted error handling completely)


So, the address of the first byte of a pixel at (x, y) is:
addr = lockedRect.pBits + y*lockedRect.Pitch + x*PixelSizeInBytes(desc.Format)

There are some important points to note: not every texture can be locked (depending on D3DPOOL and D3DUSAGE), locking is expensive (data might need to be moved from video ram to system ram), working with compressed data is likely more difficult (never done this, though).

Regards,
Andre

Share this post


Link to post
Share on other sites
I'm surprised that twice people have said you need to get the surface level before you can lock a region of a texture. The texture has a LockRect method on it that you can use to lock a rectangle on a particular level directly. For more about dealing with surfaces, formats and pixel data, consult Chapter 4. 2D Applications from my book "The Direct3D Graphics Pipeline", which you can read for free. You may also want to look at Chapter 11. Basic Texturing.

Share this post


Link to post
Share on other sites

This topic is 3412 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.

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