#### Archived

This topic is now archived and is closed to further replies.

# How to copy raw data to texture ????

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

## Recommended Posts

Hi I have a little problem trying to copy my raw data to a texture. My problem is that no matter what I do I can''t seem to get the right data over to the texture. Has anyone read the raw lightmap data from q3bsp file and can give me a hint or someone just tell me how to copy the raw data in format [128][128][3] to a texture? Maybe I should first create a surface and copy it to a texture? Any input would help /Joachim HRESULT WorldBSP::CreateLightmaps() { int i = 0, x = 0; myLightmaps = new LPDIRECT3DTEXTURE8[myBSPreader->myNumLightMaps]; ZeroMemory(myTextures, sizeof(myTextures)); //Create texture for(i=0;imyNumLightMaps;i++) { if( FAILED( D3DXCreateTexture(D3DInit::ourD3DDevice, 128, 128, 3, NULL, D3DFMT_R8G8B8, D3DPOOL_MANAGED, &myLightmaps) ) ) { assert(myLightmaps[i] != NULL); } } D3DLOCKED_RECT lrect; myLightmaps[i]->LockRect(0, &lrect, 0, 0); unsigned char* pDst = (unsigned char*)lrect.pBits; size_t size = sizeof(lrect.pBits); for (i=0;i<128;i++) { for(x=0;x<128;x++) { //*pDst = 0; //pDst++; //Just picking the first for test *pDst = myBSPreader->myLightMaps[0].map[i][x][0]; pDst++; *pDst = myBSPreader->myLightMaps[0].map[i][x][1]; pDst++; *pDst = myBSPreader->myLightMaps[0].map[i][x][2]; pDst++; } pDst += lrect.Pitch; } myLightmaps[0]->UnlockRect(0); return S_OK; }

##### Share on other sites
You''re using pitch wrong. Pitch is the distance between two rows in memory, not the distance between end of one row and beginning of the next.

And sizeof(pBits) will always give you 4, the size of a pointer. Use GetDesc/GetLevelDesc to retrieve information like height.

##### Share on other sites
First, aren''t you getting a compiler error in the D3DXCreateTextur function call? myLightmaps should be myLightmaps. Anyway, this is not the problem. I can see two problems here. First, you are referencing myLightmaps[i] outside the for loop. Second, you''re filling the data of only the first level of the texture. If your geometry is to use the second or third level, it''ll use invalid data.

##### Share on other sites
Yup, I've read the raw data from a Q3 BSP file and can give you the exact code to convert the data. I had a problem though. My graphics card only supports R5G6B5 display modes, so I had to convert the 24 bit color values to 16 bit values.

First off create an empty texture:

if(FAILED(D3DXCreateTexture(m_Graphics->GetDevice(), 128,128,3,0,D3DFMT_R5G6B5, D3DPOOL_MANAGED, &m_lightmaps)))		PostQuitMessage(0);

next you want to read the texture information. To do so you must obtain a surface from the texture onto which you can plot the pixel data:

		// Grab a texture surface to draw our lightmap on		IDirect3DSurface8 *TextureSurface;		if(FAILED(m_lightmaps[i]->GetSurfaceLevel(0, &TextureSurface)))			PostQuitMessage(0);

This creates a pointer to the surface.

To do something to the surface you need to lock it and specify an area to lock. Given that the size of the textures generated in the Q3 BSP process is 128 by 128 we specify this and lock the surface.

// The rectangle to lock		D3DLOCKED_RECT pLockedRect;		RECT rectangleToLock;		rectangleToLock.top = 0.0f;		rectangleToLock.left = 0.0f;		rectangleToLock.bottom = 128.0f;		rectangleToLock.right = 128.0f;				// Lock the entire 128 x 128 surface		if(FAILED(TextureSurface->LockRect(&pLockedRect,&rectangleToLock,0 )))			PostQuitMessage(0);				// A Pointer to the buffer		USHORT* pData = (USHORT*)pLockedRect.pBits;

Notice also at the end that I have performed a typecast upon the pointer that is returned when I lock the surface. This is because in my case my created surface is only able to be specififed in 16 bit format due to graphics card limitations. A USHORT being 16 bit is ideal for this purpose, just change the data type cast to, to match whichever color format you are dealing with, thus each time the pointer is incremented, it represents one pixel.

Next we set up a nested for loop that represents scanning thruogh each pixel on the surface. Again given that Q3A lightmap textures are 128X128 and this is not going to change I just specify these values in my loops.

The define command here creates a macro that bitshifts the values given to fit into a 16 bit value (our pixel) You then specify which pixel to write to using the following code:
"pData[(q * (pLockedRect.Pitch/2)) + p] = lightmap_pixel_565;"
This takes into account the pitch of the surface to get you the correct area of memory for the pixel you are changing. Note that you divide the pitch by two as we need 16 bits per pixel, if you need 32 bits per pixel you divide by 4 instead. Please also note that prior to putting the values through the RGB macro we must shift them right by 3 for red, 2 for green and 3 for blue. This is because 16 bit colours are specified (0-31,0-63,0-31) as opposed to 32 bit colours being specified as (0-255,0-255,0-255) and as the data in a BSP file is given as 0-255 we must perform the aformentioned bitshift to convert the values from the 0-255 range to the appropriate range.

for(int p = 0; p<128;p++) {			for(int q = 0; q<128; q++) {				#define RGB_16BIT565(r, g, b)  ((r << 11) | (g << 5) | (b))								if (pLightmaps[i].imageBits[q][p][0] < (255 - 100)) {					pLightmaps[i].imageBits[q][p][0] += 100;				}				if (pLightmaps[i].imageBits[q][p][1] < (255 - 100)) {					pLightmaps[i].imageBits[q][p][1] += 100;				}				if (pLightmaps[i].imageBits[q][p][2] < (255 - 100)) {					pLightmaps[i].imageBits[q][p][2] += 100;				}				WORD red = pLightmaps[i].imageBits[q][p][0];				WORD green = pLightmaps[i].imageBits[q][p][1];				WORD blue = pLightmaps[i].imageBits[q][p][2] ;				WORD alpha = pLightmaps[i].imageBits[q][p][3];				WORD lightmap_pixel_565 =RGB_16BIT565 (red>>3,green>>2,blue>>3);				pData[(q * (pLockedRect.Pitch/2)) + p] = lightmap_pixel_565;			}		}

The if statements in the above code also take into account that the resultant lightmap is far too dark. It just raises any color values given up to 155 by 100, this stops the dark spots being entirely pitch black as I found as the case with my graphics card

Finally you unlock the surface and free it sa it is not needed any more

if(FAILED(TextureSurface->UnlockRect()))			PostQuitMessage(0);				TextureSurface->Release();

Anyways that ws all very badly explained, I know I could do a much better job, but hopefully it will get you started. I kinda just don't have the time to write an in depth tutorial at this exact minute, but I thought having gone through the process myself you might appreciate any help you could get

hope it helps,

Steve AKA Mephs

[edited by - mephs on July 1, 2002 3:57:38 AM]

##### Share on other sites
Hi,

I''m not sure, but try pDst += lrect.Pitch-3 insted of adding only lrect.Pitch (because you do pDst++ three time).

Sorry for my English but I''m Italian

gnolo

##### Share on other sites
I actually solved it.

There were a couple of problems. The biggest was of course that I used the first textures texture coordinates. The other seems to be a strange problem with copying the colorvalues directly. But when I use the D3DCOLOR_ARGB(); Macro this also works fine.