Archived

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

Keba

Dynamic Lightmaps

Recommended Posts

I Read a tutorial about Dynamic Lightmaps at http://www.3ddrome.com/articles/dynamiclightmaps.php the author is using OpenGL and i want to convert this to DirectX, the thing is about Creating Surfaces/Textures. He is creating a Texture and filling it with data which he calculated for the Lightmaps (pixeldata), anyway the data is a static unsigned char array and i wan''t to create a texture/surface in DirectX and fill it with this data, and hopefully get a renderable texture .... first: should i create a texture or surface? second: how do i import the data to that surface/texture to get a correc/renderable texture/surface, should i use the LocRect funktion and fill it?

Share this post


Link to post
Share on other sites
Do all of the following during initialization. When your app is about to finish, first release the surface, then release the texture itself:

// To create texture/surface....

HRESULT hr;

if( FAILED( hr = D3DXCreateTexture( m_pd3dDevice, width, height, 1, 0, D3DFMT_A8R8G8B8, D3DPOOL_DEFAULT, &m_pLightMapTexture ) ) )
return DXTRACE_ERR_MSGBOX( "D3DXCreateTexture", hr );

if( FAILED( hr = m_pLightMapTexture->GetSurfaceLevel( 0, &m_pLightMapSurface ) ) )
return DXTRACE_ERR_MSGBOX( "GetSurfaceLevel", hr );

// To load surface with the data you want...

D3DLOCKED_RECT lockedRect;
if( FAILED( hr = m_pLightMapSurface->LockRect( &lockedRect, NULL, 0 ) ) )
return DXTRACE_ERR_MSGBOX( "LockRect", hr );

// Do NOT perform a straight "memcpy" here because the width of

// a texture/surface will not always be the same as its

// pitch (i.e. the number of bytes in one row of the

// texture/surface)

unsigned char* pSurface = static_cast<unsigned char*>( lockedRect.pBits );

// Since one "char" is 1 byte, then the number of chars in one

// row is the same as the Pitch. However, for other texture

// types, like floating point textures (which have 4 bytes per float),

// this is not the case. This line is here so that you know that

// you need to divide by the number of bytes that the variable

// type takes up. In this case, it's redundant.

DWORD dwCharsPerRow = lockedRect.Pitch/1;
for( DWORD i = 0; i < height; i++ )
{
DWORD dwIndex = i * dwCharsPerRow;
for( DWORD j = 0; j < width; j++ )
{
pSurface[dwIndex + j*4 + 0] = data[i*width + j*4 + 0]; // A

pSurface[dwIndex + j*4 + 1] = data[i*width + j*4 + 1]; // R

pSurface[dwIndex + j*4 + 2] = data[i*width + j*4 + 2]; // G

pSurface[dwIndex + j*4 + 3] = data[i*width + j*4 + 3]; // B

}
}

m_pLightMapSurface->Unlock();

Depending on how your data is set up, you may have to swap some of the indices around in the 'for' loop but you get the idea.

Hope this helps,
neneboricua

[edited by - neneboricua19 on January 25, 2004 5:34:35 PM]

Share this post


Link to post
Share on other sites
so, i ran into another problem....

you wrote this:

pSurface[dwIndex + j*4 + 0] = data[i*width + j*4 + 0]; // A

pSurface[dwIndex + j*4 + 1] = data[i*width + j*4 + 1]; // R

pSurface[dwIndex + j*4 + 2] = data[i*width + j*4 + 2]; // G

pSurface[dwIndex + j*4 + 3] = data[i*width + j*4 + 3]; // B


dwIndex is the start location for this row? right?
and then you add j*4 and the 4 is there because of A,R,G,B ? right?...and j is the current pixel on this row? and then you add 0,1,2,3 depending on Current pixels A,R,G,B?

ok, so why don't you do the same for data? whu are you using width? is it because the pitch isn't the same as the width of the texture?

and what if i don't want the alpha channel, should it be j*3 + 0....j*3+2?

is it possible that the pitch could be larger than the texture width?

[edited by - keba on January 29, 2004 6:23:08 AM]

Share this post


Link to post
Share on other sites
quote:
Original post by Keba
so, i ran into another problem....

you wrote this:

pSurface[dwIndex + j*4 + 0] = data[i*width + j*4 + 0]; // A

pSurface[dwIndex + j*4 + 1] = data[i*width + j*4 + 1]; // R

pSurface[dwIndex + j*4 + 2] = data[i*width + j*4 + 2]; // G

