Sign in to follow this  
Phrawth

Updating managed textures

Recommended Posts

I'm trying to create a texture to put several sprites on. The sprites need to be written from individual files to the texture at initialization. I assume it should look something like: LPDIRECT3DTEXTURE9 pTempTexture; g_pd3dDevice->CreateTexture(256, 256, 1, 0, FORMAT, D3DPOOL_MANAGED, &pTempTexture, NULL); D3DLOCKED_RECT lockedRect; (Update the texture with the images from the file here) pTempTexture->LockRect(0,&lockedRect,0,0); My question is, what do I use to update the texture? It seems like all of the functions are for default pool textures. Thanks

Share this post


Link to post
Share on other sites
You can use these function also for managed textures.

If you call "LockRect" the pointer to the texture memory will be passed over the "lockedRect" variable.
Then you can update the texture as you like.
After that you should call "UnlockRect" or a function sounds like that.

Now, you have an updated texture. ;)

Share this post


Link to post
Share on other sites
I made a little error on the code there. I meant to put:

pTempTexture->LockRect(0,&lockedRect,0,0);
(update texture here)
pTempTexture->UnlockRect(0);

I'm still not quite sure how to update the managed texture. I get a pointer to the bits, but then what? Can I cast the pointer as a surface pointer and use updatesurface or what?

It seems like this would be a pretty common trick. Could someone point me in the direction of a little code, or show me how it's done?

Share this post


Link to post
Share on other sites
You can update a pixel of the texture as follows:

#define ARGB(a, r, g, b) ((a) << 24 | (r) << 16 | (g) << 8 | (b))

I'm not sure if this macro is right. If the colors are a little bit wrong. You can exchange "r" and "b" at the right side.

// Initialization
INT * buffer = (LONG*)lockedRect.pBits;
INT pitch = lockedRect.Pitch;

[...]

// Writing to a pixel with (x, y)

*(buffer + y * pitch + x) = ARGB( [alpha value], [red], [green], [blue] );
// all values must be in range of 0 to 255. Choose alpha = 255 for no transparency

Share this post


Link to post
Share on other sites
Edit2: I was using the D3DLOCKED_RECT.Pitch member incorrectly, but I think your pixel pointer dereference is wrong, razorjack.

The value that LockRect gives you is a structure including a pointer to bitmap data. You use this pointer as an array of bytes/words/dwords/floats depending on the surface format.

For example, if the texture was created with
D3DXCreateTextureFromFileEx(pDevice, pSrcFile, Width, Height, MipLevels, Usage, D3DFMT_A8R8G8B8, Pool, 
Filter, MipFilter, ColorKey, pSrcInfo, pPalette, &pTexture);
then you could set the value of the pixel with coordinates (x, y) using:
struct ARGBPixel {
unsigned char a;
unsigned char r;
unsigned char g;
unsigned char b;
};

...

ASSERT(lockedRect.Pitch / Width == sizeof(ARGBPixel)); // A8R8G8B8 better be four bytes wide
ARGBPixel* pixel_array = reinterpret_cast<ARGBPixel*> (lockedRect.pBits);

// Set the (x, y)th pixel's red component to zero
pixel_array[y * Width + x].r = 0;
// (See below)
and so on. Don't forget to unlock the texture when you're done.

Admiral

[Edited by - TheAdmiral on April 7, 2007 7:02:28 AM]

Share this post


Link to post
Share on other sites
Oups.
I meant *(INT *)((char *)buffer + y * pitch + x) = [any color]. Otherwise the offset would be multiplied with 4 and thats wrong.

I've been told that the pitch member is necessary because the row could have more bytes than "width * [size of color datatype]" so I haven't ever tried to use "width" instead.

Maybe I'm wrong or it was only the case of DX7 and down. Please correct me if it's so.

Share this post


Link to post
Share on other sites
Quote:
Original post by razorjack
Oups.
I meant *(INT *)((char *)buffer + y * pitch + x) = [any color]. Otherwise the offset would be multiplied with 4 and thats wrong.

I've been told that the pitch member is necessary because the row could have more bytes than "width * [size of color datatype]" so I haven't ever tried to use "width" instead.

Maybe I'm wrong or it was only the case of DX7 and down. Please correct me if it's so.

It looks like you're right about the necessity of pitch:
Quote:
MSDN, Width vs. Pitch
When you lock a surface using the IDirect3DSurface9::LockRect method, the method fills in a D3DLOCKED_RECT structure that contains the pitch of the surface and a pointer to the locked bits. The value in the Pitch member describes the surface's memory pitch, also called stride. Pitch is the distance, in bytes, between two memory addresses that represent the beginning of one bitmap line and the beginning of the next bitmap line. Because pitch is measured in bytes rather than pixels, a 640x480x8 surface has a very different pitch value than a surface with the same dimensions but a different pixel format. Additionally, the pitch value sometimes reflects bytes that Direct3D has reserved as a cache, so it is not safe to assume that pitch is just the width multiplied by the number of bytes per pixel.


However, I'm still suspicious of your array indexing:

((char *)buffer + y * pitch + x)

looks like it would correctly determine the offset of the 'bitmap line', but then move along by x bytes, rather than x pixels. I'd be happier with:

int pixel_width = pitch / surface_width;
*(reinterpret_cast<SPixelFormat> (reinterpret_cast<char*> (buffer) + (y * pitch) + (x * pixel_width))) = [any colour];

Admiral

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