Copying TextureBuffer to UCHAR *

Started by
12 comments, last by webmunkey 22 years, 5 months ago
Yeah, I know this probably a dumb question, but I''m going to ask it. How can I read the pixel values of IDirect3DTexture8 struct and copy them to a unsigned char *? Thanks, -Jesse
Advertisement
IDirect3DTexture8::LockRect

you get back a structure with a void pointer to the data and the pitch of the surface (distance in bytes between consecutive horizontal lines). cast the pointer to UCHAR and copy line by line.
So just off the top of my head, I'd do something along the lines of:
UCHAR *surface;
D3DLOCKED_RECT gStruct;
TextureBuffer->LockRect(0, &gStruct, NULL, NULL);
memcpy(surface, (UCHAR *)gStruct.pBits, sizeof(gStruct));
TextureBuffer->UnlockRect(NULL);

Hmm, would that work? Something looks fishy...
Thanks,
-Jesse

Edited by - webmunkey on November 9, 2001 11:24:44 PM
Not exactly. You have to use one memcpy per row, because you are not guaranteed that rows are contiguous -- thats why you get the pitch (pitch is sometimes NOT equal to width). I assume you already know the surface width, hieght, and depth.

    UCHAR *b = new UCHAR [surfaceWidth*surfaceHieght*bytesPerPixel];D3DLOCKED_RECT r;surface->LockRect(r, NULL,D3DLOCK_READONLY); //should check error codefor (int y=0; y < surfaceHieght; y++)   memcpy ((void*)b,(r.pBits+r.Pitch*y),r.Pitch); //if you use memcpy it wants void *surface->UnlockLockRect();    



Edited by - invective on November 9, 2001 12:15:16 AM
Oh, okay, I see now. Thanks,
-Jesse
How many programmers does it take to change a light bulb?
None. It''s a hardware problem.
Ahh, wait, isn''t Pitch an int? So, wouldn''t I get an error if I tried to add the two? I could convert pBits to an int and the then cast the entire statement to const void *, but I might loose information. What do you think?
Thanks,
-Jesse
You can always add an integer to any pointer type except pointer-to-void. Adding 1 to a pointer advances the pointer to the ''next item'' (for a byte-pointer this would mean an advancement of 1 byte; for a 32-bit-int-pointer it would mean the pointer is advanced 4 bytes; etc.).
no, when you add to a void pointer it always adds one byte per number -- if you cast to int* then you have to divide by sizeof (int) because of the way pointer arithmatic works -- it always advances by sizeof(pointertype) bytes, or 4 for integers on win32. Pitch is specified in bytes. Its correct as written, but cast everything to char, then add, then cast it back to void if that makes it easier for you to understand.

char * pbits = (char *) r.pBits;

memcpy ((void*)b,(void*)(pbits+r.Pitch*y),r.Pitch)

pointer math example:

int *p=something;
*(p+4)=1; //same as p[4]=1

that means that the pointer is advanced by 16 bytes and then dereferenced, because each int is 4 bytes wide.

void *p=something;
p+=4; //advances p by only 4 bytes because void is always incremented one byte at a time
Hmm, it''s not working in the game... The debuger fails when I try to exit and it is obvious the heightmap isn''t correct.
  uchar *height_map_ptr = NULL;	// load in height maphRet = D3DXCreateTextureFromFile(pID3DDevice, "heightd2.bmp", &HeightMap);if (hRet != D3D_OK)   InitFail(hWnd, hRet, "Error loading bitmap!");height_map_ptr = new UCHAR[HFIELD_WIDTH * HFIELD_HEIGHT * 24];	D3DLOCKED_RECT gSurface;HeightMap->LockRect(0, &gSurface, NULL, D3DLOCK_READONLY);char *pBits = (char *)gSurface.pBits;	for (int i = 0; i < HFIELD_HEIGHT; i++)    memcpy((void *)height_map_ptr, (void *)(pBits + gSurface.Pitch * i), gSurface.Pitch);HeightMap->UnlockRect(NULL);  

It compliles without error; however, inside the game the heightmap is flawed. I think that this because the heightmap is being filled with very high arbitrary number which means that something is going wrong inside of the load heightmap function. Sorry to be such a newbie, but thanks for your help so far,
-Jesse
oops, forgot to mention you need to adjust your destination pointer too, otherwise you are copying everything over line one!
note you adjust by width of the image, not pitch of the surface.

memcpy((void *)(height_map_ptr+width*i), (void *)(pBits + gSurface.Pitch * i), gSurface.Pitch);

also, this is very large:

height_map_ptr = new UCHAR[HFIELD_WIDTH * HFIELD_HEIGHT * 24];

if you want a 24 bit image, it is 24 bits * 1/8 bytes per bit, or 3 bytes per pixel, not 24.

height_map_ptr = new UCHAR[HFIELD_WIDTH * HFIELD_HEIGHT * 3];

finally, if you have photoshop, consider converting your image to grayscale and saving as .raw. this gives you 1 byte per pixel (which is usually enough), and its just a byte dump, so you can read it like:

BYTE * pbHieghtField = new BYTE [ width * hieght ];

std::ifstream file;
file.open (filename, std::ios::binary );
file.read ( (char *)pbHieghtField, width * hieght );
file.close();

This topic is closed to new replies.

Advertisement