pSurface[dwIndex + j*4 + 3] = data[i*width + j*4 + 3]; // B


dwIndex is the start location for this row? right?
and then you add j*4 and the 4 is there because of A,R,G,B ? right?...and j is the current pixel on this row? and then you add 0,1,2,3 depending on Current pixels A,R,G,B?

ok, so why don''t you do the same for data? whu are you using width? is it because the pitch isn''t the same as the width of the texture?

and what if i don''t want the alpha channel, should it be j*3 + 0....j*3+2?

is it possible that the pitch could be larger than the texture width?

[edited by - keba on January 29, 2004 6:23:08 AM]

The hardware uses "Pitch" because it doesn''t always allocate the exact amount of space necessary for a texture. This is because sometimes it is more effecient to allocate or transfer blocks of certain sizes.

You mentioned earlier that the data is stored in a regular array. This regular array doesn''t have this drawback. As the application developer, you allocate your array to be just large enough to fit the data you want. So in that case, you just use the conceptual "width" of the data and don''t have to worry about the "pitch" since the "pitch" is basically a hardware issue.

Yes, "dwIndex" is the start of the particular row we''re doing. Yes, "j" is the current texel. The j*4 is there so that we get to the start of the particular texel we''re filling in. If you use a texture format that doesn''t have an alpha channel, then you replace the 4 by a 3 and you should be ok.

Remember that it depends on the format of the texture. If you use something like D3DFMT_X8R8G8B8, the hardware still allocates the same amount of space as for D3DFMT_A8R8G8B8. The difference is that the first format doesn''t allow you to use the alpha channel. Just be aware of how much space is actually allocated for each texture format and you should be ok.

neneboricua

Share this post


Link to post
Share on other sites
Ok, now I got some colors, but its not correct, i got red, green, blue stripes on the texture, and not the whole texture is filled, something like this:
Where R is Red G is Green and B is Blue and 0 is Black

RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000
RGBRGBRGBRGB0000

NOTE: maybe it should be rotated 90 degrees, not sure.


The texture is 16*16
And is setuped as followed:

if( FAILED( hr = D3DXCreateTexture( m_pD3DDevice, Width, Height, 1,0, D3DFMT_R8G8B8,D3DPOOL_MANAGED , &m_pLightmapTexture ) ) )
{
...
// error
...
}

OBS, I hade to use D3DPOOL_MANAGED because D3DPOOL_DEFAULT can’t lock and access memory directly, is there a better choose?

Ok, now I lock and access the surface as you wrote and filling the texture as followed:

DWORD dwCharsPerRow = lockedRect.Pitch/1;

for( DWORD i = 0; i < Height; i++ )
{
DWORD dwIndex = i * dwCharsPerRow;

for( DWORD j = 0; j < Width; j++ )
{

Surface[dwIndex + j*3 + 0] = 255; // R
pSurface[dwIndex + j*3 + 1] = 0; // G
pSurface[dwIndex + j*3 + 2] = 0; // B
}
}

Height and Width is the texture Height/Width (16) so as far as I’m concern the texture should be red, not striped with Red, Blue and green, and why is the last part black?!
What I’m I doing wrong?

btw, how do i get thoose code friendly fields? much easier
thanks

Share this post


Link to post
Share on other sites
What type of variables are your "Surface" pointer and your "pSurface" pointer??? If they're something like "int" or "float" you would get the results you describe. Assuming that it's just a typo and you only have one variable (i.e. "pSurface") and that it's declared like this:

unsigned char* pSurface = static_cast< unsigned char* >( lockedRect.pBits );

Then you should be ok. Could you please post the entire code you're using to create and load the texture? You can get the code friendly boxes by using this in your message:
[ source ]
code goes here
[ / source ]

Take out the spaces in those tags and you'll get the source code boxes.

neneboricua

[edited by - neneboricua19 on January 30, 2004 5:07:33 PM]

Share this post


Link to post
Share on other sites
yeah...ehrrmmm...sorry my mistake, it should only be one Surface, that is pSurface, and yes its done like this:


unsigned char* pSurface = static_cast< unsigned char* >( lockedRect.pBits );


anyway, i figured it out, i DID create the texture with D3DFMT_R8G8B8, but in someway he did create memory for the alpha channel(or something else), and the order was B,G,R,?....what could cause this ? i mean, why did he create extra memory when i specified D3DFMT_R8G8B8? this computer has an old graphics card( TNT 2 Ultra) could that cause it?

anyway, thanks for all help!

Share this post


Link to post
Share on other sites