Updating managed textures

Started by
5 comments, last by TheAdmiral 17 years ago
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
Advertisement
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. ;)
My spacesim project blog:http://www.simerge.com/
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?
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
My spacesim project blog:http://www.simerge.com/
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 wideARGBPixel* pixel_array = reinterpret_cast<ARGBPixel*> (lockedRect.pBits);// Set the (x, y)th pixel's red component to zeropixel_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]
Ring3 Circus - Diary of a programmer, journal of a hacker.
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.
My spacesim project blog:http://www.simerge.com/
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
Ring3 Circus - Diary of a programmer, journal of a hacker.

This topic is closed to new replies.

Advertisement